Python Logging
原来真的远比我想象的要复杂不少不少,学习路线堪比git。可是又绕不过去,alternatives又少,因此必需要予以重视,踏踏实实认认真真的来好好学学才行。
学习Logging的目的:
简单脚本还好,print足够。
可是稍微复杂点,哪怕是三四个文件加起来两三百行代码,调试也开始变复杂起来了。
再加上若是是后台长期运行的那种脚本,运行信息的调查更是复杂起来。
一开始我还在各类查crontab
的日志查看,或者是python后台运行查看
,或者是python stdout的获取
等等,全都找错了方向。
真正的解决方案在于正确的logging。
记录好了的话,我不须要去找python的控制台输出stdout
,也不须要找crontab
的日志,只须要查看log文件便可。
下面是python的logging学习记录。python
import logging logging.error("出现了错误") logging.info("打印信息") logging.warning("警告信息")
网上各类关于python logging的文章实在是太不体谅新手了,logging这么复杂的东西居然想表现得很简单,还用各类简单的东西作假象。
实际上咱们真正要用起来的日志,绝对是不会直接用logging.info()
和logging.basicConfig()
这样的,这是此模块的官方推出来迷惑人的——看似让你一键上手,快速看到结果,可是跟实际真的不搭!
因此为了后面解释起来轻松,必须先警告这点:忘记它们俩!
记住,惟一要用到logging.
什么的,就只有logging.getLogger()
这一次。git
不想上流程图一类的东西,那样反而更迷糊。
简单说吧:logging
模块是会自动将你自定制的logger对象全局化
的,
也就是说,
你在本身的模块里只要定义了一次某个logger,好比叫log
,那么只要是在同一个模块中运行的其余文件都能读取到它。
好比说,你在主文件main.py
中自定义了一个logger,可能设置了什么输出文件、输出格式什么的,而后你在main.py
中会引用一些别的文件或模块,好比sub.py
,那么在这个sub.py
中你什么都不用设置,只要用一句logger = logging.getLogger('以前在main.py定义的日志名')
便可得到以前的一切自定义设置。函数
固然,被调用的文件(先称为子模块)中,用logging.getLogger('日志名')
时,最好在日志名后加一个.子名称
这样的,好比main.sub
。这样输出的时候就会显示出来某条日志记录是来自于这个文件里了。固然,.
前面的父级logger必须名字一致,是会被识别出来的!
而后,子日志还能够再子日志,甚至一个子模块能够再让全部函数各又一个子子日志,好比main.sub.func1
这样的。logging都会根据.
识别出来上下级关系的。学习
这样一说,实际上也就是class类继承的那种机制了。你按照父级名称继承,而后还能够改写本身的新设置等。测试
了解了这些概念之后,才能来谈代码。实际上也就好理解多了。调试
看来看去,这篇文章说得比较全面也最清楚,如下不少都参考到它的内容:Python 101: An Intro to logging日志
通常想要自定义一个logger,好比让它输出信息时按照什么格式显示,输出到哪一个文件,要不要输出到屏幕一类,有三种方法能够达到设置:code
三种达到的目的都是同样的,字典用的人不多也不方便,配置文件比较好用只是.ini
的语法不是很方便读,且不容易作到变量的动态设置,因此通常直接在python代码里写就好。orm
如下是程序主入口文件的通用写法,注意,必定要在主入口定义好logger,这样其余全部的子模块才可以继承到。对象
# main.py import logging import otherMod2 # 等下会调用到的子模块 def main(): """ 这个文件是程序的主入口 """ define_logger() log = logging.getLogger('exampleApp') # 输出信息测试 logger.info("Program started") result = otherMod2.add(7, 8) # 这个是来自别的模块的方法 logger.info("Done!") def define_logger(): logger = logging.getLogger("exampleApp") logger.setLevel(logging.INFO) # 设置输出格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 设置日志文件处理器 fh = logging.FileHandler("new_snake.log") fh.setFormatter(formatter) # 为这个处理器添加格式 # 设置屏幕stdout输出处理器 sh = logging.StreamHandler(stream=None) sh.setFormatter(formatter) # 把处理器加到logger上 logger.addHandler(fh) logger.addHandler(sh) if __name__ == "__main__": main()
下面是子模块中的调用方法(很简单):
# otherMod2.py import logging module_logger = logging.getLogger("exampleApp.otherMod2") def add(x, y): # 这里一句`getLogger`就继承到父级的logger了 logger = logging.getLogger("exampleApp.otherMod2.add") # 输出测试 logger.info("added %s and %s to get %s" % (x, y, x+y)) return x+y
注意,主文件
中,在什么地方定义logger均可以,能够在main()
里也能够在任何单独的函数或类里,无所谓。只要在调用子模块以前定义好了就能够了。一旦定义过,日志名
就会被记下来,而后子模块就能够轻松继承到。