Python编程-使用logging管理程序日志

2024-04-06 06:28

本文主要是介绍Python编程-使用logging管理程序日志,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Python编程-使用logging管理程序日志

自动化运维时时常用到,故抽时间专门总结

Python的logging模块是Python内置的日志记录工具,用于在程序中实现灵活的日志记录功能。使用logging模块可以记录程序运行时的各种信息,如调试信息、警告、错误等,以便在需要时进行排查和分析。

Python的logging模块定义了5个日志级别,用于指示日志消息的重要程度,从低到高分别为:

  1. DEBUG:最详细的日志级别,通常用于调试目的,记录详细的系统状态信息。对于生产环境,应该将DEBUG日志级别关闭,以避免记录过多的信息。
  2. INFO:用于记录程序的正常操作信息,例如启动信息、关闭信息等。对于生产环境,INFO级别是默认的日志级别,可以提供足够的信息来了解系统的运行情况。
  3. WARNING:警告级别,表示可能出现的问题,但不会影响系统的正常运行。例如,使用了过期的函数或者接口,但是系统仍然能够正常工作。
  4. ERROR:错误级别,表示出现了一些问题,但不会导致系统崩溃。例如,文件无法读取、网络连接失败等。
  5. CRITICAL:最高级别的日志级别,表示严重问题,可能会导致系统崩溃或无法继续运行。例如,关键文件丢失、关键服务停止等。

需要注意的是,logging允许我们自定义日志级别,但是最好不要这样操作,有可能导致日志级别出现混乱,加大维护与管理的难度

日志处理模块的四大组件

  1. Logger(日志器):Logger对象用于创建和记录日志消息。可以通过logging.getLogger(name)方法获取Logger对象,其中name参数为日志器的名称。每个Logger对象都可以设置自己的日志级别和处理器,用于控制日志消息的输出。
  2. Handler(处理器):Handler对象用于将日志消息发送到指定的位置,如控制台、文件、网络等。可以通过logging.StreamHandlerlogging.FileHandler等类创建不同类型的处理器。每个Handler对象都可以设置自己的日志级别和格式,用于控制输出的细节。
  3. Formatter(格式器):Formatter对象用于指定日志消息的输出格式。可以通过logging.Formatter类创建格式化器,并将其应用到Handler对象中。可以自定义输出的格式,包括时间、日志级别、日志名称、日志消息等信息。
  4. Filter(过滤器):Filter对象用于过滤日志消息,只有符合条件的日志消息才会被处理和输出。可以通过继承logging.Filter类创建自定义的过滤器,并将其应用到Logger或Handler对象中。过滤器可以根据日志消息的属性(如级别、名称、消息内容等)进行过滤。

日志器Logger使用案例

日志器的创建

日志器的创建一个是通过其本身的构造器创建,它接收两个参数,一个是日志器名称,一个是日志器最低等级。Logger的构造器中的level参数用于设置日志器的最低级别(或者说最低优先级),低于该级别的日志消息将被忽略。level参数的类型是整数,对应着不同的日志级别,如下所示:

  • logging.DEBUG(整数值为10):调试信息级别,最低的日志级别。
  • logging.INFO(整数值为20):信息消息级别。
  • logging.WARNING(整数值为30):警告消息级别。
  • logging.ERROR(整数值为40):错误消息级别。
  • logging.CRITICAL(整数值为50):严重错误消息级别,最高的日志级别。

通过设置level参数,可以控制日志记录器记录哪些级别以上的日志消息。例如,如果将level参数设置为logging.WARNING,则只有警告级别及以上的日志消息才会被记录,而调试和信息级别的消息将被忽略。

import logginglogging.Logger(name='my_logger', level=logging.DEBUG)

一个是通过getLogger([name])来进行创建,它只接受日志器的名称

import logginglogging.getLogger(name='my_logger')  

注意:在未指定日志级别时,默认为Warning级别日志

日志器的常用方法

方法描述
debug(msg, *args, **kwargs)记录调试级别的日志消息。
info(msg, *args, **kwargs)记录信息级别的日志消息。
warning(msg, *args, **kwargs)记录警告级别的日志消息。
error(msg, *args, **kwargs)记录错误级别的日志消息。
critical(msg, *args, **kwargs)记录严重级别的日志消息。
exception(msg, *args, **kwargs)类似于error()方法,但是会同时记录异常信息。
log(level, msg, *args, **kwargs)记录指定级别的日志消息。
setLevel(level)设置日志记录的最低级别。
addHandler(hdlr)添加日志处理器(handler)到日志器中。
removeHandler(hdlr)从日志器中移除指定的日志处理器。
setFormatter(fmt)设置日志消息的格式化器(formatter)。
hasHandlers()检查日志器是否有任何处理器。

创建并添加日志

import logging# 创建Logger对象
my_logger = logging.getLogger('my_logger')
my_logger.setLevel(logging.DEBUG)# 添加五种不同级别的日志消息
my_logger.debug('This is a DEBUG message')
my_logger.info('This is an INFO message')
my_logger.warning('This is a WARNING message')
my_logger.error('This is an ERROR message')
my_logger.critical('This is a CRITICAL message')

注意:日志器是一个单例模式,在未指定name时,多次处理均为同一个logger对象,要解决这个问题可以运行结束后移除处理器,或者对每次的日志器进行不同的命名(网上看到有人在提,不给过个人觉得一般不会这样写程序)

import loggingdef self_define_log() -> logging.Logger:logger = logging.getLogger()logger.setLevel(logging.DEBUG)console_handler = logging.StreamHandler()console_handler.setLevel(logging.DEBUG)logger.addHandler(console_handler)return loggerif __name__ == "__main__":self_define_log().info('This is an INFO message')self_define_log().debug('This is a DEBUG message')

我们将会得到输出结果:

This is an INFO message
This is a DEBUG message
This is a DEBUG message

日志处理器Handler使用案例

日志处理器需要通过Logger的addHandler方法来进行添加,我们给出常用方法表进行展示:

方法描述
setLevel(level)设置处理器将处理的日志消息的最低级别。
setFormatter(formatter)为处理器设置日志消息的格式化方式。
addFilter(filter)添加过滤器,过滤器可以根据特定的条件决定是否处理日志消息。
removeFilter(filter)移除指定的过滤器。

但是我们使用它的时候实质上使用的是它的子类对象:

子类对象描述
StreamHandler将日志消息输出到流(通常是sys.stdout或sys.stderr)。
FileHandler将日志消息写入到文件中。
RotatingFileHandler将日志消息写入到文件中,并可以在达到一定大小或时间间隔时自动切割文件。
TimedRotatingFileHandler类似于RotatingFileHandler,但是根据时间间隔来切割文件,比如每天、每周或每月。
SocketHandler将日志消息发送到网络套接字。
SMTPHandler将日志消息通过电子邮件发送。
MemoryHandler将日志消息存储在内存中,可以设置当达到一定数量或大小时将日志消息写入到其他处理器(如FileHandler)中。
QueueHandler将日志消息放入队列中,可以与多个处理器共享一个队列,用于实现多线程日志记录。
NullHandler空处理器,用于禁用日志记录。
HTTPHandler将日志消息发送到远程HTTP服务器。

将日志输出到控制台

import logging
import logging.handlerslogger = logging.getLogger('example_logger')
logger.setLevel(logging.DEBUG)stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
logger.addHandler(stream_handler)logger.debug('This is a DEBUG message')
logger.info('This is an INFO message')
logger.warning('This is a WARNING message')
logger.error('This is an ERROR message')
logger.critical('This is a CRITICAL message')

要输出DEBUGINFO级别的日志消息,需要在添加处理程序时将其级别设置为相应的级别。默认情况下,StreamHandler的级别是WARNING,因此它将忽略DEBUGINFO级别的消息。要输出这些级别的消息,需要在创建StreamHandler时将其级别设置为DEBUG或更低级别。

将日志发送到指定服务器

import logging
import logging.handlerslogger = logging.getLogger('example_logger')
logger.setLevel(logging.DEBUG)# 创建HTTPHandler,指定远程HTTP服务器的URL和HTTP方法
http_handler = logging.handlers.HTTPHandler('localhost:8000', '/log', method='POST')
http_handler.setLevel(logging.DEBUG)
logger.addHandler(http_handler)logger.debug('This is a DEBUG message sent via HTTP')
logger.info('This is an INFO message sent via HTTP')
logger.warning('This is a WARNING message sent via HTTP')
logger.error('This is an ERROR message sent via HTTP')
logger.critical('This is a CRITICAL message sent via HTTP')

日志过滤器使用案例

在使用日志过滤器时,我们需要自定义一个Filter类,在该类中重写filter方法,来自定义过滤条件:

  1. 基于Logger名称过滤:可以根据Logger的名称来过滤日志记录,只输出特定名称的Logger的日志记录。
class CustomFilter(logging.Filter):def filter(self, record):return record.name == 'example'filter_instance = CustomFilter()
logger.addFilter(filter_instance)
  1. 基于日志消息内容过滤:可以根据日志消息的内容来过滤日志记录,只输出包含特定内容的日志记录。
class CustomFilter(logging.Filter):def filter(self, record):return 'error' in record.msg.lower()filter_instance = CustomFilter()
logger.addFilter(filter_instance)
  1. 基于创建线程过滤:可以根据其他条件来过滤日志记录,比如根据日志记录的创建时间、线程名等。
class CustomFilter(logging.Filter):def filter(self, record):return record.threadName == 'MainThread'filter_instance = CustomFilter()
logger.addFilter(filter_instance)
  1. 基于日志等级过滤:指定日志的等级条件来过滤日志
class CustomFilter(logging.Filter):def filter(self, record):return record.levelno == logging.INFO
filter_instance = CustomFilter()
logger.addFilter(filter_instance)

日志格式器使用案例

格式器的构造方式

格式器的构造器接受五个参数,依次是输出消息的格式,输出日期时的格式,日志风格字符,另外两个参数是后来新加的:

  • validate:如果为 True,则不正确或不匹配的 fmtstyle 将引发 ValueError。默认为 True。
  • defaults:一个字典,包含在自定义字段中使用的默认值。例如 logging.Formatter('%(ip)s %(message)s', defaults={"ip": None})
def __init__(self, fmt=None, datefmt=None, style='%', validate=True, *,defaults=None):if style not in _STYLES:raise ValueError('Style must be one of: %s' % ','.join(_STYLES.keys()))self._style = _STYLES[style][0](fmt, defaults=defaults)if validate:self._style.validate()self._fmt = self._style._fmtself.datefmt = datefmt

我们来看简单的使用示例:

import logginglogger = logging.getLogger('example')
logger.setLevel(logging.DEBUG)console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
logger.addHandler(console_handler)formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)logger.debug('This is a DEBUG message')
logger.info('This is an INFO message')
logger.warning('This is a WARNING message')
logger.error('This is an ERROR message')
logger.critical('This is a CRITICAL message')

style 参数指定了格式字符串的风格,可以是 %{$ 之一,决定了格式字符串将如何与数据合并。以下是每种风格的用法:

  • %:使用 printf 风格的字符串格式化。例如,logging.Formatter('%(asctime)s - %(message)s')
  • {:使用 str.format()。例如,logging.Formatter('{asctime} - {message}')
  • $:使用 string.Template。例如,logging.Formatter('$asctime - $message')

格式器的内容指定符

格式化字符串描述
%(name)s日志记录器的名称(日志通道)
%(levelno)s消息的数字日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)
%(levelname)s消息的文本日志级别(“DEBUG”、“INFO”、“WARNING”、“ERROR”、“CRITICAL”)
%(pathname)s发出日志调用的源文件的完整路径名(如果可用)
%(filename)s路径名的文件名部分
%(module)s模块(文件名的名称部分)
%(lineno)d发出日志调用的源行号(如果可用)
%(funcName)s函数名
%(created)f创建 LogRecord 的时间(time.time() 的返回值)
%(asctime)sLogRecord 创建时的文本时间
%(msecs)d创建时间的毫秒部分
%(relativeCreated)d创建 LogRecord 时的时间(相对于加载日志模块的时间,通常为应用程序启动时间)的毫秒数
%(thread)d线程 ID(如果可用)
%(threadName)s线程名称(如果可用)
%(process)d进程 ID(如果可用)
%(message)s记录.getMessage() 的结果,即记录被发出时计算的消息内容

日志器统一配置添加

基本参数配置

logging.basicConfig 方法用于配置默认的日志记录器的基本配置,例如日志级别、输出格式和处理程序。如果在应用程序中没有显式配置日志系统,则会使用默认配置。该方法的签名如下:

logging.basicConfig(**kwargs)

参数说明:

  • filename:要将日志消息写入的文件名称。
  • filemode:写入文件时使用的模式,默认为 'a'(追加)。如果指定了 filename,则此参数有效。
  • format:用于设置日志消息的格式。
  • datefmt:用于设置日期/时间部分的格式。
  • level:设置日志记录器的级别。
  • stream:指定一个流(例如 sys.stdoutsys.stderr),用于输出日志消息。如果指定了 filename,则 stream 参数无效。
  • style:设置格式化字符串的风格,默认为 '%'
  • handlers:设置默认的处理器

例如,要将日志消息记录到文件中,并设置日志级别为 DEBUG,可以使用以下代码:

import logginglogging.basicConfig(filename='example_log.log', level=logging.DEBUG)

这将导致日志消息被写入到名为 example.log 的文件中,并且只有 DEBUG 级别或更高级别的消息会被记录。

需要注意的是filenamestream参数不能够同时设置,两者定义的都是输出流,将会引发ValueError

可迭代处理器

logging.basicConfig 方法还可以接受一个 handlers 参数,用于指定要添加到根记录器的处理程序列表。处理程序用于定义将日志消息发送到的位置,例如控制台、文件、网络等。

以下是一个示例,将日志同时输出到控制台和文件中,handlers列表中的参数将依次运行:

import logging# 创建一个日志记录器
logger = logging.getLogger(name='my_logger')
logger.setLevel(logging.DEBUG)# 创建一个控制台处理程序,将日志输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)# 创建一个文件处理程序,将日志写入到文件中
file_handler = logging.FileHandler('example.log')
file_handler.setLevel(logging.DEBUG)# 将处理程序添加到日志记录器中,并进行格式化
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',handlers=[file_handler, console_handler])# 记录日志消息
logger.info('This is an info message')
logger.debug('This is a debug message')
logger.log(level=logging.WARNING, msg='This is a warning message')

这里需要注意的是,写日志的方法也可以脱离Logger对象使用:

logger.info('This is an info message')
logger.debug('This is a debug message')
logger.log(level=logging.WARNING, msg='This is a warning message')

日志模块配置分离

logging.config 模块提供了用于配置 Python 日志系统的功能。它允许您从配置文件、字典或其他来源加载日志配置,并将其应用于日志记录器。

主要的函数和类包括:

  • dictConfig(config):从字典配置日志系统。字典可以包含处理程序、格式化器和日志记录器的配置信息。
  • fileConfig(fname, defaults=None, disable_existing_loggers=True):从配置文件配置日志系统。配置文件的格式可以是 INI 格式或 JSON 格式。
  • listen(port):在给定端口上启动一个网络日志监听器,用于接收远程日志记录请求,但是这个有一定安全风险。
  • stopListening():停止网络日志监听器。
  • threading.Thread(target=handleLogRecords):一个线程类,用于处理接收到的日志记录。

其实我们常用的还是fileConfig,所以这里我也仅介绍此方式

配置日志器config

在编写config文件时,我们默认使用的是ini风格:

[loggers]
keys=root,exampleLogger[logger_root]
level=DEBUG
handlers=consoleHandler[logger_exampleLogger]
level=DEBUG
handlers=consoleHandler
qualname=logger1
propagate=0
  • [loggers]:这个部分定义了所有的logger,并使用keys关键字指定了所有logger的名称。需要注意的是,我们必须定义root日志器,以保证全局配置完整

  • logger_xxx:用于单独配置每个logger

    • level=DEBUG:设置日志级别DEBUG
    • handlers=consoleHandler:指定了处理器为consoleHandler
    • qualname=logger1:指定了logger的名称为logger1。这个名称将在代码中使用,用于获取对应的logger对象。
    • propagate=0:禁止消息传播到父logger。如果不禁用传播,将会在打印日志输出两份相同日志,一个传递到父日志器,一个传递给当前日志器

还有个与propagate相关的属性:parent属性用于指定父日志器,在未声明情况下默认为root日志器

配置处理器config

[handlers]
keys=consoleHandler[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
  • [handlers]:这个部分定义了所有的handlers,并使用keys关键字指定了所有handlers的名称。

  • handlers_xxx:用于单独配置每个handlers

    • class=StreamHandler:设置处理器为StreamHandler
    • level=DEBUG:设置处理器级别DEBUG
    • formatter=simpleFormatter:指定了格式器为simpleFormatter
    • args=(sys.stdout,):指定了处理器的接受参数为(sys.stdout, )元组

配置格式器config

[formatters]
keys=simpleFormatter[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S
style=%

这里就不过多赘述了,只需要注意format控制的是输出msg的格式,datefmt控制的是日期格式,style控制格式风格即可

使用配置文件

import logging
from logging.config import fileConfig# 加载配置文件
fileConfig('config.ini')# 获取名为 'logger1' 的日志记录器
logger1 = logging.getLogger('logger1')
print(logger1.getEffectiveLevel())
logger1.debug('This is a debug message from logger1')
logger1.info('This is an info message from logger1')

需要注意的是,尽管使用了配置文件,但是我们仍然可以获取配置文件以外的日志器,并且这些配置文件外的日志器默认继承配置文件中的root日志器

这篇关于Python编程-使用logging管理程序日志的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/879234

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]