Skip to content

Instantly share code, notes, and snippets.

@nguyenkims

nguyenkims/log.py

Last active Jun 10, 2021
Embed
What would you like to do?
Basic example on how setup a Python logger
import logging
import sys
from logging.handlers import TimedRotatingFileHandler
FORMATTER = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
LOG_FILE = "my_app.log"
def get_console_handler():
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(FORMATTER)
return console_handler
def get_file_handler():
file_handler = TimedRotatingFileHandler(LOG_FILE, when='midnight')
file_handler.setFormatter(FORMATTER)
return file_handler
def get_logger(logger_name):
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG) # better to have too much log than not enough
logger.addHandler(get_console_handler())
logger.addHandler(get_file_handler())
# with this pattern, it's rarely necessary to propagate the error up to parent
logger.propagate = False
return logger
@dimension4c137

This comment has been minimized.

Copy link

@dimension4c137 dimension4c137 commented Dec 29, 2019

how would you write it in a class? for using it in some other modules too

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Dec 30, 2019

how would you write it in a class? for using it in some other modules too

You can try with this

import logging
import sys
from logging import Logger
from logging.handlers import TimedRotatingFileHandler


class MyLogger(Logger):
    def __init__(
        self,
        log_file=None,
        log_format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        *args,
        **kwargs
    ):
        self.formatter = logging.Formatter(log_format)
        self.log_file = log_file

        Logger.__init__(self, *args, **kwargs)

        self.addHandler(self.get_console_handler())
        if log_file:
            self.addHandler(self.get_file_handler())

        # with this pattern, it's rarely necessary to propagate the| error up to parent
        self.propagate = False

    def get_console_handler(self):
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(self.formatter)
        return console_handler

    def get_file_handler(self):
        file_handler = TimedRotatingFileHandler(self.log_file, when="midnight")
        file_handler.setFormatter(self.formatter)
        return file_handler
@toren77

This comment has been minimized.

Copy link

@toren77 toren77 commented Jan 1, 2020

How to use MyLogger class in custom classes ? for example have classes Dog() and Cat()

@amidium

This comment has been minimized.

Copy link

@amidium amidium commented Feb 1, 2020

Hello @toren77,

As I understand we need to add logging.setLoggerClass(MyLogger) to start using our custom Logger implementation.

@urwa

This comment has been minimized.

Copy link

@urwa urwa commented Jul 16, 2020

@nguyenkims Thank you so much for this amazing class. Would be great if you can share some usage example. Struggling with a couple of parameters in myLogger() class. Thanks again.

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Jul 16, 2020

@urwa I'd suggest using the log.py directly, for example

import log

logger = log. get_logger("any_name")

logger.debug("this is a debug message")
logger.info("this is a debug message")
@nykolab

This comment has been minimized.

Copy link

@nykolab nykolab commented Jul 27, 2020

Hello @nguyenkims
To be honest I don't really understand how the construction with log class is going to work (class MyLogger).
For example, how to provide log_file to it during initialization ?

Doing something like won't allow to provide log_file name:

logging.setLoggerClass(MyLogger)
logger = logging.getLogger(__name__)

Am I missing something ?

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Jul 29, 2020

@nykolab the class is there rather for illustrating how the first code snippet can be used as a class. I'd suggest using the log.py directly, for example:

import log

logger = log. get_logger("any_name")

logger.debug("this is a debug message")
logger.info("this is a debug message")
@MarvinKweyu

This comment has been minimized.

Copy link

@MarvinKweyu MarvinKweyu commented Aug 7, 2020

Hey @nguyenkims, tried the class out. A call-in one function for instance:

import log
custom_logger = log.getLogger(__name__)


def do_something():
    custom_logger.info(f"Random logs")

However:

 logger = log.get_logger(__name__)
AttributeError: module 'log' has no attribute 'get_logger'

Perhaps I'm looking at it wrong.

@danielplatt

This comment has been minimized.

Copy link

@danielplatt danielplatt commented Aug 7, 2020

What's the license for this code?

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Aug 7, 2020

@danielplatt: it's MIT or you can use it freely without any restriction :).

@danielplatt

This comment has been minimized.

Copy link

@danielplatt danielplatt commented Aug 7, 2020

Thanks!

@Tamilvanantmv

This comment has been minimized.

Copy link

@Tamilvanantmv Tamilvanantmv commented Sep 16, 2020

Where do you set logging level in class level logging

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Sep 16, 2020

@Tamilvanantm: good catch! The class-based implementation is for illustrating the idea and I suggest using function-based implementation (log.py ) instead.

@StL-Jim

This comment has been minimized.

Copy link

@StL-Jim StL-Jim commented Sep 18, 2020

I too have been trying to wrap my head around what you're doing here, especially with the class. You've put so much time into this, why not write a complete, functional logging class?

@yolonhese

This comment has been minimized.

Copy link

@yolonhese yolonhese commented Sep 22, 2020

Let's say you have multiple modules and in each one you do get_logger from the log.py. Isn't the log then configured again every time you include a module?

I was under the impression that the best practice would be to do something along the lines of what get_logger does while starting the application, and then do

import logging
logger = logging.getLogger(<logger_name>)

in each module where you wish to use it. Am I wrong?

@nguyenkims

This comment has been minimized.

Copy link
Owner Author

@nguyenkims nguyenkims commented Sep 24, 2020

I usually have a single logger that is shared for all modules in my app it's just my preference.

@snehotosh

This comment has been minimized.

Copy link

@snehotosh snehotosh commented Jan 7, 2021

The above class can be executed as follows:
logger2 = MyLogger(log_file=, name = )

logger2.debug("this is a debug message")
logger2.info("this is a info message")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment