python中的logger和handler到底是个什么鬼(代码片段)

风-fmgao 风-fmgao     2022-11-17     248

关键词:

最近的任务经常涉及到日志的记录,特意去又学了一遍logging的记录方法。跟java一样,python的日志记录也是比较繁琐的一件事,在写一条记录之前,要写好多东西。典型的日志记录的步骤是这样的:

  1. 创建logger
  2. 创建handler
  3. 定义formatter
  4. 给handler添加formatter
  5. 给logger添加handler

写成代码差不多就是酱婶的(这个是照别的网页抄的,参考附注):

 1 import logging 
 2 
 3 # 1、创建一个logger 
 4 logger = logging.getLogger(mylogger) 
 5 logger.setLevel(logging.DEBUG) 
 6 
 7 # 2、创建一个handler,用于写入日志文件 
 8 fh = logging.FileHandler(test.log) 
 9 fh.setLevel(logging.DEBUG) 
10 
11 # 再创建一个handler,用于输出到控制台 
12 ch = logging.StreamHandler() 
13 ch.setLevel(logging.DEBUG) 
14 
15 # 3、定义handler的输出格式(formatter)
16 formatter = logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s) 
17 
18 # 4、给handler添加formatter
19 fh.setFormatter(formatter) 
20 ch.setFormatter(formatter) 
21 
22 # 5、给logger添加handler 
23 logger.addHandler(fh) 
24 logger.addHandler(ch) 

之后才可以正式的开始记录日志。Java里面的java.util.Logging类差不多也是这样,代码还要更复杂一点。Golang的日志相对写法简单一些,不过没有什么格式,系统记录一条时间,内容格式完全自己手画。第三方的日志库倒是没有接触过,像Java的Log4j,Golang的log4go和seelog等等,不知道用起来会不会简单一点。我一直都记不住这些,因为不太理解logger和handler为什么要这样写。一直到这次任务中出现的在我看来相当“诡异”的bug,才深入理解了一下。

我的任务是这样的,要做一个日志切割的工具,按天将日志分割开,即每天0点产生一个新日志,将旧日志改名。并且,将超过3个月的日志删除掉,以保证磁盘空间不会被log占满。程序要求可以切割多个目录中的不同日志,具体路径由json中配置。

这里用到了logging.handlers类中的TimedRotatingFileHandler方法,用以获得一个handler。大概的写法为:

1 logger = logging.getLogger() #获得logger
2 handler = logging.handlers.TimedRotatingFileHandler(logfile, S‘, 1, 0) #切割日志
3 handler.suffix = %Y%m%d#切割后的日志设置后缀
4 logger.addHandler(handler) #把logger添加上handler
5 logger.fatal(datetime.datetime.now().strftime(%Y-%m-%d‘)) #在新日志中写上当天的日期

这里我没有设置level和formatter。因为只是分割,对新日志没有什么影响。TimedRotatingFileHandler函数的方法见附注,或查看python的源码,这个函数是python写的,可以找到定义。这里我使用的是每秒生成一个新的日志文件,之后用Crontab在每天0点调度,然后用for循环处理json中的每一个日志文件。

但是奇怪的是,每次运行程序,第一个切割的日志生成一个分割后的文件,而后面的都生成两个新日志。百思不得其解。后检查代码觉得,可能是程序中设置的时间太短了,每秒生成一个文件,有可能一秒钟处理不完,就生成了两个。虽然这个说法没有什么科学根据,但是还是把TimedRotatingFileHandler中的第三个参数改成了60,即每60秒生成一个文件。完成,静静的等待crontab到时间。

 

叮!时间到。赶紧检查一下结果。一个好消息和一个坏消息。好消息是这次每个日志都只切割生成了一个新文件,没有生成两个。坏消息是每个文件里面添加的当天的日期的数量见鬼了。我切割了4条日志,生成的新日志里面就分别写上了一、二、三、四行当天日期。

 

此刻我的内心几乎是崩溃的。我开始思考为什么会这样。很明显四行日期是调用了4次logger.fatal(‘datetime.datetime.now().strftime(‘%Y-%m-%d‘)) 这个函数。换句话说,我每一次for循环都在这个log里面写了一句话。可是明明每个for是处理一个日志,下一次for应该是处理下一个日志的,为什么会再处理这个日志一次?我突然想到,logger.addHandler(handler)是每次循环都会运行的,也就是说,logger是同一个logger,添加了4次handler。到第4次循环的时候,这个logger中有4个handler,也就会往4个不同的日志中添加内容了。呃。

 

如果是这样的话,那么把上面的程序改改,第一句和最后一句放在循环外,循环内只用中间的三句。这次OK了。回头再看log记录的步骤,也就明白了logger和handler到底是个什么鬼:logger可以看做是一个记录日志的人,对于记录的每个日志,他需要有一套规则,比如记录的格式(formatter),等级(level)等等,这个规则就是handler。使用logger.addHandler(handler)添加多个规则,就可以让一个logger记录多个日志。至于logging.getLogger()方法获得的root logger和继承关系,可以详见附注的网页,这里我也只是大概明白了什么意思,还没有具体用过。也许将来在框架中使用,要记录较为复杂的日志时候会用到吧。

java日志中的处理者(handler)问题

Logger默认的处理者是java.util.logging.ConsoleHandler,但为什么我定义一个Logger实例后用getHandlers()后得到的数组长度是0而不是1呢?importjava.util.logging.*;publicclassLoggerDemopublicstaticvoidmain(String[]args)Loggerlogger=Logger.getLogger("com.cn.jhy");Han... 查看详情

pythonlogging继承关系

...承而来。如下图所示:每个logger下面可能存在0个或多个handler,handler实现日志的输出,每个handler对应一个输出目标。通过配置多个handler,可以实现同时输出到文件,控制台的功能。同时,每个handler可以定制日志级别,从而使得... 查看详情

python日志模块介绍

...来创建日志消息,只需将需要记录的消息写进括号内即可Handler对象负责将日志消息(基于日志消息的严重性)分派给处理器的指定目标。在上一步中提到,可以使用Logger.addHandler()来添加零个或多个处理器对象。例如,算法可以... 查看详情

关于log4jjuljclslf4j等等日志组件的理解

...用程序访问日志系统的入口程序。  Appenders:也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以... 查看详情

python中的super到底是干什么的?

...好鸭,又是我小熊猫啦🖤今天来和大家一起学习一下python中的super知识点~有什么python相关报错解答自己不会的、或者源码资料/模块安装/女装大佬精通技巧都可以来这里:(https://jq.qq.com/?_wv=1027&k=2Q3YTfym)或者+V:python10 查看详情

logging将日志写入文件filehandler(代码片段)

importlogginglogger=logging.getLogger()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)logger.addHandler(handler)logger.info("Startpr... 查看详情

django日志(代码片段)

...n的logging模块中,主要包含下面四大金刚:Loggers:记录器Handlers:处理器Filters:过滤器Formatters:格式化器下文假定你已经对logging模块有一定的了解。否则,可能真的像看天书......一、在Django视图中使用logging使用方法非常简单,... 查看详情

时间戳中的 T 和 Z 到底是啥意思?

...意思?我正在尝试模拟这个网络服务,那么有没有办法在python中使用strftime生成 查看详情

python中的“容器”到底是啥? (以及所有的 python 容器类型是啥?)

】python中的“容器”到底是啥?(以及所有的python容器类型是啥?)【英文标题】:Whatexactlyare"containers"inpython?(Andwhatareallthepythoncontainertypes?)python中的“容器”到底是什么?(以及所有的python容器类型是什么?)【发布时... 查看详情

pythonlogging.formatter可以带变量吗

...判断是否要过滤3.根据其日志级别将该条日志分发给不同handler其常用函数有:Logger.setLevel()设置日志级别Logger.addHandler()和Logger.removeHandler()添加和删除一个HandlerLogger.addFilter()添加一个FilterHandlerHandler基于日志级别对日志进行分发... 查看详情

loggingbasic

...到什么地方,以及怎么输出;在python中,logging由logger,handler,filter,formater四个部分组成:    logger是提供我们记录日志的方法;handler是让我们选择日志的输出地方,如:控制台,文件,邮件发送等,一个logger添... 查看详情

python中的字典到底是有序的吗(代码片段)

之前写了文章介绍python中的列表和字典,在文章中描述到了python中的列表是有序的,字典是无序的,后来有粉丝在群里提醒我,说python3.6的版本之后,字典是有序的,因此,我找了一个低版本的python来... 查看详情

python中的KFold到底是做啥的?

】python中的KFold到底是做啥的?【英文标题】:WhatdoesKFoldinpythonexactlydo?python中的KFold到底是做什么的?【发布时间】:2016-07-0322:42:59【问题描述】:我正在看这个教程:https://www.dataquest.io/mission/74/getting-started-with-kaggle我进入第9部... 查看详情

python中更优雅的记录日志

...也可以自己使用level函数定义)。类似logging中的logger.addHandler,loguru统一使用add函数来管理格式、文件输出、过滤等操作,它提供了许多参数来实现logger.addHandler中的配置更加简单方便。其中sink是最重要的参数,可以传入不同的... 查看详情

python脚本demo(代码片段)

importatexitimportloggingimportosimportsignalimportsysfromlogging.handlersimportRotatingFileHandlerlogger=logging.getLogger()MAX=10*1024*1024BACK_UP_COUNT=10defsetup_logging():log_file=os.path.join(r'C:\',"demo.log")logger.setLevel(logging.INFO)file_handler=RotatingFileHandler(log_... 查看详情

logger:java原生日志工具(代码片段)

...日志工具java.util.logging.Logger1.目录位置关键类:其中Handler、Formatter配合使用,LogRecord是输出信息java.util.logging.Loggerjava.util.logging.Leveljava.util.logging.Handlerjava.util.logging.Formatterjava.util.logging.LogRecord2.Logger默认的格式输出默认的... 查看详情

javascript中的prototype到底是什么

Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言。在Javascript中,类和对象看起来没有太多的区别。什么是prototype:function定义的对象有一个prototype属性,prototype属性又指向了一个prototype对... 查看详情

[py3]——logging

logging模块的logger、handler、filter、formatterLogger记录器提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的nam... 查看详情