python + logging 实现日志输出及保存到文件
最近缘由一个小需求, 得将日志保存至文件中。因平常调试皆只用print, 当不需要时又要把print删掉, 如此很是不便, 并且如此仅能把报错信息输出至控制台。于是去上网查找了一番, 有一个内置模块, 用以输出日志信息, 能够进行各类配置, 看过之后有种相见恨晚之感。下面开展一些个人总结过程, 主要是对自身学习予以归纳, 也期望能对你有所助益。1开始投入使用, 1.1首个程序。首先是最简单的使用# -*- coding: utf-8 -*- import logging logging.debug(debug级别一般用来打印一些调试信息级别最低) logging.info(info级别一般用来打印一些正常的操作信息) logging.warning(waring级别一般用来打印警告信息) logging.error(error级别一般用来打印一些错误信息) logging.critical(critical级别一般用来打印一些致命的错误信息等级最高)这样直接就可以在控制台输出日志信息了WARNING:root:waring级别一般用来打印警告信息 ERROR:root:error级别一般用来打印一些错误信息 CRITICAL:root:critical级别一般用来打印一些致命的错误信息等级最高1.2 日志级别能够发觉仅仅输出如下三条讯息, 这是鉴于其具备等级性的缘故上面那5个级别的讯息是按照从前往下的顺序依次递增的情况, 能够借助设置好的level, 使得只去打印处于某个级别往上的相关讯息。由于默认的等级是这样的情况, 所以只有在这个默认等级往上的级别的日志才会被打印出来。要是我们打算将debug以及info也给打印出来, 能够运用, 针对其展开配置:logging.basicConfig(levellogging.DEBUG)这样控制台的输出就会包含上面5条所有信息。日志级别并非仅存在特定情况才有, 大多数情况下日志是有分级的, 如此能够使我们于不同阶段关注各异重点, 像我们将某些调试信息用以debug级别输出, 并且把相应level设定为DEBUG, 这般当我们后续无需显示这些日志时, 只需把level改成info乃至更高, 不用如同print那样得去将那条语句注释掉或者删除掉。1.3 输出格式我们发觉, 上面的日志输出信息极为简略, 短时间内根本无法契合我们的需求, 举例而言, 我们或许需要输出该条信息的既定时间, 以及所处位置等等, 而这一模一样能够借助进行配置达成。logging.basicConfig(format%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s, levellogging.DEBUG)然后输出就会是这样的格式2019-07-19 15:54:26,625 - log_test.py[line:11] - DEBUG: debug级别一般用来打印一些调试信息级别最低可以指定输出的内容和格式其内置的参数如下%(name)sLogger的名字 %(levelno)s打印日志级别的数值 %(levelname)s打印日志级别的名称 %(pathname)s打印当前执行程序的路径其实就是sys.argv[0] %(filename)s打印当前执行程序名 %(funcName)s打印日志的当前函数 %(lineno)d打印日志的当前行号 %(asctime)s打印日志的时间 %(thread)d打印线程ID %(threadName)s打印线程名称 %(process)d打印进程ID %(message)s打印日志信息此外 还可以进行许多其他配置后文继续介绍。2 输出日志到文件 2.1 使用 配置文件路径到此为止, 我们仅仅是将日志输出至控制台, 只是, 好多时候, 我们说不定会具备把日志保存于文件的需求, 如此一来, 在程序产生问题之际, 便能够便利我们依据日志信息来实施定位了吖。最简单的方式是使用 logging.basicConfig(format%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s, levellogging.DEBUG, filenametest.log, filemodea)只是于先前配置之上, 增添与参数, 如此一来, 便能将日志输出至test.log文件里, 要是该文件不存在, 便会自动予以创建。参数为文件打开模式, 若不设置, 那么默认是’a’, 也就是追加模式, 并且不是必须设置还能够设置成’w’, 导致每次写日志时会将之前的日志直接覆盖。在实施了这般操作以后, 我们会察觉到控制台停止输出了, 那要怎样达成既往控制台输出又写入文件的情况呢?这需要更进一步的学习。2.2 模块化设计仅是以上这些, 我们不过是在用其去实施非常简易的操作而已, 然而这般所起到的作用是有限的, 实际上该库秉持了模块化的总体设计模式, 进而提供了诸多不同类型的系统组件, 其中包括记录器, 还有处理器, 另外有过滤器, 以及格式化器。暂且简单来讲, 其中存在着专门负责记录日志消息的部分, 而后, 对于所记录产生的这些日志消息要安放到何处去的问题, 将其交付给能够进行处理的一方去处置, 而这能够进行处理的一方会帮我们去过滤信息, 这里所说的过滤信息并不局限于只是依据级别来进行过滤, 还有与之类似的另外一个部分, 它所表示的意思跟上面提及的部分实际是一致的, 它的作用是被用来对日志内容以及相关格式进行设置。这样我们试一下使用模块的方式重新记录日志logger logging.getLogger(test) logger.debug(debug级别一般用来打印一些调试信息级别最低) logger.info(info级别一般用来打印一些正常的操作信息) logger.warning(waring级别一般用来打印警告信息) logger.error(error级别一般用来打印一些错误信息) logger.critical(critical级别一般用来打印一些致命的错误信息等级最高)首先, 在第一行, 获取了一个记录器, 该记录器中的命名标识了这个。接着, 下面的输出方式, 跟我们一开始的用法, 是很相似的, 看上去, 是不是很简单。然而, 这样是不行的, 运行后, 会报错:No handlers could be found for logger test话说此前我们并未针对这个予以指定, 致使它不清楚该如何去处理日志, 也不晓得要将日志输出至何处。那么我们就给它增添一个吧, 其种类存在许多, 其中常用的有4种:现在我们先使用最简单的把日志输出到控制台logger logging.getLogger(test) stream_handler logging.StreamHandler() logger.addHandler(stream_handler) ...这样就可以在控制台看到waring级别一般用来打印警告信息 error级别一般用来打印一些错误信息 critical级别一般用来打印一些致命的错误信息等级最高有条数不多的日志短缺着, 是鉴于我们未曾进行日志级别的设置, 我们也来设定一下级别, 而且通过模块对输出格式加以设置。logger logging.getLogger(test) logger.setLevel(levellogging.DEBUG) formatter logging.Formatter(%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s) stream_handler logging.StreamHandler() stream_handler.setLevel(logging.DEBUG) stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) ...是我们所发现的属于给进行设置的情况, 这能够很好地被理解, 原因在于它是承担着将日志输出至何处职责的, 所以是针对其情形给予设置格式, 并非另外的给予那么为何level会需要设置两次呢? 给予设置意味着告知它所要记录的是哪些级别的日志, 给予设置又是在告知它所要输出怎样级别的那些日志, 就差不多等同于已经进行了两次的过滤操作。这样存在好处点在于, 当我们存在多个日志去向情形时, 比如说既留存进文件, 又输出于控制台, 此时能够分别针对它们设置不一样的级别其级别是预先过滤的, 因而被其过滤的日志同样是无法予以记录的, 如此一来便能够仅仅改动其级别而不影响所有输出事项。而将两者进行结合的话能够更为便利地去管理日志记录所涉及的级别。有了我们就可以很方便地同时将日志输出到控制台和文件logger logging.getLogger(test) logger.setLevel(levellogging.DEBUG) formatter logging.Formatter(%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s) file_handler logging.FileHandler(test2.log) file_handler.setLevel(levellogging.INFO) file_handler.setFormatter(formatter) stream_handler logging.StreamHandler() stream_handler.setLevel(logging.DEBUG) stream_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(stream_handler)只需要多加一个即可。2.3 自动分割日志文件偶尔之际, 我们所需之事乃是针对日志档案予以划分, 目的在于能够便利我们予以管理。存在着两个处理器, 其作用是便于我们去分割文件:其使用方法跟上面所提及的相类似, 只是要添加一些参数配置, 举例来说, whenD意味着以天作为周期去对文件进行切分, 而其他参数的含义能够参考, 输出到屏幕, 把log日志写入文件。from logging import handlers time_rotating_file_handler handlers.TimedRotatingFileHandler(filenamerotating_test.log, whenD) time_rotating_file_handler.setLevel(logging.DEBUG) time_rotating_file_handler.setFormatter(formatter) logger.addHandler(time_rotating_file_handler)要是改成when等于S的情况, 就是按照秒作为周期来实施切割, 运转几次之后就会产生文件:其中没有后缀的为最新日志文件。参考文章 输出到屏幕将log日志写入文件标准模块–