Skip to content

Instantly share code, notes, and snippets.

@nguyenkims

nguyenkims/log.py

Last active Nov 18, 2020
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.