问题
在最近的工作当中,需要使用到python的一个常见库叫做logging,这个库可以用于项目的日志记录,但是在我使用的过程当中却需要多个log对象分别输出到不同的日志文件当中的时候,我使用以下代码失败了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | import logging
 
  logging.basicConfig(level=logging.DEBUG,                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                     datefmt='%a, %d %b %Y %H:%M:%S',                     filename='test.log',                     filemode='w')
  log = logging log.debug('debug message')
  logging.basicConfig(level=logging.DEBUG,                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                     datefmt='%a, %d %b %Y %H:%M:%S',                     filename='test2.log',                     filemode='w')
  log = logging log.debug('debug message')
   | 
 
按照我浅薄的理解,这应该是两个对象才对,但是为啥最后只有一个日志文件生成,第二个对象并没有生成日志文件呢?
原因
根据官方的解释:
根据basicConfig源码可以发现只有当“handlers”的长度为0时才会进行日志信息配置,否则跳过该配置步骤。那么在步骤1中root已经自动进行了日志信息配置,“handlers”的长度不为0,则步骤2中的“logging.basicConfig”并没有达到日志信息配置的作用。
那么有没有什么办法可以解决呢?
解决没办法配置的问题的答案当然是有的,那就是在python3.8及之后在basicConfig中新增了force参数,当“force=True”时可以强制进行日志信息重新设置。也就是如下代码:
1 2 3 4 5 6
   | logging.basicConfig(level=logging.DEBUG,                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                     datefmt='%a, %d %b %Y %H:%M:%S',                     filename='test.log',                     filemode='w',                     force=True) 
   | 
 
但是这还是有问题,因为这个仅仅支持重新配置,并不支持将对象保存起来因此如果代码写成了下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | import logging
 
  logging.basicConfig(level=logging.DEBUG,                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                     datefmt='%a, %d %b %Y %H:%M:%S',                     filename='test.log',                     filemode='w',                     force=True)
  log1 = logging
 
  logging.basicConfig(level=logging.DEBUG,                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                     datefmt='%a, %d %b %Y %H:%M:%S',                     filename='test2.log',                     force=True,                     filemode='w')
  log2 = logging log1.debug('debug message') log2.debug('debug message')
   | 
 
运行之后就会发现,虽然是两个对象,也生成了两个日志文件,但是却只能往一个文件里面输入日志信息,也就是最后指定的那个文件。
后续疑问
假设就是需要同时存在两个不同的log对象,用于写入不同的日志文件该怎么办?如果是上述方法,也不可能需要写的时候立马修改吧。在学习中我发现另一种方法能够解决这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
   | NG_DIC = {     'version': 1,     'disable_existing_loggers': False,          'formatters': {         'standard': {             'format': "[%(levelname)s][%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]"                       "[%(message)s]"         },         'simple': {             'format': "[%(levelname)s] [%(asctime)s] [%(name)s] [%(filename)s:%(lineno)d] [%(message)s]"         },     },     'filters': {},     'handlers': {         'file': {             'level': 'INFO',             'class': 'logging.handlers.RotatingFileHandler',                          'filename': "log.log",                          'maxBytes': 15 * 1024 * 1024,                          'backupCount': 10,                          'formatter': 'simple'         },         'console': {             'level': 'DEBUG',             'class': 'logging.StreamHandler',             'formatter': 'simple'         },     },     'loggers': {                  'tasks': {             'handlers': ["file"],             'level': 'INFO',             'propagate': False,           },         '': {             'handlers': ["file"],             'level': 'INFO',             'propagate': False,           }     } }
  logging.config.dictConfig(LOGGING_DIC) logger1 = logging.getLogger('tasks') logging.info("123123123")
  | 
 
使用字典配置的方法可以解决需要创建多个log对象的问题。