简介
按照上一篇的计划, 这一篇给小伙伴们讲解一下:(1)多模块使用 logging,(2)通过文件配置 logging 模块,(3)自己封装一个日志 (logging) 类. 可能有的小伙伴在这里会有个疑问一个 logging 为什么分两篇的篇幅来介绍她呢??? 那是因为日志是非常重要的, 用于记录系统, 软件操作事件的记录文件或文件集合, 可分为事件日志和消息日志. 具有处理历史数据, 诊断问题的追踪以及理解系统, 软件的活动等重要作用, 在开发或者测试软系统过程中出现了问题, 我们首先想到的就是她 --logging. 她可不像泰戈尔说的:"天空没有留下翅膀的痕迹, 但我已经飞过"; 这个 90 后的小姑娘, 她可是一个爱炫耀, 爱显摆的人已经达到了人过留名, 雁过留声的境界. 好了逗大家一乐, 下面开始进入今天的正题.
多模块使用 logging
1, 父模块 fatherModule.py:
2, 子模块 sonModule.py:
3, 运行结果, 在控制和日志文件 log.txt 中输出:
首先在父模块定义了 logger'fatherModule', 并对它进行了配置, 就可以在解释器进程里面的其他地方通过 getLogger('fatherModule')得到的对象都是一样的, 不需要重新配置, 可以直接使用. 定义的该 logger 的子 logger,
都可以共享父 logger 的定义和配置, 所谓的父子 logger 是通过命名来识别, 任意以'fatherModule'开头的 logger 都是它的子 logger, 例如'fatherModule.son'.
实际开发一个 application, 首先可以通过 logging 配置文件编写好这个 application 所对应的配置, 可以生成一个根 logger, 如'PythonAPP', 然后在主函数中通过 fileConfig 加载 logging 配置, 接着在 application 的其他地方, 不同的模块中, 可以使用根 logger 的子 logger,
如'PythonAPP.Core','PythonAPP.Web'来进行 log, 而不需要反复的定义和配置各个模块的 logger.
4, 参考代码
fatherModule.py 文件:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-24
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - 多模块使用 logging
- '''
- # 3. 导入模块
- import logging
- import sonModule
- logger = logging.getLogger("fatherModule")
- logger.setLevel(level = logging.INFO)
- handler = logging.FileHandler("log.txt")
- handler.setLevel(logging.INFO)
- formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- handler.setFormatter(formatter)
- console = logging.StreamHandler()
- console.setLevel(logging.INFO)
- console.setFormatter(formatter)
- logger.addHandler(handler)
- logger.addHandler(console)
- logger.info("creating an instance of sonModule.sonModuleClass")
- a = sonModule.SonModuleClass()
- logger.info("calling sonModule.sonModuleClass.doSomething")
- a.doSomething()
- logger.info("done with sonModule.sonModuleClass.doSomething")
- logger.info("calling sonModule.some_function")
- sonModule.som_function()
- logger.info("done with sonModule.some_function")
sonModule.py 文件:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-24
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - 多模块使用 logging
- '''
- # 3. 导入模块
- import logging
- module_logger = logging.getLogger("fatherModule.son")
- class SonModuleClass(object):
- def __init__(self):
- self.logger = logging.getLogger("fatherModule.son.module")
- self.logger.info("creating an instance in SonModuleClass")
- def doSomething(self):
- self.logger.info("do something in SonModule")
- a = []
- a.append(1)
- self.logger.debug("list a =" + str(a))
- self.logger.info("finish something in SonModuleClass")
- def som_function():
- module_logger.info("call function some_function")
文件配置 logging 模块
1, 通过 logging.config 模块配置日志构造信息
logger.conf 文件:
- [loggers]
- keys = root, example01, example02
- [logger_root]
- level = DEBUG
- handlers = hand01, hand02
- [logger_example01]
- handlers = hand01, hand02
- qualname = example01
- propagate = 0
- [logger_example02]
- handlers = hand01, hand03
- qualname = example02
- propagate = 0
- [handlers]
- keys = hand01, hand02, hand03
- [handler_hand01]
- class = StreamHandler
- level = INFO
- formatter = form01
- args=(sys.stdout, )
- [handler_hand02]
- class = FileHandler
- level = DEBUG
- formatter = form01
- args = ('log/test_case_log.log', 'a')
- [handler_hand03]
- class = handlers.RotatingFileHandler
- level = INFO
- formatter = form01
- args = ('log/test_case_log.log', 'a', 10*1024*1024,3)
- [formatters]
- keys = form01, form02
- [formatter_form01]
- format = %(asctime)s-%(filename)s-[line:%(lineno)d]-%(levelname)s-[LogInfoMessage]: %(message)s
- datefmt = %a, %d %b %Y %H:%M:%S
- [formatter_form02]
format = %(name)-12s: %(levelname)-8s-[日志信息]: %(message)s
datefmt = %a, %d %b %Y %H:%M:%S
一, 实例:
1, 实例代码
2, 运行结果:
3, 参考代码:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-27
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - 多模块使用 logging
- '''
- # 3. 导入模块
- import logging
- import logging.config
- logging.config.fileConfig("logger.conf")
- logger = logging.getLogger("example01")
- logger.debug('This is debug message')
- logger.info('This is info message')
- logger.warning('This is warning message')
二, 实例
1, 实例代码
2, 运行结果
3, 参考代码:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-24
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - 多模块使用 logging
- '''
- # 3. 导入模块
- import logging
- import logging.config
- logging.config.fileConfig("logger.conf")
- logger = logging.getLogger("example02")
- logger.debug('This is debug message')
- logger.info('This is info message')
- logger.warning('This is warning message')
2, 通过 JSON 文件配置
JSON 配置文件:
- {
- "version":1,
- "disable_existing_loggers":false,
- "formatters":{
- "simple":{
- "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- }
- },
- "handlers":{
- "console":{
- "class":"logging.StreamHandler",
- "level":"DEBUG",
- "formatter":"simple",
- "stream":"ext://sys.stdout"
- },
- "info_file_handler":{
- "class":"logging.handlers.RotatingFileHandler",
- "level":"INFO",
- "formatter":"simple",
- "filename":"info.log",
- "maxBytes":"10485760",
- "backupCount":20,
- "encoding":"utf8"
- },
- "error_file_handler":{
- "class":"logging.handlers.RotatingFileHandler",
- "level":"ERROR",
- "formatter":"simple",
- "filename":"errors.log",
- "maxBytes":10485760,
- "backupCount":20,
- "encoding":"utf8"
- }
- },
- "loggers":{
- "my_module":{
- "level":"ERROR",
- "handlers":["info_file_handler"],
- "propagate":"no"
- }
- },
- "root":{
- "level":"INFO",
- "handlers":["console","info_file_handler","error_file_handler"]
- }
- }
1, 通过 JSON 加载配置文件, 然后通过 logging.dictConfig 配置 logging:
2, 运行结果:
3, 参考代码:
- import JSON
- import logging.config
- import os
- def setup_logging(default_path = "logging.json",default_level = logging.INFO,env_key = "LOG_CFG"):
- path = default_path
- value = os.getenv(env_key,None)
- if value:
- path = value
- if os.path.exists(path):
- with open(path,"r") as f:
- config = JSON.load(f)
- logging.config.dictConfig(config)
- else:
- logging.basicConfig(level = default_level)
- def func():
- logging.info("start func")
- logging.info("exec func")
- logging.info("end func")
- if __name__ == "__main__":
- setup_logging(default_path = "logging.json")
- func()
3, 通过 YAML 文件配置
1, 首先要导入 YAML 模块, 输入命令 python2: pip install YAML python3:pip install pyyaml
2, 通过 YAML 文件进行配置, 比 JSON 看起来更加简介明了:
logging.YAML 文件:
- version: 1
- disable_existing_loggers: False
- formatters:
- simple:
- format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- handlers:
- console:
- class: logging.StreamHandler
- level: DEBUG
- formatter: simple
- stream: ext://sys.stdout
- info_file_handler:
- class: logging.handlers.RotatingFileHandler
- level: INFO
- formatter: simple
- filename: info.log
- maxBytes: 10485760
- backupCount: 20
- encoding: utf8
- error_file_handler:
- class: logging.handlers.RotatingFileHandler
- level: ERROR
- formatter: simple
- filename: errors.log
- maxBytes: 10485760
- backupCount: 20
- encoding: utf8
- loggers:
- my_module:
- level: ERROR
- handlers: [info_file_handler]
- propagate: no
- root:
- level: INFO
- handlers: [console,info_file_handler,error_file_handler]
3, 通过 YAML 加载配置文件, 然后通过 logging.dictConfig 配置 logging:
4, 运行结果:
5, 参考代码:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-24
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - yaml 文件配置 logging
- '''
- # 3. 导入模块
- import YAML
- import logging.config
- import os
- def setup_logging(default_path = "logging.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
- path = default_path
- value = os.getenv(env_key,None)
- if value:
- path = value
- if os.path.exists(path):
- with open(path,"r") as f:
- config = YAML.load(f)
- logging.config.dictConfig(config)
- else:
- logging.basicConfig(level = default_level)
- def func():
- logging.info("start func")
- logging.info("exec func")
- logging.info("end func")
- if __name__ == "__main__":
- setup_logging(default_path = "logging.yaml")
- func()
注意: 配置文件中 "disable_existing_loggers" 参数设置为 False; 如果不设置为 False, 创建了 logger, 然后你又在加载日志配置文件之前就导入了模块. logging.fileConfig 与 logging.dictConfig 默认情况下会使得已经存在的 logger 失效. 那么, 这些配置信息就不会应用到你的 Logger 上."disable_existing_loggers" = False 解决了这个问题
自己封装一个 logging 类
1, 实例代码:
2, 运行结果:
3, 参考代码:
- # coding=utf-8
- # 1. 先设置编码, utf-8 可支持中英文, 如上, 一般放在第一行
- # 2. 注释: 包括记录创建时间, 创建人, 项目名称.
- '''
- Created on 2019-5-27
- @author: 北京 - 宏哥
- Project: 学习和使用 python 的 logging 日志模块 - 自己封装 logging
- '''
- # 3. 导入模块
- import logging
- class Log(object):
- def __init__(self, name=__name__, path='mylog.log', level='DEBUG'):
- self.__name = name
- self.__path = path
- self.__level = level
- self.__logger = logging.getLogger(self.__name)
- self.__logger.setLevel(self.__level)
- def __ini_handler(self):
- """初始化 handler"""
- stream_handler = logging.StreamHandler()
- file_handler = logging.FileHandler(self.__path, encoding='utf-8')
- return stream_handler, file_handler
- def __set_handler(self, stream_handler, file_handler, level='DEBUG'):
- """设置 handler 级别并添加到 logger 收集器"""
- stream_handler.setLevel(level)
- file_handler.setLevel(level)
- self.__logger.addHandler(stream_handler)
- self.__logger.addHandler(file_handler)
- def __set_formatter(self, stream_handler, file_handler):
- """设置日志输出格式"""
- formatter = logging.Formatter('%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]'
- '-%(levelname)s-[日志信息]: %(message)s',
- datefmt='%a, %d %b %Y %H:%M:%S')
- stream_handler.setFormatter(formatter)
- file_handler.setFormatter(formatter)
- def __close_handler(self, stream_handler, file_handler):
- """关闭 handler"""
- stream_handler.close()
- file_handler.close()
- @property
- def Logger(self):
- """构造收集器, 返回 looger"""
- stream_handler, file_handler = self.__ini_handler()
- self.__set_handler(stream_handler, file_handler)
- self.__set_formatter(stream_handler, file_handler)
- self.__close_handler(stream_handler, file_handler)
- return self.__logger
- if __name__ == '__main__':
- log = Log(__name__, 'file.log')
- logger = log.Logger
- logger.debug('I am a debug message')
- logger.info('I am a info message')
- logger.warning('I am a warning message')
- logger.error('I am a error message')
- logger.critical('I am a critical message')
小结
1, 在 YAML 文件配置 logging 的时候, 会有个报警信息. 有代码洁癖的人, 可以处理一下
2, 是什么原因造成上面的告警呢??? 是因为: YAML 5.1 版本后弃用了 YAML.load(file)这个用法, 因为觉得很不安全, 5.1 版本之后就修改了需要指定 Loader, 通过默认加载器 (FullLoader) 禁止执行任意函数, 该 load 函数也变得更加安全.
3, 解决办法:
不用改很多代码 加一句就行了 在 YAML.load(f, Loader=YAML.FullLoader) 加上 Loader=YAML.FullLoader 就行了. 这里要注意的是 L 要大写的, 否则会报错的.
4, 加上以后, 看一下运行结果:
最后给大家留个彩蛋: 文章中有一处 bug, 会影响运行结果而报错, 聪明的你, 可以找到吗??? 嘿嘿!!! 欢迎互动和留言
来源: https://www.cnblogs.com/du-hong/p/10913133.html