找回密码
 会员注册
查看: 23|回复: 0

万字长文-Python日志记录器logging百科全书-高级配置之日志文件配置

[复制链接]

4

主题

0

回帖

13

积分

新手上路

积分
13
发表于 2024-9-10 17:07:10 | 显示全部楼层 |阅读模式
万字长文-Python日志记录器logging百科全书-高级配置之日志文件配置前言在Python的logging模块中,它不仅提供了基础的日志功能,还拥有一系列高级配置选项来满足复杂应用的日志管理需求。说到logging模块的高级配置,必须提及日志分层、logging.config配置、日志异步操作等关键功能。它们每一项都为开发者提供了强大的调试和监控环境,对于构建可维护和高效的日志系统至关重要。在接下来的三篇logging高级配置文章中,我将为读者朋友们介绍Python的logging模块中的三个高级配置的具体应用:日志分层、logging.config以及日志异步操作,探讨它们如何优化日志处理流程,并提升应用的整体性能。本文将聚焦于logging模块中的日志文件配置概念,探讨如何通过配置文件灵活定义和调整日志记录器的行为。我们将详细解析如何利用配置文件来设置日志级别、格式、输出目的地等,以构建一个既灵活又可扩展的日志系统。知识点📖📖模块释义loggingPython的日志记录工具,标准库logging.config日志文件配置函数导入模块importloggingimportlogging.config123文章脉络:点击直达:万字长文-Python日志记录器logging百科全书之基础配置点击直达:Python日志记录器logging百科全书之日志回滚点击直达:万字长文-Python日志记录器logging百科全书之日志过滤点击直达:万字长文-Python日志记录器logging百科全书-高级配置之日志分层点击直达:万字长文-Python日志记录器logging百科全书-高级配置之日志文件配置理解文件配置logging.configlogging.config专门用于配置日志系统。它提供了灵活的配置方式,支持多种配置方法,包括基于文件的配置(如INI、JSON和YAML文件等)。作用和应用场景logging.config模块的主要作用是提供一种标准化、灵活的方法来配置Python应用程序中的日志记录。通过使用这个模块,开发者可以轻松定义日志的级别、格式、输出目标(如文件、控制台、网络服务等)以及其他高级功能,比如日志轮转和过滤。它适用于各种规模的Python应用程序,从小型脚本到大型系统。在复杂的系统中,logging.config可以立大功,因为它可以帮助管理和控制多个日志记录器和处理器。下面是logging.config中常用的方法及其作用:方法名作用dictConfig(config_dict)使用字典配置日志记录器。fileConfig(fname,defaults=None,disable_existing_loggers=True)从配置文件加载日志配置。listen(port=DEFAULT_LOGGING_CONFIG_PORT)监听远程日志配置的更改。stopListening()停止监听远程日志配置的更改。下面只介绍关于dictConfig和fileConfig,因为listen不常用。⚠️⚠️注意点建议使用dictConfig,而不是fileConfig。先说结论,fileConfig在某些方面(不支持filters,需要额外配置)显得不够灵活,适用于简单的日志配置需求。dictConfig提供了更高的灵活性和更全面的配置选项,更适合复杂的日志配置需求。logging.config.dictConfig较比logging.config.fileConfig可谓是遥遥领先!!dictConfig支持JSON和YAML格式,支持所有日志配置功能,可以更灵活地表示复杂的配置结构,包括过滤器、多个处理器和记录器等。fileConfig支持INI格式的文件,这种格式相对简单,在表达能力上不如JSON或YAML强。不支持直接在配置文件中定义过滤器,只适合简单的日志配置需求。logging.config.dictConfig配置字典,支持字典,JSON和YAML格式。无论使用哪种格式,它们的主要区别在于数据格式和可读性。选择更加符合自己的开发习惯的即可。JSON:格式更严格(例如,必须使用双引号,不能有注释)。在多数编程环境中广泛支持。可能更适合那些习惯于编程和处理结构化数据的用户。YAML:可读性更好,容错性更好(例如,可以使用注释,对引号不敏感)。适合配置文件,因为它更易于读写,特别是对于较长或复杂的配置。需要额外的库来解析(Python中需要安装PyYAML)。下面将使用dict()字典进行介绍(因为方便),JSON和YAML格式自行学习~方法:logging.config.dictConfig(config)1基本示例下面是一个使用logging.config.dictConfig的简单示例,这个示例配置了基本的日志记录功能,只包含一个将日志信息输出到控制台的处理器(handler)定义了一个名为console的处理器,它使用logging.StreamHandler将日志信息输出到控制台(标准输出)。设置了一个简单的日志格式,包括时间戳、日志级别和日志消息。配置了根日志记录器,将其日志级别设置为INFO,这意味着只有INFO级别及以上(如WARNING,ERROR,CRITICAL)的日志会被处理。使用dictConfig函数应用这个配置。示例代码importloggingfromlogging.configimportdictConfig#日志配置字典log_config={'version':1,'handlers':{'console':{#定义一个名为"console"的处理器'class':'logging.StreamHandler','level':'INFO','formatter':'simple','stream':'ext://sys.stdout'#使用标准输出}},'formatters':{'simple':{#定义一个简单的格式器'format':'%(asctime)s-%(levelname)s-%(message)s','datefmt':'%Y-%m-%d%H:%M:%S'}},'root':{#配置根日志记录器'level':'INFO','handlers':['console']}}#应用日志配置dictConfig(log_config)#获取日志记录器logger=logging.getLogger()#记录一些日志logger.info("这是一个信息级别的日志")logger.warning("这是一个警告级别的日志")123456789101112131415161718192021222324252627282930313233343536参数详解下面的每一个参数都不是独立的,最终它们结合起来,便是一份完整的logging.config.dictConfig的日志文件配置。以下是logging.config.dictConfig方法中各个参数的整理:参数名类型必需描述versionint必需唯一一个必选项,必须设置为1,表示配置字典的版本。formattersdict可选定义日志的格式,键是格式器的名称,值是格式器的配置字典。filtersdict可选定义过滤器,用于过滤日志记录。键是过滤器的名称,值是过滤器的配置字典。handlersdict可选定义处理程序,决定日志如何输出。键是处理程序的名称,值是处理程序的配置字典。loggersdict可选定义记录器,用于生成日志记录。键是记录器的名称,值是记录器的配置字典。rootdict可选定义根记录器的配置,包含日志级别和处理程序列表。incrementalbool可选默认False,用于指定是否应该增量地应用配置。disable_existing_loggersbool可选默认True,用于指定是否禁用所有已存在的记录器。1.version应设为代表架构版本的整数值。目前唯一有效的值是1。唯一一个必选项,必须设置为1,表示配置字典的版本。logg_config={'version':1}1232.formatters对应的值是一个字典,其中每个键是一个格式器ID而每个值则是一个描述如何配置相应Formatter实例的字典以下是formatters字典中全部的参数:format:定义日志消息的格式。这是一个字符串,可以包含各种日志记录属性的占位符,如%(levelname)s,%(message)s,%(asctime)s等。datefmt:定义日期和时间的格式。这是一个字符串,用于格式化日志记录中的时间戳,例如%Y-%m-%d%H:%M:%S。style:指定format字符串的格式化风格。Python标准库的日志模块支持三种风格:‘%’(默认)、‘{‘和’$’。validate:布尔值,指定是否对format字符串进行验证。默认为True。class:指定自定义的格式器类。这是可选的,仅当需要使用不是标准的logging.Formatter的格式器时使用。示例代码:包含两个格式器,simple和complex,分别指定了format、style等log_config={'version':1,'formatters':{'simple':{'format':'%(levelname)s-%(asctime)s-%(name)s-%(message)s','style':'%',#默认值'datefmt':'%Y-%m-%d%H:%M:%S',},'complex':{'format':'{levelname}-{asctime}-{name}-{message}','style':'{'}}}12345678910111213143.filters这里可以结合这篇文章食用:万字长文-Python日志记录器logging百科全书之日志过滤对应的值将是一个字典,其中每个键是一个过滤器ID而每个值则是一个描述如何配置相应Filter实例的字典。配置日志记录的过滤器,一般过滤器需要绑定到处理器中,所以需要结合下面的handlees使用。name:字符串,过滤器名称():字符串,过滤器的类命,用于指定日志系统使用哪个过滤器,如logging.Filter,也可以是自定义过滤器类的路径。param:可选,如果过滤类有需要,则可传递。无param参数:自定义过滤器CommonFilter,console_filter指定的过滤器类路径为CommonFilter(__main__需要更改为自定义过滤器的路径importlogging#自定义过滤器-控制台使用classCommonFilter(logging.Filter):deffilter(self,record):#过滤掉包含敏感信息的日志return"敏感信息"notinrecord.getMessage()log_config={'version':1,'filters':{'console_filter':{'()':'__main__.CommonFilter'}}}123456789101112131415161718有param参数:携带参数importlogging#自定义过滤器-控制台使用classCommonFilter(logging.Filter):def__init__(self,param1=None,param2=None):super().__init__()self.param1=param1self.param2=param2deffilter(self,record):#过滤掉包含敏感信息的日志return"敏感信息"notinrecord.getMessage()log_config={'version':1,'filters':{'console_filter':{'()':'__main__.CommonFilter','param1':"value1",'param2':"value2"}}}12345678910111213141516171819202122232425264.handlers对应的值将是一个字典,其中每个键是一个处理器ID而每个值则是一个描述如何配置相应Handler实例的字典。参数名类型必需描述classstring必需处理器的类名,例如logging.StreamHandler或logging.handlers.FileHandlerlevelstring可选处理器的日志级别,例如‘DEBUG’、‘INFO’、‘WARNING’、‘ERROR’或‘CRITICAL’。默认为‘NOTSET’formatterstring可选处理器使用的格式化器的名称,通常与formatters字典中的一个格式化器名称对应filenamestring可选只有在处理器类型为FileHandler时才适用。指定写入日志的文件名modestring可选只有在处理器类型为FileHandler时才适用。指定文件的打开模式,默认为aencodingstring可选只有在处理器类型为FileHandler时才适用。指定文件的编码,默认为Nonedelaybool可选只有在处理器类型为FileHandler时才适用。指定文件创建的时机streamstring可选只有在处理器类型为StreamHandler时才适用。指定输出流,例如ext://sys.stdout,默认为sys.stderrfilterslist可选指定一个或多个过滤器的名称列表,用于过滤要发送到处理器的日志消息代码一般来说,需要将日志处理器(Handler)添加到日志记录器(Logger)中才能使用。包含两个处理器console和file,分别设置了class,formatter,level,等,注意FileHandler和StreamHandler所接受的参数有所不同!log_config={'version':1,'handlers':{'console':{'class':'logging.StreamHandler','formatter':'simple','level':'DEBUG','filters':['common_filter'],'stream':'ext://sys.stdin',},'file':{'class':'logging.FileHandler','formatter':'complex','level':'DEBUG','filters':['common_filter'],'filename':'app.log','mode':'a','encoding':'utf-8',}}}1234567891011121314151617181920215.loggers其中每个键是一个日志记录器名称,而每个值则是一个描述如何配置相应Logger实例的字典。每个日志记录器可以接受以下参数:level(可选)。字符串,日志记录器的级别。propagate(可选)。布尔值,日志记录器的传播设置。filters(可选)。由日志记录器对应过滤器的ID组成的列表。handlers(可选)。由日志记录器对应处理器的ID组成的列表。代码配置这里就不解释了,在前的文章都有介绍~log_config={'version':1,'loggers':{'common_logger':{'level':'DEBUG','filters':['common_filter'],'handlers':['console'],},'common_logger.file':{'level':'WARNING','propagate':False,'filters':['common_filter'],'handlers':['console','file'],}}}12345678910111213141516176.root根日志记录器对应的配置。配置的处理方式将与所有日志记录器一致,除了propagate设置将不可用之外。一般情况下,不需要显式设置根日志记录器(rootlogger),我们只需要设置自定义的子记录器Logger即可。如果我们的应用可能会使用默认的日志记录器(即直接通过logging.getLogger()获取的记录器),那么配置根日志记录器是有意义的,因为它定义了这些记录器的默认行为。根记录器的目的是提供一个全局的、基本的日志配置,为了保持简单和明确,通常不会涉及过于复杂的参数设置。置根日志记录器的root部分包含以下参数:level(可选):设置根日志记录器的日志级别。handlers(可选):指定一个处理器列表,这些处理器会被附加到根日志记录器。这些处理器控制日志信息的输出方式和位置。propagate(可选):不常用于root,对于非根日志记录器,这个布尔值指定日志信息是否向上传播到父记录器。但对于根记录器本身,这个设置通常不适用或忽略,因为根记录器是层级的顶端。示例代码指定跟日志记录器的level,handlers,filters等log_config={'version':1,'root':{'level':'DEBUG','handlers':['console','file'],'filters':['common_filter']}}123456787.incremental配置是否要被解读为在现有配置上新增。该值默认为False.当incremental=True时,这意味着正在进行增量更新。只有在配置字典中显式修改的部分会被更新,而其他的配置将保持不变;当不使用incremental=True,并且提供了一个新的配置字典给dictConfig,那么整个日志配置将被这个新的配置字典替换(被覆盖)。使用incremental=True的主要作用是允许对日志配置进行部分更新,!!!值得注意的是系统将完全忽略任何formatters和filters条目,并仅会处理handlers条目中的level设置,以及loggers和root条目中的level和propagate设置。应用场景假设小菜维护一个在生产环境中运行的Web服务,该服务正常情况下仅记录INFO级别以上的日志。但是,当遇到某些特定问题时,小菜可能需要临时增加日志的详细程度,以便能更好地分析和调试问题。例如,小菜可能想要将某个模块的日志级别从INFO提升到DEBUG来获得更多信息。示例代码在不重写整个日志配置的情况下动态调整日志配置,仅更新了日志级别。这对于生产环境中的问题诊断和调试会有用。初始日志配置:最初,小菜的日志配置设置为仅记录INFO级别及以上的日志。检测到特定问题:当系统检测到特定问题(可能是通过错误计数、特定类型的请求或其他指标)时,小菜想动态调整相关模块的日志级别以捕获更详细的信息。应用增量更新:此时,小菜可以使用incremental=True来更新特定日志记录器的配置,而不影响其他配置。importloggingfromlogging.configimportdictConfigimporttime#初始配置,记录INFO级别及以上的日志initial_config={'version':1,'handlers':{'console':{'class':'logging.StreamHandler','level':'DEBUG'}},'root':{'level':'INFO','handlers':['console'],}}dictConfig(initial_config)logger=logging.getLogger()#模拟应用程序运行foriinrange(5):ifi==3:#当出现特定条件时,提升日志级别到DEBUGincremental_config={'version':1,'incremental':True,'root':{'level':'DEBUG'}}dictConfig(incremental_config)logger.debug("日志级别已提升至DEBUG")logger.debug(f"详细的调试信息{i}")logger.info(f"一般的信息{i}")time.sleep(1)123456789101112131415161718192021222324252627282930313233343536373839408.disable_existing_loggers是否要禁用任何现有的非根日志记录器。形参默认为True。这个选项的作用主要是控制新的日志配置是否会影响到现有的日志记录器。当disable_existing_loggers设置为True时,它的作用是关闭(禁用)之前创建的所有日志记录器,除非它们在新的日志配置中明确定义。当disable_existing_loggers设置为False时,它的作用是忽略之前创建的日志记录器,不会关闭它们,除非在新的日志配置中明确定义。如果希望保留现有记录器的配置,并且不希望新的配置覆盖它们,通常会将disable_existing_loggers设置为False。如果想要在新的配置中重新定义所有记录器的配置,则不必理会,因为disable_existing_loggers默认为True。log_config={'version':1,'disable_existing_loggers':False}1234🧐使用JSONlog_config.json{"version":1,"formatters":{"simple":{"format":"%(asctime)s-%(levelname)s-%(name)s-%(message)s"}},"handlers":{"console":{"class":"logging.StreamHandler","formatter":"simple","level":"DEBUG"}},"root":{"level":"INFO","handlers":["console"]}}12345678910111213141516171819代码importloggingimportlogging.configimportjson#从JSON文件加载配置withopen('log_config.json','r')asfile:config=json.load(file)logging.config.dictConfig(config)#获取日志记录器logger=logging.getLogger()1234567891011🎈使用YAML整体来看,确实需要比YAML确实会比JSON更加简单和容易阅读。配置与上面的使用JSON同款。log_config.yamlversion:1 #如需要则添加注释formatters:simple:format:"%(asctime)s-%(levelname)s-%(name)s-%(message)s"handlers:console:class:logging.StreamHandlerformatter:simplelevelEBUGroot:level:INFOhandlers:[console]123456789101112首先需要安装PyYAMLpipinstallpyyaml1代码importloggingimportlogging.configimportyaml#从YAML文件加载配置withopen('log_config.yaml','r')asfile:config=yaml.safe_load(file)logging.config.dictConfig(config)#获取日志记录器logger=logging.getLogger()1234567891011logging.config.fileConfig配置文件,支持INI文件⚠️⚠️⚠️不支持过滤器⚠️⚠️⚠️不支持过滤器⚠️⚠️⚠️不支持过滤器方法:logging.config.fileConfig(fname,defaults=None,disable_existing_loggers=True,encoding=None)1这里只做基本介绍,不深入。因为它不够友好。参数详解以下是logging.config.fileConfig函数的参数整理:参数名称类型必需描述fnamestr必须配置文件的路径。这个文件包含了日志配置的信息。defaultsdict可选配置文件中使用的变量的默认值。disable_existing_loggersbool可选决定是否禁用在调用fileConfig之前已经存在的日志记录器。默认为True。encodingstr可选用于指定配置文件的编码方式。必需的字段在logging.config.fileConfig中使用的INI文件中,有几个必需的字段来确保至少基本的日志配置能够工作。以下是一个最简单的示例,其中包含了必需的基础字段。[loggers]:至少需要列出需要配置的日志记录器。[handlers]:至少需要定义一个处理器。[formatters]:至少需要定义一个格式器。[logger_]:为每个需要配置的记录器定义具体配置。[handler_]:为每个处理器定义具体配置。[formatter_]:为每个格式器定义具体配置。基础示例INI文件log_config.ini这个配置定义了一个根日志记录器root,它的日志级别为INFO。有一个处理器consoleHandler,它将日志输出到标准输出(控制台),同时也设置为INFO级别。有一个格式器simpleFormatter,它定义了日志的显示格式。[loggers]keys=root[handlers]keys=consoleHandler[formatters]keys=simpleFormatter[logger_root]level=INFOhandlers=consoleHandler[handler_consoleHandler]class=StreamHandlerlevel=INFOformatter=simpleFormatterargs=(sys.stdout,)[formatter_simpleFormatter]format=%(asctime)s-%(levelname)s-%(message)sdatefmt=%Y-%m-%d%H:%M:%S12345678910111213141516171819202122示例代码代码通过fileConfig加载INI文件中的配置,然后使用getLogger创建一个日志记录器。此记录器将根据INI文件中定义的配置处理日志消息。importloggingimportlogging.configlogging.config.fileConfig('log_config.ini')#创建日志记录器logger=logging.getLogger()#记录消息logger.info("这是一个信息级别的日志")logger.debug("这条调试消息不会显示,因为日志级别设置为INFO")123456789101112特别处理:添加filtersimportloggingimportlogging.config#自定义过滤器classCommonFilter(logging.Filter):deffilter(self,record):#过滤掉包含敏感信息的日志return"敏感信息"notinrecord.getMessage()logging.config.fileConfig('log_config.ini')#创建日志记录器logger=logging.getLogger()#添加过滤器logger.addFilter(CommonFilter())#记录消息logger.info("这是一个信息级别的日志")logger.debug("这条调试消息不会显示,因为日志级别设置为INFO")123456789101112131415161718192021实际案例以下的代码来自万字长文-Python日志记录器logging百科全书-高级配置之日志分层里的示例代码,将他修改成本文所介绍的logging.config高级配置。importloggingimportlogging.configimportrequestsimportsysclassRemoteLogHandler(logging.Handler):"""自定义远程处理器"""def__init__(self,remote_url):super().__init__()self.remote_url=remote_urlself.error_logger=logging.getLogger('error')#self.setFormatter(formatter)defemit(self,record):#发送日志记录到远程服务器log_entry=self.format(record)#格式化日志记录try:response=requests.post(self.remote_url,data=log_entry)response.raise_for_status()exceptExceptionase:record.msg=f"Originalmessage:{record.msg},Failedtosendlogtoremote:{str(e)}"print('error_logger等级是',self.error_logger.level)self.error_logger.handle(record)log_config={'version':1,'formatters':{'simple':{'format':'%(levelname)-7s-%(asctime)s-%(name)s-%(message)s'}},'handlers':{'file_global':{'()':'logging.FileHandler','filename':'ecommerce_global.log','level':'DEBUG','formatter':'simple','delay':True},'file_error':{'()':'logging.FileHandler','filename':'error.log','level':'ERROR','formatter':'simple','delay':True},'file_order':{'()':'logging.FileHandler','filename':'orders.log','level':'WARNING','formatter':'simple','delay':True},'file_payment':{'()':'logging.FileHandler','filename':'payments.log','level':'ERROR','formatter':'simple','delay':True},'stream':{'()':'logging.StreamHandler','stream':'ext://sys.stdout','formatter':'simple'},'remote':{'()':'__main__.RemoteLogHandler','remote_url':'http://127.0.0.1:5000/submit_log',}},'loggers':{'ecommerce':{'handlers':['file_global','stream'],'level':'DEBUG'},'ecommerce.orders':{'handlers':['file_order','remote'],'level':'INFO','propagate':False},'ecommerce.payments':{'handlers':['file_payment','remote'],'level':'WARNING','propagate':False},'error':{'handlers':['file_error'],'level':'WARNING',}}}if__name__=='__main__':logging.config.dictConfig(log_config)#使用日志记录器global_logger=logging.getLogger('ecommerce')order_logger=logging.getLogger('ecommerce.orders')payment_logger=logging.getLogger('ecommerce.payments')#日志测试global_logger.info('Globalloggerconfigured')order_logger.warning('Orderloggerconfigured')payment_logger.error('Paymentloggerconfigured')123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107总结🎈🎈本文全面介绍了Python中logging模块的高级文件配置技巧,重点讨论了dictConfig和fileConfig两种配置方法。通过dictConfig,开发者可以灵活地使用字典、JSON或YAML格式来设置日志级别、格式和处理器,而fileConfig则提供了对INI格式配置文件的支持。尽管fileConfig在功能上有所限制,但它仍适用于简单的配置需求。文章通过实例和注意事项,指导读者如何选择和应用这些配置方法,以优化日志处理流程并提升应用性能。总的来说,这篇文章可以帮助读者朋友们深入了解如何使用logging.config进行日志文件配置。进而帮助读者建立一个高效、可维护的日志系统。后话本次分享到此结束,seeyou~~✨✨
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-7 07:03 , Processed in 0.921107 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表