Python之配置日志的几种方式(logging模块)

作为开发者,我们可以通过以下3种方式来配置logging:

  • 1)使用Python代码显式的创建loggers, handlers和formatters并分别调用它们的配置函数;
  • 2)创建一个日志配置文件,然后使用fileConfig()函数来读取该文件的内容;
  • 3)创建一个包含配置信息的dict,然后把它传递个dictConfig()函数;

需要说明的是,logging.basicConfig()也属于第一种方式,它只是对loggers, handlers和formatters的配置函数进行了封装。另外,第二种配置方式相对于第一种配置方式的优点在于,它将配置信息和代码进行了分离,这一方面降低了日志的维护成本,同时还使得非开发人员也能够去很容易地修改日志配置。

一、使用Python代码实现日志配置


代码如下:

 
  1. # 创建一个日志器logger并设置其日志级别为DEBUG

  2. logger = logging.getLogger('simple_logger')

  3. logger.setLevel(logging.DEBUG)

  4.  
  5. # 创建一个流处理器handler并设置其日志级别为DEBUG

  6. handler = logging.StreamHandler(sys.stdout)

  7. handler.setLevel(logging.DEBUG)

  8.  
  9. # 创建一个格式器formatter并将其添加到处理器handler

  10. formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

  11. handler.setFormatter(formatter)

  12.  
  13. # 为日志器logger添加上面创建的处理器handler

  14. logger.addHandler(handler)

  15.  
  16. # 日志输出

  17. logger.debug('debug message')

  18. logger.info('info message')

  19. logger.warn('warn message')

  20. logger.error('error message')

  21. logger.critical('critical message')

运行输出:

 
  1. 2017-05-15 11:30:50,955 - simple_logger - DEBUG - debug message

  2. 2017-05-15 11:30:50,955 - simple_logger - INFO - info message

  3. 2017-05-15 11:30:50,955 - simple_logger - WARNING - warn message

  4. 2017-05-15 11:30:50,955 - simple_logger - ERROR - error message

  5. 2017-05-15 11:30:50,955 - simple_logger - CRITICAL - critical message

二、使用配置文件和fileConfig()函数实现日志配置


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

 
  1. # 读取日志配置文件内容

  2. logging.config.fileConfig('logging.conf')

  3.  
  4. # 创建一个日志器logger

  5. logger = logging.getLogger('simpleExample')

  6.  
  7. # 日志输出

  8. logger.debug('debug message')

  9. logger.info('info message')

  10. logger.warn('warn message')

  11. logger.error('error message')

  12. logger.critical('critical message')

配置文件logging.conf内容如下:

 
  1. [loggers]

  2. keys=root,simpleExample

  3.  
  4. [handlers]

  5. keys=fileHandler,consoleHandler

  6.  
  7. [formatters]

  8. keys=simpleFormatter

  9.  
  10. [logger_root]

  11. level=DEBUG

  12. handlers=fileHandler

  13.  
  14. [logger_simpleExample]

  15. level=DEBUG

  16. handlers=consoleHandler

  17. qualname=simpleExample

  18. propagate=0

  19.  
  20. [handler_consoleHandler]

  21. class=StreamHandler

  22. args=(sys.stdout,)

  23. level=DEBUG

  24. formatter=simpleFormatter

  25.  
  26. [handler_fileHandler]

  27. class=FileHandler

  28. args=('logging.log', 'a')

  29. level=ERROR

  30. formatter=simpleFormatter

  31.  
  32. [formatter_simpleFormatter]

  33. format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

  34. datefmt=

运行输出:

 
  1. 2017-05-15 11:32:16,539 - simpleExample - DEBUG - debug message

  2. 2017-05-15 11:32:16,555 - simpleExample - INFO - info message

  3. 2017-05-15 11:32:16,555 - simpleExample - WARNING - warn message

  4. 2017-05-15 11:32:16,555 - simpleExample - ERROR - error message

  5. 2017-05-15 11:32:16,555 - simpleExample - CRITICAL - critical message

1. 关于fileConfig()函数的说明:

该函数实际上是对configparser模块的封装,关于configparser模块的介绍请参考<

函数定义:

该函数定义在loging.config模块下:

logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)

参数:

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

2. 配置文件格式说明:

上面提到过,fileConfig()函数是对ConfigParser/configparser模块的封装,也就是说fileConfig()函数是基于ConfigParser/configparser模块来理解日志配置文件的。换句话说,fileConfig()函数所能理解的配置文件基础格式是与ConfigParser/configparser模块一致的,只是在此基础上对文件中包含的sectionoption做了一下规定和限制,比如:

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

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

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

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

  • 5)定义handler的section中必须指定classargs这两个option,levelformatter为可选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;

说明:

配置文件中的class指定类名时,该类名可以是相对于logging模块的相对值,如:FileHandlerhandlers.TimeRotatingFileHandler;也可以是一个绝对路径值,通过普通的import机制来解析,如自定义的handler类mypackage.mymodule.MyHandler,但是mypackage需要在Python可用的导入路径中--sys.path。

3. 对于propagate属性的说明

实例1:

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

 
  1. [logger_simpleExample]

  2. level=DEBUG

  3. handlers=consoleHandler

  4. qualname=simpleExample

  5. propagate=1

现在来执行同样的代码:

 
  1. # 读取日志配置文件内容

  2. logging.config.fileConfig('logging.conf')

  3.  
  4. # 创建一个日志器logger

  5. logger = logging.getLogger('simpleExample')

  6.  
  7. # 日志输出

  8. logger.debug('debug message')

  9. logger.info('info message')

  10. logger.warn('warn message')

  11. logger.error('error message')

  12. logger.critical('critical message')

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

 
  1. 2017-05-15 16:06:25,366 - simpleExample - ERROR - error message

  2. 2017-05-15 16:06:25,367 - simpleExample - CRITICAL - critical message

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

实例2:

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

 
  1. # 读取日志配置文件内容

  2. logging.config.fileConfig('logging.conf')

  3.  
  4. # 用一个没有在配置文件中定义的logger名称来创建一个日志器logger

  5. logger = logging.getLogger('simpleExample1')

  6.  
  7. # 日志输出

  8. logger.debug('debug message')

  9. logger.info('info message')

  10. logger.warn('warn message')

  11. logger.error('error message')

  12. logger.critical('critical message')

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

 
  1. 2017-05-15 16:13:16,810 - simpleExample1 - ERROR - error message

  2. 2017-05-15 16:13:16,810 - simpleExample1 - CRITICAL - critical message

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

三、使用字典配置信息和dictConfig()函数实现日志配置


Python 3.2中引入的一种新的配置日志记录的方法--用字典来保存logging配置信息。这相对于上面所讲的基于配置文件来保存logging配置信息的方式来说,功能更加强大,也更加灵活,因为我们可把很多的数据转换成字典。比如,我们可以使用JSON格式的配置文件、YAML格式的配置文件,然后将它们填充到一个配置字典中;或者,我们也可以用Python代码构建这个配置字典,或者通过socket接收pickled序列化后的配置信息。总之,你可以使用你的应用程序可以操作的任何方法来构建这个配置字典。

这个例子中,我们将使用YAML格式来完成与上面同样的日志配置。

首先需要安装PyYAML模块:

pip install PyYAML

Python代码:

 
  1. import logging

  2. import logging.config

  3. import yaml

  4.  
  5. with open('logging.yml', 'r') as f_conf:

  6. dict_conf = yaml.load(f_conf)

  7. logging.config.dictConfig(dict_conf)

  8.  
  9. logger = logging.getLogger('simpleExample')

  10. logger.debug('debug message')

  11. logger.info('info message')

  12. logger.warn('warn message')

  13. logger.error('error message')

  14. logger.critical('critical message')

logging.yml配置文件的内容:

 
  1. version: 1

  2. formatters:

  3. simple:

  4. format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

  5. handlers:

  6. console:

  7. class: logging.StreamHandler

  8. level: DEBUG

  9. formatter: simple

  10. stream: ext://sys.stdout

  11. console_err:

  12. class: logging.StreamHandler

  13. level: ERROR

  14. formatter: simple

  15. stream: ext://sys.stderr

  16. loggers:

  17. simpleExample:

  18. level: DEBUG

  19. handlers: [console]

  20. propagate: yes

  21. root:

  22. level: DEBUG

  23. handlers: [console_err]

输出结果:

 
  1. 2017-05-21 14:19:31,089 - simpleExample - DEBUG - debug message

  2. 2017-05-21 14:19:31,089 - simpleExample - INFO - info message

  3. 2017-05-21 14:19:31,089 - simpleExample - WARNING - warn message

  4. 2017-05-21 14:19:31,089 - simpleExample - ERROR - error message

  5. 2017-05-21 14:19:31,090 - simpleExample - CRITICAL - critical message

1. 关于dictConfig()函数的说明:

该函数实际上是对configparser模块的封装,关于configparser模块的介绍请参考<

函数定义:

该函数定义在loging.config模块下:

logging.config.dictConfig(config)

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

2. 配置字典说明

无论是上面提到的配置文件,还是这里的配置字典,它们都要描述出日志配置所需要创建的各种对象以及这些对象之间的关联关系。比如,可以先创建一个名额为“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则该选项将会被忽略

handlers定义示例:

 
  1. handlers:

  2. console:

  3. class : logging.StreamHandler

  4. formatter: brief

  5. level : INFO

  6. filters: [allow_foo]

  7. stream : ext://sys.stdout

  8. file:

  9. class : logging.handlers.RotatingFileHandler

  10. formatter: precise

  11. filename: logconfig.log

  12. maxBytes: 1024

  13. backupCount: 3

3. 关于外部对象的访问

需要说明的是,上面所使用的对象并不限于loggging模块所提供的对象,我们可以实现自己的formatter或handler类。另外,这些类的参数也许需要包含sys.stderr这样的外部对象。如果配置字典对象是使用Python代码构造的,可以直接使用sys.stdout、sys.stderr;但是当通过文本文件(如JSON、YAML格式的配置文件)提供配置时就会出现问题,因为在文本文件中,没有标准的方法来区分sys.stderr和字符串'sys.stderr'。为了区分它们,配置系统会在字符串值中查找特定的前缀,例如'ext://sys.stderr'中'ext://'会被移除,然后import sys.stderr

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Pythonlogging模块可以帮助你记录应用程序运行时的信息,以便于进行跟踪和分析。使用logging模块,你可以记录任何级别的消息,从debug级别的调试信息,到警告级别的错误信息,再到严重级别的异常信息。你可以将消息记录到一个文件中,或者通过网络传输到另一台计算机,以便进行远程监控。 ### 回答2: Pythonlogging模块是一种用于记录日志的工具,可以帮助我们在开发过程中进行日志记录和调试。下面是一个简要的介绍和使用该模块的步骤。 首先,我们需要导入logging模块: ``` import logging ``` 接下来,我们通过配置logging模块来设置日志的输出方式和级别。可以使用如下代码来进行基本的配置: ``` logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[ logging.FileHandler("log.txt"), logging.StreamHandler() ]) ``` 上述代码中: - `level`参数指定了日志的级别,可以包括`DEBUG`、`INFO`、`WARNING`、`ERROR`和`CRITICAL`等级别。 - `format`参数定义了日志输出的格式,可以使用`%(asctime)s`来表示时间戳,`%(levelname)s`表示日志级别,`%(message)s`表示日志内容。 - `handlers`参数指定了日志的输出目标,可以包括文件和终端等。 设置完配置后,我们就可以使用相应级别的日志函数进行日志的记录。例如,使用`log.debug()`方法记录`DEBUG`级别的日志: ``` logging.debug("This is a debug message") ``` 使用`log.info()`、`log.warning()`、`log.error()`等方法可以分别记录不同级别的日志。 最后,在程序完成后,可以使用`log.shutdown()`方法来关闭日志记录。 以上就是Pythonlogging模块的基本使用方法。通过合理使用logging模块,我们可以更好地进行日志记录和调试,提高程序的可读性和可维护性。 ### 回答3: Python中的logging模块是用于记录日志的工具。使用该模块可以方便地将程序运行过程中的各种信息输出到控制台或者保存到文件中,以便后续的查阅和分析。 首先需要导入logging模块,并进行基本的配置。可以通过以下几个步骤来完成: 1. 导入logging模块: import logging 2. 配置日志logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') 这里设置了日志的级别为DEBUG,即输出所有级别的日志信息;设置了日志的格式,包括时间、日志名称、日志级别和日志内容。 3. 输出日志logging.debug('This is a debug message.') logging.info('This is an info message.') logging.warning('This is a warning message.') logging.error('This is an error message.') logging.critical('This is a critical message.') 可以使用不同级别的日志函数输出不同级别的日志信息。 另外,还可以对日志进行更加详细的配置,例如设置日志的保存路径、日志的保存方式(覆盖、追加等)、最大保存文件数量等。通过使用不同的handler来实现。 以下是一个例子: import logging logger = logging.getLogger('app') logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(formatter) fh = logging.FileHandler('app.log') fh.setLevel(logging.WARNING) fh.setFormatter(formatter) logger.addHandler(ch) logger.addHandler(fh) logger.debug('This is a debug message.') logger.info('This is an info message.') logger.warning('This is a warning message.') logger.error('This is an error message.') logger.critical('This is a critical message.') 这样配置后,日志信息会同时输出到控制台和保存到文件app.log中。同时,控制台和文件中的日志信息级别由设置的handler决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值