python logging模块

https://www.cnblogs.com/yyds/p/6901864.html
https://www.cnblogs.com/yyds/p/6885182.html
https://blog.csdn.net/weixin_47154909/article/details/106203639
https://www.jb51.net/article/186787.htm
https://blog.csdn.net/pansaky/article/details/90710751
https://www.cnblogs.com/restran/p/4743840.html

logging模块的日志级别

日志等级(level)描述
DEBUG最详细的日志信息,典型应用场景是 问题诊断
INFO信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
WARNING当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
ERROR由于一个更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL当发生严重错误,导致应用程序不能继续运行时记录的信息
  • 开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;
  • 应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。
  • 日志级别的指定通常都是在应用程序的配置文件中进行指定的。

logging模块的四大组件

组件说明
loggers提供应用程序代码直接使用的接口
handlers用于将日志记录发送到指定的目的位置
filters提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略)
formatters用于控制日志信息的最终输出格式

最简单的日志输出

  • logging模块提供的日志记录函数所使用的日志器设置的日志级别是WARNING
import logging

logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")

也可以这样写:

import logging
logging.log(logging.DEBUG, "This is a debug log.")
logging.log(logging.INFO, "This is a info log.")
logging.log(logging.WARNING, "This is a warning log.")
logging.log(logging.ERROR, "This is a error log.")
logging.log(logging.CRITICAL, "This is a critical log.")

logger.exception

logger.exception(msg,_args),它等价于logger.error(msg,exc_info = True,_args),推荐这个

# -*- coding: utf-8 -*-
import logging
 
 
def foo(a, b):
  c = a + b
  raise ValueError('test')
  return c
 
 
def bar(a):
  print('a + 100:', foo(a, 100))
 
 
def main():
  try:
    bar(100)
  except Exception as e:
    logging.exception(e)
 
if __name__ == '__main__':
  main()

其他说明

logging.debug(msg, *args, **kwargs)

参数:

  • msg:日志消息格式字符串
  • args:args是被合并到参数 MSG使用字符串格式化操作,当未提供args时,不会对msg执行%格式化操作。
  • kwargs:kwargs中检查了三个关键字参数: exc_info,stack_info和extra。

关于exc_info, stack_info, extra关键词参数的说明:

  • exc_info: 其值为布尔值,如果该参数的值设置为True,则会将异常异常信息添加到日志消息中。如果没有异常信息则添加None到日志信息中。
  • stack_info: 其值也为布尔值,默认值为False。如果该参数的值设置为True,栈信息将会被添加到日志信息中。
  • extra: 这是一个字典(dict)参数,它可以用来自定义消息格式中所包含的字段,但是它的key不能与logging模块定义的字段冲突。

exc_info实例:没有错误时,会在下一行输出NoneType: None

logger.debug("====================【开始测试】====================", exc_info=True)

输出结果:

2020-05-21 19:37:03,421 - __main__ - DEBUG - ====================【开始测试】====================
NoneType: None

当有错误时:会在日志记录的下一行,输出Traceback信息

try:
    open("notreal.txt", "rb")
except Exception:
    logger.debug("Faild to open notreal.txt from logger.debug", exc_info=True)

输出结果:

2020-05-21 19:42:16,673 - __main__ - DEBUG - Faild to open notreal.txt from logger.debug
Traceback (most recent call last):
  File "E:/PyProject/Test_Pratice/test_logger_formatter.py", line 40, in <module>
    open("notreal.txt", "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'notreal.txt'

stack_info实例:在日志记录的下一行,输出堆栈信息

logger.debug("====================【开始测试】====================", stack_info=True)

输出结果:

2020-05-21 19:45:51,822 - __main__ - DEBUG - ====================【开始测试】====================
Stack (most recent call last):
  File "E:/PyProject/Test_Pratice/test_logger_formatter.py", line 34, in <module>
    logger.debug("====================【开始测试】====================", stack_info=True)

extra实例:

FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logger = logging.getLogger('tcpserver')
logger.warning('Protocol problem: %s', 'connection reset', extra=d)

输出结果

2020-05-21 19:51:11,313 192.168.0.1 fbloggs  Protocol problem: connection reset

logging.basicConfig()函数说明

logging.basicConfig(**kwargs)

该函数可接收的关键字参数如下:

参数名称描述
filename指定日志输出目标文件的文件名,指定该设置项后日志信心就不会被输出到控制台了
filemode指定日志文件的打开模式,默认为’a’。需要注意的是,该选项要在filename指定时才有效
format指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。
datefmt指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效
level指定日志器的日志级别
stream指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常
stylePython 3.2中新添加的配置项。指定format格式字符串的风格,可取值为’%’、’{‘和’$’,默认为’%’
handlersPython 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。
  • logging.basicConfig()函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。

logger对象配置完成后,可以使用下面的方法来创建日志记录:

方法描述
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical()创建一个与它们的方法名对应等级的日志记录
Logger.exception()创建一个类似于Logger.error()的日志消息
Logger.log()需要获取一个明确的日志level参数来创建一个日志记录

Logger.exception()与Logger.error()的区别在于:Logger.exception()将会输出堆栈追踪信息,另外通常只是在一个exception handler中调用该方法。

logging模块定义的格式字符串字段

字段/属性名称使用格式描述
asctime%(asctime)s日志事件发生的时间–人类可读时间,如:2003-07-08 16:49:45,896
created%(created)f日志事件发生的时间–时间戳,就是当时调用time.time()函数返回的值
relativeCreated%(relativeCreated)d日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的)
msecs%(msecs)d日志事件发生事件的毫秒部分
levelname%(levelname)s该日志记录的文字形式的日志级别(‘DEBUG’, ‘INFO’, ‘WARNING’, ‘ERROR’, ‘CRITICAL’)
levelno%(levelno)s该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
name%(name)s所使用的日志器名称,默认是’root’,因为默认使用的是 rootLogger
message%(message)s日志记录的文本内容,通过 msg % args计算得到的
pathname%(pathname)s调用日志记录函数的源码文件的全路径
filename%(filename)spathname的文件名部分,包含文件后缀
module%(module)sfilename的名称部分,不包含后缀
lineno%(lineno)d调用日志记录函数的源代码所在的行号
funcName%(funcName)s调用日志记录函数的函数名
process%(process)d进程ID
processName%(processName)s进程名称,Python 3.1新增
thread%(thread)d线程ID
threadName%(thread)s线程名称

经过配置的日志输出

import logging
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"

logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)

logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")

此时会发现控制台中已经没有输出日志内容了,但是在python代码文件的相同目录下会生成一个名为’my.log’的日志文件

使用Python代码实现日志配置

import logging

# 创建一个日志器logger并设置其日志级别为DEBUG
logger = logging.getLogger('simple_logger')
logger.setLevel(logging.DEBUG)

# 创建一个流处理器handler并设置其日志级别为DEBUG
handler = logging.FileHandler("info.log")
handler.setLevel(logging.DEBUG)

# 创建一个格式器formatter并将其添加到处理器handler
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)

# 为日志器logger添加上面创建的处理器handler
logger.addHandler(handler)

# 日志输出
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')

Handler类

Handler描述
logging.StreamHandler将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。
logging.FileHandler将日志消息发送到磁盘文件,默认情况下文件大小会无限增长
logging.handlers.RotatingFileHandler将日志消息发送到磁盘文件,并支持日志文件按大小切割
logging.hanlders.TimedRotatingFileHandler将日志消息发送到磁盘文件,并支持日志文件按时间切割
logging.handlers.HTTPHandler将日志消息以GET或POST的方式发送给一个HTTP服务器
logging.handlers.SMTPHandler将日志消息发送给一个指定的email地址
logging.NullHandler该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免’No handlers could be found for logger XXX’信息的出现。

StreamHandler

日志记录发送到控制台中

logging.StreamHandler(stream=None

参数:
stream:默认为None,日志输出到sys.stderr;指定stream的话中,则日志输出到指定stream

FileHandler

日志记录发送到磁盘文件中

logging.FileHandler(filename, mode='a', encoding=None, delay=False) 

参数:

  • filename:只填写文件名称,则默认新增文件到当前工作目录;填写工作路径+文件名称,则新增到对应工作目录
  • mode:默认a模式,可自定义
  • encoding:默认为None,可自定义
  • delay:默认为False,为True时,将文件打开延迟到第一次调用时进行emit()

NullHandler

不做任何事情的处理器,防止sys.stderr在没有日志记录配置的情况下将库的已记录事件输出

logging.NullHandler()

WatchedFileHandler

该处理器旨在在Unix / Linux下使用,它监视文件以查看自上一次发出以来是否已更改。(如果文件的设备或索引节点已更改,则认为该文件已更改。)如果文件已更改,则关闭旧文件流,并打开该文件以获取新的流,不适合在Windows下使用

logging.handlers.WatchedFileHandler(filename, mode='a', encoding=None, delay=False)

RotatingFileHandler

日志记录到文件中,且支持指定日志文件大小,备份文件数量

logging.handlers.RotatingFileHandler(filename, mode='a',
 maxBytes=0, backupCount=0, encoding=None, delay=False)

参数:

  • maxBytes:日志文件大小,单位为字节
  • backupCount:备份文件数量

注意:当maxBytes或backupCount中的任何一个为零,则永远不会发生过渡

例子:使用backupCount 5和的基本文件名app.log,你会得到app.log, app.log.1,app.log.2,达到app.log.5。写入的文件始终为app.log。当这个文件被填满时,它被关闭并重新命名为app.log.1,如果文件app.log.1, app.log.2等存在,那么它们被重命名为app.log.2, app.log.3分别等。

TimedRotatingFileHandler

日志记录到文件中,支持按时间间隔来更新日志

logging.handlers.TimedRotatingFileHandler(filename, 
when='h', interval=1, backupCount=0, encoding=None, 
delay=False, utc=False, atTime=None)

参数:
when:不同值对应不同时间类型,以字符串填入,不区分大小写
在这里插入图片描述
基于工作日的轮换时,将“ W0”指定为星期一,将“ W1”指定为星期二,依此类推,直到“ W6”指定为星期日。在这种情况下,不使用为interval传递的值

关于过渡时间:首次(在创建处理程序时)计算下一个过渡时间时,将使用现有日志文件的最后修改时间或当前时间来计算下一个轮换发生的时间。

  • interval:时间长度,与when结合使用

  • backupCount:如果backupCount不为零,则最多将保留backupCount数的文件,并且如果发生翻转时将创建更多文件,则最早的文件将被删除。删除逻辑使用间隔来确定要删除的文件,因此更改间隔可能会留下旧文件。

  • utc:默认为False,使用本地时间;为True时,使用UTC时间

  • actime:默认为None,若非None时,必须是一个datetime.time实例,该实例指定发生翻转的一天中的时间,对于将翻转设置为“在午夜”或“在特定工作日”发生的情况。请注意,在这些情况下,atTime值可有效地用于计算初始 翻转,随后的翻转将通过正常间隔计算来计算。
    在这里插入图片描述

其他handler

其他还有SocketHandler、DatagramHandler、SysLogHandler、NTEventLogHandler、SMTPHandler、MemoryHandler、HttpHandler、QueueHandler、QueueListener等,有兴趣的童鞋可以看官网:
https://docs.python.org/3.8/library/logging.handlers.html#logging.handlers

fileConfig()函数实现日志配置

关于fileConfig()函数的说明

函数定义:

  • 该函数定义在loging.config模块下:
logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)

参数:

  • fname:表示配置文件的文件名或文件对象
  • defaults:指定传给ConfigParser的默认值
  • disable_existing_loggers:这是一个布尔型值,默认值为True(为了向后兼容)表示禁用已经存在的logger,除非它们或者它们的祖先明确的出现在日志配置中;如果值为False则对已存在的loggers保持启动状态。

使用配置文件conf

现在我们通过配置文件的方式来实现与上面同样的功能:

[loggers]
keys=root,simpleExample 
# 这里要说明下,如果使用root,handler下面就使用fileHandler,
# 如果使用simpleExample,handler就使用consoleHandler,左右对应关系

[handlers]
keys=fileHandler,consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=fileHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
args=(sys.stdout,)
level=DEBUG
formatter=simpleFormatter

[handler_fileHandler]
class=FileHandler
args=('logging.log', 'a')
level=ERROR
formatter=simpleFormatter

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

代码:

import logging
import logging.config

# 读取日志配置文件内容
logging.config.fileConfig('logging.conf')

# 创建一个日志器logger
logger = logging.getLogger('root')

# 日志输出
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
配置文件格式说明

上面提到过,fileConfig()函数是对ConfigParser/configparser模块的封装,也就是说fileConfig()函数是基于ConfigParser/configparser模块来理解日志配置文件的。

换句话说,fileConfig()函数所能理解的配置文件基础格式是与ConfigParser/configparser模块一致的,只是在此基础上对文件中包含的section和option做了一下规定和限制,比如:

1)配置文件中一定要包含loggers、handlers、formatters这些section,
它们通过keys这个option来指定该配置文件中已经定义好的loggers、handlers和formatters,
多个值之间用逗号分隔;另外loggers这个section中的keys一定要包含root这个值;

2)loggers、handlers、formatters中所指定的日志器、
处理器和格式器都需要在下面以单独的section进行定义。
seciton的命名规则为[logger_loggerName][formatter_formatterName][handler_handlerName]

3)定义logger的section必须指定level和handlers这两个option,
level的可取值为DEBUG、INFO、WARNING、ERROR、CRITICAL、NOTSET,
其中NOTSET表示所有级别的日志消息都要记录,包括用户定义级别;
handlers的值是以逗号分隔的handler名字列表,
这里出现的handler必须出现在[handlers]这个section中,
并且相应的handler必须在配置文件中有对应的section定义;

4)对于非root logger来说,除了level和handlers这两个option之外,还需要一些额外的option,
其中qualname是必须提供的option,它表示在logger层级中的名字,在应用代码中通过这个名字得到logger;
propagate是可选项,其默认是为1,表示消息将会传递给高层次logger的handler,通常我们需要指定其值为0,
这个可以看下下面的例子;另外,对于非root logger的level如果设置为NOTSET,
系统将会查找高层次的logger来决定此logger的有效level。

5)定义handler的section中必须指定class和args这两个option,level和formatter为可选option;
class表示用于创建handler的类名,args表示传递给class所指定的handler类初始化方法参数,
它必须是一个元组(tuple)的形式,即便只有一个参数值也需要是一个元组的形式;level与logger中的level一样,而formatter指定的是该处理器所使用的格式器,
这里指定的格式器名称必须出现在formatters这个section中,
且在配置文件中必须要有这个formatter的section定义;
如果不指定formatter则该handler将会以消息本身作为日志消息进行记录,
而不添加额外的时间、日志器名称等信息;

6)定义formatter的sectioin中的option都是可选的,其中包括format用于指定格式字符串,
默认为消息字符串本身;datefmt用于指定asctime的时间格式,默认为'%Y-%m-%d %H:%M:%S'class用于指定格式器类名,默认为logging.Formatter;
对于propagate属性的说明

我们把logging.conf中simpleExample这个handler定义中的propagate属性值改为1,或者删除这个option(默认值就是1):

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=1

现在来执行同样的代码:

# 读取日志配置文件内容
logging.config.fileConfig('logging.conf')

# 创建一个日志器logger
logger = logging.getLogger('simpleExample')

# 日志输出
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

我们会发现,除了在控制台有输出信息时候,在logging.log文件中也有内容输出:

2017-05-15 16:06:25,366 - simpleExample - ERROR - error message
2017-05-15 16:06:25,367 - simpleExample - CRITICAL - critical message

这说明simpleExample这个logger在处理完日志记录后,把日志记录传递给了上级的root logger再次做处理,所有才会有两个地方都有日志记录的输出。通常,我们都需要显示的指定propagate的值为0,防止日志记录向上层logger传递。

实例2:
现在,我们试着用一个没有在配置文件中定义的logger名称来获取logger:

# 读取日志配置文件内容
logging.config.fileConfig('logging.conf')

# 用一个没有在配置文件中定义的logger名称来创建一个日志器logger
logger = logging.getLogger('simpleExample1')

# 日志输出
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

运行程序后,我们会发现控制台没有任何输出,而logging.log文件中又多了两行输出:

2017-05-15 16:13:16,810 - simpleExample1 - ERROR - error message
2017-05-15 16:13:16,810 - simpleExample1 - CRITICAL - critical message

这是因为,当一个日志器没有被设置任何处理器是,系统会去查找该日志器的上层日志器上所设置的日志处理器来处理日志记录。simpleExample1在配置文件中没有被定义,因此logging.getLogger(simpleExample1)这行代码这是获取了一个logger实例,并没有给它设置任何处理器,但是它的上级日志器–root logger在配置文件中有定义且设置了一个FileHandler处理器,simpleExample1处理器最终通过这个FileHandler处理器将日志记录输出到logging.log文件中了。

dictConfig()函数实现日志配置

关于dictConfig()函数的说明

函数定义:

  • 该函数定义在loging.config模块下:
logging.config.dictConfig(config)

该函数可以从一个字典对象中获取日志配置信息,config参数就是这个字典对象。关于这个字典对象的内容规则会在下面进行描述。

配置字典说明

无论是上面提到的配置文件,还是这里的配置字典,它们都要描述出日志配置所需要创建的各种对象以及这些对象之间的关联关系。比如,可以先创建一个名额为“simple”的格式器formatter;然后创建一个名为“console”的处理器handler,并指定该handler输出日志所使用的格式器为"simple";然后再创建一个日志器logger,并指定它所使用的处理器为"console"。

传递给dictConfig()函数的字典对象只能包含下面这些keys,其中version是必须指定的key,其它key都是可选项:

key名称描述
version必选项,其值是一个整数值,表示配置格式的版本,当前唯一可用的值就是1
formatters可选项,其值是一个字典对象,该字典对象每个元素的key为要定义的格式器名称,value为格式器的配置信息组成的dict,如format和datefmt
filters可选项,其值是一个字典对象,该字典对象每个元素的key为要定义的过滤器名称,value为过滤器的配置信息组成的dict,如name
handlers可选项,其值是一个字典对象,该字典对象每个元素的key为要定义的处理器名称,value为处理器的配置信息组成的dcit,如class、level、formatter和filters,其中class为必选项,其它为可选项;其他配置信息将会传递给class所指定的处理器类的构造函数,如下面的handlers定义示例中的stream、filename、maxBytes和backupCount等
loggers可选项,其值是一个字典对象,该字典对象每个元素的key为要定义的日志器名称,value为日志器的配置信息组成的dcit,如level、handlers、filters 和 propagate(yes
root可选项,这是root logger的配置信息,其值也是一个字典对象。除非在定义其它logger时明确指定propagate值为no,否则root logger定义的handlers都会被作用到其它logger上
incremental可选项,默认值为False。该选项的意义在于,如果这里定义的对象已经存在,那么这里对这些对象的定义是否应用到已存在的对象上。值为False表示,已存在的对象将会被重新定义。
disable_existing_loggers可选项,默认值为True。该选项用于指定是否禁用已存在的日志器loggers,如果incremental的值为True则该选项将会被忽略

使用yaml配置文件

首先需要安装PyYAML模块:

pip install PyYAML

配置文件的内容:

version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
  console_err:
    class: logging.StreamHandler
    level: ERROR
    formatter: simple
    stream: ext://sys.stderr
  info_file_handler:
    class: logging.handlers.RotatingFileHandler # 使用哪个Handler下面就要设置对应的参数
    level: INFO
    formatter: simple
    filename: info.log
    maxBytes: 10485760
    backupCount: 20
    encoding: utf8

loggers:
  simpleExample:
    level: DEBUG
    handlers: [console]
    propagate: yes
root:
  level: DEBUG
  handlers: [info_file_handler]

代码:

import logging.config
import yaml

with open('logging.yaml', 'r') as f_conf:
    dict_conf = yaml.load(f_conf, Loader=yaml.FullLoader)
logging.config.dictConfig(dict_conf)

logger = logging.getLogger('simpleExample')
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')

使用json配置文件

和yaml差不多

config = json.load(f)
logging.config.dictConfig(config)

多进程写日志问题

logging 是线程安全的,也就是说,在一个进程内的多个线程同时往同一个文件写日志是安全的

可以使用 ConcurrentLogHandler,ConcurrentLogHandler 可以在多进程环境下安全的将日志写入到同一个文件,并且可以在日志文件达到特定大小时,分割日志文件。在默认的 logging 模块中,有个 TimedRotatingFileHandler 类,可以按时间分割日志文件,可惜 ConcurrentLogHandler 不支持这种按时间分割日志文件的方式。

logging.config.dictConfig({
    ...
    'handlers': {
        'file': {
            'level': 'DEBUG',
            # 如果没有使用并发的日志处理类,在多实例的情况下日志会出现缺失
            'class': 'cloghandler.ConcurrentRotatingFileHandler',
            # 当达到10MB时分割日志
            'maxBytes': 1024 * 1024 * 10,
            # 最多保留50份文件
            'backupCount': 50,
            # If delay is true,
            # then file opening is deferred until the first call to emit().
            'delay': True,
            'filename': 'logs/mysite.log',
            'formatter': 'verbose'
        }
    },
    ...
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值