简体   繁体   中英

Using variable-controlled logging level in Python logger

I want to write a function that will get the requested logging level from the user, ie something like:

import logging

logger = logging.getLogger()

def func(log_level: <Type?>):
    logger.log_level("everything is bad")

Can this be done?

You could use this. It first looks a little verbose, but you can easily add addtional handlers (maybe some that log to a file...)

import logging

logger = logging.getLogger()
handler = logging.StreamHandler() #you can also use FileHandler here, but then you need to specify a path
handler.setLevel(logging.NOTSET)

LOG_FORMAT = "%(levelname)s: %(message)s"
formatter = logging.Formatter(LOG_FORMAT)

handler.setFormatter(formatter)
logger.addHandler(handler)

logger.log(logging.CRITICAL, "your logging message 1") #==> CRITICAL: your logging message 1
logger.log(logging.WARN,     "your logging message 2") #==> WARN: your logging message 2

Note 1: LOG_FORMAT is defined according to the logging-documentation

Note 2: the logging levels ( logging.DEBUG , logging.INFO ...) are explained here . You can also use integer values accordingly:

logging.XX Value
NOTSET 0
DEBUG 10
INFO 20
WARN 30
ERROR 40
CRITICAL 50

You can use the context manager, I quote for the documentation "There are times when it would be useful to temporarily change the logging configuration and revert it back after doing something. For this, a context manager is the most obvious way of saving and restoring the logging context. Here is a simple example of such a context manager, which allows you to optionally change the logging level and add a logging handler purely in the scope of the context manager:"

import logging
import sys

class LoggingContext:
    def __init__(self, logger, level=None, handler=None, close=True):
        self.logger = logger
        self.level = level
        self.handler = handler
        self.close = close

    def __enter__(self):
        if self.level is not None:
            self.old_level = self.logger.level
            self.logger.setLevel(self.level)
        if self.handler:
            self.logger.addHandler(self.handler)

    def __exit__(self, et, ev, tb):
        if self.level is not None:
            self.logger.setLevel(self.old_level)
        if self.handler:
            self.logger.removeHandler(self.handler)
        if self.handler and self.close:
            self.handler.close()
        # implicit return of None => don't swallow exceptions

Exactly in the documentation, it is here: https://docs.python.org/3/howto/logging-cookbook.html#using-a-context-manager-for-selective-logging . You can also rewrite any of the sample code snippets from: https://docs.python.org/3/howto/logging-cookbook.html#using-logging-in-multiple-modules .

Just use the log() method of a logger, which takes a level as well as a format string and arguments.

import logging

logger = logging.getLogger()

def func(log_level: int, message: str):
    logger.log(log_level, message)
    
logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')

func(logging.DEBUG, 'message at DEBUG level')
func(logging.INFO, 'message at INFO level')
func(logging.CRITICAL, 'message at CRITICAL level')

Which prints

DEBUG    message at DEBUG level
INFO     message at INFO level
CRITICAL message at CRITICAL level

when run.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM