Python标准库logging的使用
用法介绍
import logging
# 创建一个logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) # 设置日志级别为INFO,低于此级别的日志将被忽略
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('app.log') # 将日志记录到名为'app.log'的文件中
fh.setLevel(logging.DEBUG) # 可以单独设置handler的日志级别,这里是DEBUG级别
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR) # 控制台只输出ERROR及更高级别的日志
# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)
# 使用logger记录日志
logger.debug("Debugging information")
logger.info("Some useful info")
logger.warning("Warning occurred")
logger.error("An error happened")
logger.critical("Critical failure")
# 当不再需要记录日志时,可以移除handler
# logger.removeHandler(fh)
# logger.removeHandler(ch)
上述代码首先创建了一个logger对象,并设置了它的日志级别为INFO。然后分别创建了两个handler,一个是FileHandler,将日志写入到文件;另一个是StreamHandler,将日志输出到控制台。每个handler都有自己独立的日志级别设置和格式化器,最后将这两个handler添加到logger中。执行日志记录时,会根据设置的级别筛选输出相应级别的日志信息。
示例:控制台打印
log.py
import datetime
import logging
import os
import threading
# 定义自定义格式器,添加进程ID和线程ID
class CustomFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
record.asctime = str(datetime.datetime.now())[0:-3]
record.pid = os.getpid()
record.tid = threading.current_thread().ident
return f"[{record.asctime}][{record.levelname:<8}] [PID-{record.pid} TID-{record.tid}] " \
f"[({record.funcName}){record.filename}:{record.lineno}] | {record.msg}"
# 外部可使用的logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
sh = logging.StreamHandler()
sh.setLevel(logging.INFO)
# [2024-04-14 03:08:41,439] [(<module>)test05.py:14] | xxxxx
formatter0 = logging.Formatter('[%(asctime)s] [(%(funcName)s)%(filename)s:%(lineno)d] | %(message)s')
# [2024-04-14 03:08:41,439] [INFO] [(<module>)test05.py:14] | xxxxx
formatter1 = logging.Formatter('[%(asctime)s] [%(levelname)s] [(%(funcName)s)%(filename)s:%(lineno)d] | %(message)s')
# [2024-04-14 03:07:18,850] [INFO] [25728-28640] [(<module>)test04.py:42] | xxxxx
formatter2 = logging.Formatter(
"[%(asctime)s] [%(levelname)s] [%(process)s-%(thread)s] " +
"[(%(funcName)s)%(filename)s:%(lineno)d] | %(message)s"
)
# [2024-04-14 03:06:04,007] [INFO] [25728-MainProcess] [28640-MainThread] [(<module>)test04.py:36] | xxxxx
formatter3 = logging.Formatter(
"[%(asctime)s] [%(levelname)s] [%(process)s-%(processName)s] [%(thread)s-%(threadName)s] " +
"[(%(funcName)s)%(filename)s:%(lineno)d] | %(message)s"
)
sh.setFormatter(formatter1)
# sh.setFormatter(CustomFormatter()) # 使用自定义format
logger.addHandler(sh)
格式化占位符
在Python标准库logging中,可以使用内置占位符来格式化日志消息。以下是几个常用的占位符及其含义:
%s - 字符串占位符,用于替换字符串类型的数据。
%d 或 %i - 整数占位符,用于替换整数类型的数据。
%f - 浮点数占位符,用于替换浮点数类型的数据,可以指定精度,例如%.3f表示保留三位小数。
%r - 字面量字符串表示形式(repr()返回值)的占位符,用于显示Python对象的字符串表示形式。
%x, %X - 十六进制整数占位符,%x是小写十六进制,%X是大写十六进制。
%p - 对象的内存地址占位符。
在logging模块中,通常使用%(name)s等形式的占位符,它们与旧式的%s、%d等不同,是用于格式字符串字面量(f-string或str.format()风格)的占位符,例如:
%(name)s - 替换logger的名字。
%(levelname)s - 替换日志级别(如'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')。
%(asctime)s - 替换日志的时间戳。
%(pathname)s - 替换产生日志调用的源代码文件的完整路径名。
%(filename)s - 替换产生日志调用的源代码文件名。
%(module)s - 替换产生日志调用的模块(文件名不带扩展名)。
%(lineno)d - 替换产生日志调用的源代码行号。
%(funcName)s - 替换产生日志调用的函数名。
%(message)s - 替换实际的消息文本。
%(process)s - 进程id。
%(processName)s - 进程名称。
%(thread)s - 线程id。
%(threadName)s - 线程名称。