[python]-日志记录之logging


一般简单输出使用print,但是要有大量输出,且做控制时,就需要做日志打印了。python中的logging模块可方便地进行日志打印。使用时:

import logging

记录器

通过logging.getLogger(name)获取日志记录器对象,多次使用相同的名称会返回同一个Logger对象。若不指定名字(或直接使用logging)则返回root(根)Logger。以下记录方式是等价的:

# 直接使用root Logger
logging.warning('warn')
#获取Logger后使用
root = logging.getLogger()
root.warning('warn')

Logger是层次结构的,使用 ‘.’ 点号分割,如’a’、‘a.b’或’a.b.c.d’,'a’是’a.b’的父parent,'a.b’是’a’的子child。以下两者是等价的:

# 按层次获取Logger
loggerA = logging.getLogger('abc').getChild('def.ghi')
# 直接获取Logger
loggerA = logging.getLogger('abc.def.ghi')

日志级别

默认生成的root logger的level是logging.WARNING,低于该级别的就不输出了。可自定义级别,若自定义级别的数值与预定义的相同,则会覆盖掉预定义的。

级别数值
CRITICAL50
ERROR40
WARNING30
INFO20
DEBUG10
NOTSET0

函数

logging提供了针对不同级别的日志 输出函数:

  • debug(msg, *args, **kwargs)
  • info(msg, *args, **kwargs)
  • warning(msg, *args, **kwargs)
  • error(msg, *args, **kwargs)
  • critical(msg, *args, **kwargs)
  • log(level, msg, *args, **kwargs)
  • exception(msg, *args, **kwargs):记录到ERROR级别

args 参数用于字符串格式化操,针对msg中的%格式符。

kwargs 中会检查四个关键字参数: exc_infostack_infostacklevelextra

  • exc_info 的求值结果不为 false ,则它将异常信息添加到日志消息中。如果提供了一个异常元组(按照 sys.exc_info() 返回的格式)或一个异常实例,则它将被使用;否则,调用 sys.exc_info() 以获取异常信息。
  • stack_info,默认为 False。如果为 True,则将堆栈信息(异常展开的栈信息)添加到日志消息中,包括实际的日志调用。
  • stacklevel ,默认为 1 。如果大于 1 ,则在为日志记录事件创建的 LogRecord 中计算行号和函数名时,将跳过相应数量的堆栈帧。
  • extra ,传递一个字典,该字典用于填充为日志记录事件创建的、带有用户自定义属性的 LogRecord 中的字典(字典的键不应与日志系统使用的键冲突) 。

如在日志中输出用户字典中的IP地址与用户信息:

FORMAT = '%(asctime)s %(clientip)-15s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
logger = logging.getLogger('tcpserver')

info = {'clientip': '192.168.0.1', 'user': 'bob'}
logger.warning('Protocol problem: %s', 'connection reset', extra=info)
# 输出如下:
2021-11-20 22:20:02,165 192.168.1.2 bob   Protocol problem: connection reset

格式化器

Formatter负责将LogRecord转换为易于识别的字符串
logging.Formatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

LogRecord

LogRecord中属性用于将来自记录的数据合并到格式字符串中。

属性名称格式描述
args在原始日志记录调用中传入的格式字符串对应的参数。
asctime%(asctime)s日志创建时间, 默认格式 ‘2021-07-08 16:49:45,896’ (逗号后为毫秒)。
msecs%(msecs)03d日志创建时间的毫秒部分。
created%(created)f日志创建时间,(即 time.time() 的返回值)。
exc_info异常元组(例如 sys.exc_info)或者如未发生异常则为 None
filename%(filename)spathname 的文件名部分。
funcName%(funcName)s函数名包括调用日志记录.
levelname%(levelname)s日志级别:消息文本记录
levelno%(levelno)s日志级别:数值
lineno%(lineno)d源行号。
message%(message)s记入日志的消息
module%(module)s模块 (filename 的名称部分)。
msecs%(msecs)d时间的毫秒部分。
msg在原始日志记录调用中传入的格式字符串。
name%(name)s用于记录调用的日志记录器名称。
pathname%(pathname)s源文件的完整路径名。
process%(process)d进程ID(如果可用)
processName%(processName)s进程名(如果可用)
relativeCreated%(relativeCreated)d相对于 logging 模块被加载时间的差值(毫秒数)。
stack_info当前线程的堆栈帧信息。
thread%(thread)d线程ID(如果可用)
threadName%(threadName)s线程名(如果可用)

默认配置

logging.basicConfig(**kwargs)设定记录系统的基础配置。其关键参数:

格式描述
filename日志文件名
filemode日志文件打开模式, 默认为 'a'
format输出格式,默认为冒号分隔的 levelname, namemessageWARNING:root:output-message)。
datefmt日期/时间格式(time.strftime() 所接受的格式)。
style*format*的格式字符串风格:
'%':printf 风格(默认),%(message)s
'{'str.format()风格,{message}
'$'string.Template风格
level记录级别
stream设定日志记录流;此参数与 filename 不兼容 (两者不能同时存在)
handlers设定日志记录处理器,此参数与 filenamestream 不兼容
forcetrue时,移除并关闭附加到根记录器的所有现有处理器。
encoding输出文件的编码格式
errors输出文件在编码出错时的处理方式

日志配置

设定日志输出格式

def init_logging(logFile=None):
    # Define a Handler and set a format which output to file
    logging.basicConfig(
        level=logging.DEBUG,  # 定义输出的log级别,
        format='%(asctime)s.%(msecs)03d [%(levelname)s]:  %(message)s',  # 定义输出log的格式
        # datefmt='%Y-%m-%d %H:%M:%S',  # 时间
        datefmt='%H:%M:%S',  # 时间
        filename=logFile,  # log文件名,None时只输出到console
        filemode='w')  # 写入模式“w”或“a”
    
if __name__ == '__main__':
    init_logging()
    # 字符串format方式
    logging.info("{} - times, output: {}".format(1, 'test-info'))
    # printf格式
    logging.info("%i - times, output: %s", 1, 'test-info')

同时输出到屏幕与日志文件(需要通过logger实现):

logger = logging.getLogger("base")

def init_logging(logFile=None, logLevel=logging.DEBUG):
    for handler in logger.handlers[:]:  # get rid of existing old handlers
        logger.removeHandler(handler)

    logger.setLevel(logLevel)
    formatter = logging.Formatter('%(asctime)s.%(msecs)03d [%(levelname)s] %(filename)s:%(lineno)d : %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
    
    # 使用StreamHandler输出到屏幕
    out = logging.StreamHandler()
    out.setLevel(logLevel)
    out.setFormatter(formatter)
    logger.addHandler(out)
    # 使用FileHandler输出到文件
    if logFile:
        fh = logging.FileHandler(logFile)
        fh.setLevel(logLevel)
        fh.setFormatter(formatter)
        logger.addHandler(fh)


if __name__ == '__main__':
    init_logging("D:\\temp\\test.log")
    logger.info("{} - times, output: {}".format(2, 'test-info'))
    logger.info("%i - times, output: %s", 2, 'test-info')
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值