pythonlogging⽤法的简单总结
⽬录
官⽅⽂档:
基本⽤法
logging默认配置了六种⽇志级别(括号为级别对应的数值),按优先级升序,依次为:
NOTSET(0)
DEBUG(10)
INFO(20)
WARNING(30)
ERROR(40)
CRITICAL(50)
logging 执⾏时输出⼤于等于设置的⽇志级别的⽇志信息,如设置⽇志级别是 INFO,则 INFO、WARNING、ERROR、CRITICAL 级别的⽇志都会输出先来看⼀个简单的⽤法⽰例:
import logging
logging.basicConfig()  # ⾃动化配置
logging.warning('This is a warning message')  # 默认的⽇志输出级别为Warning
logging.basicConfig(**kwargs) 中常⽤的参数包括:
filename:指定使⽤指定的⽂件名⽽不是 StreamHandler 创建 FileHandler
filemode:如果指定 filename,则以此模式打开⽂件(‘r’、‘w’、‘a’)。默认为“a”
format:配置⽇志格式字符串,参考:
datefmt:配置时间格式字符串,⽀持time.strftime() 所接受的⽇期/时间格式
level:指定⽇志记录器级别,默认为WARNING
handlers:指定handlers,注意此参数与filename和filemode不兼容,同时配置时会报错
basicConfig配置⽰例:
logging.basicConfig(filename="test.log",
filemode="w",
format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
datefmt="%d-%M-%Y %H:%M:%S",
level=logging.DEBUG)
进阶配置
我们先了解⼀下logging中的主要模块:
Loggers:expose the interface that application code directly uses.
Handlers:send the log records (created by loggers) to the appropriate destination.
Filters:provide a finer grained facility for determining which log records to output.
Formatters:specify the layout of log records in the final output.
程序中发送的⽇志信息将被包装成对象传⼊logging的各个组件中:
Loggers
objects have a threefold job. First, they expose several methods to application code so that applications can log messages at runtime. Second, logger objects determine which log messages to act upon based upon severity (the default filtering facility) or filter objects. Third, logger objects pass along relevant log messages to all interested log handlers.
Logger与handler之间的关系类似于邮件和邮箱,⼀封邮件可以在需要的时候抄送⾄多个收件箱。Logger常⽤的配置⽅法包括:
:设置最低显⽰级别
和:增删,每个Logger可以对应0个或多个handler
和:增删
每个Logger都有⼀个name属性,它代表了这个logger在⽤户程序中所属的模块(与作⽤域的概念类似),不同模块下logger的name可以通过.来组织层级关系,⽐如hook,hook.spark,hook.spark.attachment等。不同层级的logger间有类似于编程对象中“继承”的关系:⽗logger的各种配置项都会被⼦logger继承(包括handler,filter等)
我们可以通过⽅法获得logger对象并配置name。由于logger遵从单例模式,因此多次调⽤getLogger()并配置相同的name时,该接⼝将返回同⼀个logger对象Handlers
何时我们需要多个Handler?
As an example scenario, an application may want to send all log messages to a log file, all log messages of error or higher to stdout, and all messages of critical to an email address.
标准库中提供了⼀系列预定义的Handler,参考:,它们常⽤的配置⽅法包括:
设置handler将处理哪个级别以上的消息
为Handler指定⼀个格式配置对象
and 增删Filter
Formatters
formatter⽤来配置⽇志的各种格式,它包括三个参数:
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
其中:
fmt指定了⽇志的消息格式,如:'%(asctime)s - %(levelname)s - %(message)s'
datefmt指定了⽇期的组织格式,如:%Y-%m-%d %H:%M:%S
style允许⽤户指定⽤什么类型的标识符来描述前两个参数的内容。⽐如,在以上两⾏例⼦中,我们⽤的都是%标识符。除此之外,我们还可以⽤{}和$标识符,具体内容请参考:
整体配置
Logging可以通过三种⽅法配置:
在python代码中显式地声明loggers、handlers和formatters等组件并调⽤相关⽅法进⾏配置
创建⼀个logging配置⽂件,并调⽤进⾏配置
声明⼀个包含配置信息的dict,并将它传⼊进⾏配置
后两种配置⽅式的具体细节可参阅:,接下来展⽰⼀个第⼀种配置⽅式的简单demo:
import logging
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# add formatter to ch
ch.setFormatter(formatter)
# create logger
logger = Logger('simple_example')
logger.setLevel(logging.DEBUG)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
以上代码先创建了⼀个formatter,然后把它添加⾄handler,接着把该handler关联⾄⼀个logger,之后我们就可以⽤这个logger记录信息了代码样例
⼀个⽇志模块封装样例:
import os
import logging
from logging.handlers import RotatingFileHandler
class Log:
_logger = None
_log_dir = None
@staticmethod
def get():
if Log._logger:
return Log._logger
else:
return Log._build_logger()
@staticmethod
def set_dir(file_dir):
if Log._log_dir:
raise Exception('log directory has already been set. (Check if "get()" has been called before)')
else:
if not (ists(file_dir) and os.path.isdir(file_dir)):
os.mkdir(file_dir)
Log._log_dir = file_dir
@staticmethod
def filter(name, level):
level = str.upper(level)
assert level in {'DEBUG', 'INFO', 'WARNING', 'ERROR'}
@staticmethod
def _build_logger():
log_fmt = '[%(asctime)s | \"%(filename)s\" line %(lineno)s | %(levelname)s]  %(message)s'
formatter = logging.Formatter(log_fmt, datefmt="%Y/%m/%d %H:%M:%S")
if not Log._log_dir:
os.makedirs('logs', exist_ok=True)
Log._log_dir = 'logs'
log_filepath = os.path.join(Log._log_dir, "rotating.log")
log_file_handler = RotatingFileHandler(filename=log_filepath, maxBytes=500, backupCount=3)
log_file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
logging.basicConfig(level=logging.INFO, handlers=(log_file_handler, stream_handler))
Log._logger = Logger()
return Log._logger
if __name__ == '__main__':
import time
# Log.set_dir('logs')  # Configure the log directory before use, if needed.
log = ()
Log.set_dir('logs')
for count in range(20):
<(f"logger count: {count}")
time.sleep(1)
另⼀种写法,根据调⽤者的⽂件位置⾃动给logger命名:
import os
import logging
import traceback
from logging.handlers import RotatingFileHandler
class Log:
_root = None
_logger = None
@staticmethod
def get():
# Construct the name of the logger based on the file path
code_file = act_stack()[-2].filename  # Get the file path of the caller
if Log._root not in os.path.abspath(code_file):
raise Exception(f'The file calling the method is outside the home directory: "{code_file}"')
relpath = lpath(code_file, Log._root).replace('.py', '').replace('/', '.')
root_name = os.path.basename(Log._root)
Logger(f"{root_name}.{relpath}")
@staticmethod
def init(home):
assert os.path.isdir(home), f'invalid home directory: "{home}"'
Log._root = os.path.abspath(home)
log_dir = os.path.join(Log._root, 'logs')
if not os.path.isdir(log_dir):
os.mkdir(log_dir)
Log._configure_root_logger(log_dir)
@staticmethod
def filter(name, level):
exists的用法level = str.upper(level)
assert level in {'DEBUG', 'INFO', 'WARNING', 'ERROR'}
@staticmethod
def _configure_root_logger(log_dir):
log_fmt = '[%(asctime)s | %(name)s | %(levelname)s]  %(message)s'
formatter = logging.Formatter(log_fmt, datefmt="%Y/%m/%d %H:%M:%S")
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
log_filepath = os.path.join(log_dir, "rotating.log")
log_file_handler = RotatingFileHandler(filename=log_filepath, maxBytes=1e5, backupCount=3)        log_file_handler.setFormatter(formatter)
root_logger_name = os.path.basename(Log._root)
root_logger = Logger(root_logger_name)
root_logger.addHandler(log_file_handler)
root_logger.addHandler(stream_handler)
root_logger.setLevel(logging.DEBUG)  # default level
if __name__ == '__main__':
import os, time
log_dir = os.path.dirname(__file__)
Log.init(log_dir)  # project root directory
log = ()
for count in range(20):
log.info(f"logger count: {count}")
time.sleep(1)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。