python-logging.config【日志模块】

本文详细介绍Python的logging模块,包括其核心组件logger、handler、filter和formatter的作用与使用方法。通过多个示例程序展示了如何配置日志级别、输出格式以及如何通过配置文件管理日志。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,logging模块简介

 Python的logging模块提供了通用的日志系统,熟练使用longgong模块可以方便开发者开发第三方模块或者是自己的Python应用。同样这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP、GET/POST,SMTP,Socket等,甚至可以自己实现具体的日志记录方式。下文我将主要介绍如何使用文件方式记录log

        logging模块包括loggerhandlerfilterformatter这四个基本概念。
        logger提供日志接口,供应用代码使用。logger最长用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
        handler将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。Handler 是处理器, 可以把log记录到文件系统中, 输出到终端设备, 或者网络sockt或者邮件等。
StreamHandler
FileHandler
RotatingFileHandler
TimedRotatingFileHandler
SocketHandler
DatagramHandler
SysLogHandler
NTEventLogHandler
SMTPHandler
MemoryHandler
HTTPHandler

        filter提供一种优雅的方式决定一个日志记录是否发送到handler。

        formatter指定日志记录输出的具体格式。使用这个可以更容易的根据错误检错。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。

%(name)s            Name of the logger (logging channel)
%(levelno)s         Numeric logging level for the message (DEBUG, INFO,
                    WARNING, ERROR, CRITICAL)
%(levelname)s       Text logging level for the message ("DEBUG", "INFO",
                    "WARNING", "ERROR", "CRITICAL")
%(pathname)s        Full pathname of the source file where the logging
                    call was issued (if available)
%(filename)s        Filename portion of pathname
%(module)s          Module (name portion of filename)
%(lineno)d          Source line number where the logging call was issued
                    (if available)
%(created)f         Time when the LogRecord was created (time.time()
                    return value)
%(asctime)s         Textual time when the LogRecord was created
%(msecs)d           Millisecond portion of the creation time
%(relativeCreated)d Time in milliseconds when the LogRecord was created,
                    relative to the time the logging module was loaded
                    (typically at application startup time)
%(thread)d          Thread ID (if available)
%(process)d         Process ID (if available)
%(message)s         The result of record.getMessage(), computed just as
                    the record is emitted

2,基本方法

事实上,不管用最简单的logging模块的basicConfig函数,还是用配置文件形式,只要log文件一样,不过多少程序,都会以增加的方式往里写。

2.1,程序1

一些小型的程序我们不需要构造太复杂的log系统,可以直接使用logging模块的basicConfig函数即可,代码如下:

#test.py
import logging
LOG_FILENAME="./mylog.log"
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
logging.debug("this is a debugmsg!")  
logging.info("this is a infomsg!")  
logging.warn("this is a warn msg!")  
logging.error("this is a error msg!")  
logging.critical("this is a critical msg!") 
这样会生成一个mylog.log的日志文件,每运行一次,里面都增加如下内容:

DEBUG:root:this is a debugmsg!
INFO:root:this is a infomsg!
WARNING:root:this is a warn msg!
ERROR:root:this is a error msg!
CRITICAL:root:this is a critical msg!

需要说明的是我将level设定为DEBUG级别,所以log日志中只显示了包含该级别及该级别以上的log信息。信息级别依次是:notset、debug、info、warn、error、critical。如果在多个模块中使用这个配置的话,只需在主模块中配置即可,其他模块会有相同的使用效果。

2.2,程序2

上述的基础配置比较简单,下面我们看一个更标准的程序,我们需要依次设置logger、handler、formatter等配置。

# -* - coding: UTF-8 -* - 
import logging  
  
log_file = "./nomal_logger.log"  
log_level = logging.DEBUG  


#建立【logger】
#logger = logging.getLogger()
logger = logging.getLogger("loggingmodule.NomalLogger")  
logger.setLevel(log_level) 


#建立【文件句柄】和【流句柄】并分别设置级别
filehandler = logging.FileHandler(log_file)  
filehandler.setLevel(logging.ERROR)
streamhandler = logging.StreamHandler()
streamhandler.setLevel(logging.ERROR)
#建立【格式串】
formatter = logging.Formatter("[%(levelname)s][%(funcName)s][%(asctime)s]%(message)s")   
#【文件句柄】和【流句柄】使用【格式串】  
filehandler.setFormatter(formatter)  
streamhandler.setFormatter(formatter)
#【logger】连接【句柄】
logger.addHandler(filehandler)  
logger.addHandler(streamhandler) 
   
#test  
logger.debug("this is a debug msg!")  
logger.info("this is a info msg!")  
logger.warn("this is a warn msg!")
logger.error("this is a error msg!")
logger.critical("this is a error msg!")  
这样会生成一个Log_test.txt的日志文件,每运行一次,里面都增加2行:
[ERROR][<module>][2012-09-04 22:41:19,546]this is a error msg!
[CRITICAL][<module>][2012-09-04 22:41:19,562]this is a error msg!
上面程序首先生成一个日志对象logger,用它来控制日志的输入。然后生成了一个handler,logging支持很多种Handler,像FileHandler,SocketHandler等待,这里由于我们要写文件,所以用了FileHandler,它的参数就是filename,默认当前路径,当然我们可以自己指定路径。后面还设置日志信息输出的级别。

2.3,程序3

可以用“python test.py debug”的方式来控制输入级别,代码如下:

#test.py
import logging
import sys
LEVELS={'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARNING,
        'error':logging.ERROR,
        'critical':logging.CRITICAL}

if len(sys.argv)>1:
        level_name=sys.argv[1]
        level=LEVELS.get(level_name,logging.NOTSET)
        logging.basicConfig(level=level)

        logging.debug("This is a debug message")
        logging.info("This is an info message")
        logging.warning("This is a warning message")
        logging.error("This is an error message")


2.4,程序4

使用配置文件形式:Python的logging.config.

Python的logging模块接口仿log4j,概念上一致,使用上相当方便。利用logging.config.fileConfig(),可以将日志的配置用文件来描述,简化了日志的初始化。


例程:
# test.py
import logging
import logging.config

logging.config.fileConfig(
"logging.conf")

#create logger
logger = logging.getLogger("example")

#"application" code
logger.debug("debug message")
logger.info(
"info message")
logger.warn(
"warn message")
logger.error(
"error message")
logger.critical(
"critical message")

logHello 
= logging.getLogger("hello")
logHello.info(
"Hello world!")



配置文件示例如下:
# logging.conf

[loggers]
keys
=root,example

[handlers]
keys
=consoleHandler,rotateFileHandler

[formatters]
keys
=simpleFormatter

[formatter_simpleFormatter]
format
=[%(asctime)s](%(levelname)s)%(name)s : %(message)s

[logger_root]
level
=DEBUG
handlers
=consoleHandler,rotateFileHandler

[logger_example]
level
=DEBUG
handlers
=consoleHandler,rotateFileHandler
qualname
=example
propagate
=0

[handler_consoleHandler]
class
=StreamHandler
level
=DEBUG
formatter
=simpleFormatter
args
=(sys.stdout,)

[handler_rotateFileHandler]
class
=handlers.RotatingFileHandler
level
=DEBUG
formatter
=simpleFormatter
args
=('test.log', 'a', 200000, 9)



这样,会生成test.log.


2.5,程序5【多文件共用一个log文件】

这里叙述的是我工作中遇到的问题,需要将多个文件的log信息输入到一个文件中去。我的理解是,在A文件中设置了譬如log文件位置、log文件名字、格式化信息等等,然后在A文件末尾可能用os.system("python B.py")这样又调用了B文件,那么在B文件中要也输出到之前指定的那个log文件,必须重新设置一遍刚才的log信息。这是因为,os.system()相当于系统调用了。与import不一样,import可以理解为将代码插到这个位置。

A.py

import os,sys,time

def xixi():
    gLogger.info("xixi")

def mylog():
    import logging.config
    gLogger = logging.getLogger()
    logdir = "log/"
    logfile = "verify.log"
    os.system("mkdir -p " + logdir)
    log_file = "./%s/%s"%(logdir,logfile)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.handlers.RotatingFileHandler(log_file)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    gLogger.setLevel(logging.INFO)
    return gLogger

if __name__ == "__main__":
    gLogger = mylog()
    xixi()
    gLogger.info("A.py")
    os.system("python B.py")

B.py

import os,sys,time
import logging.config

gLogger = logging.getLogger()
logdir = "log/"
logfile = "verify.log"
os.system("mkdir -p " + logdir)
log_file = "./%s/%s"%(logdir,logfile)
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
gLogger.addHandler(handler)
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
handler = logging.handlers.RotatingFileHandler(log_file)
handler.setFormatter(formatter)
gLogger.addHandler(handler)
gLogger.setLevel(logging.INFO)

gLogger.info("B1.py")
if __name__ == "__main__":
    gLogger.info("B2.py")

命令

[admin@r42h06016.xy2.aliyun.com]$python A.py

输出

[2012-09-18 23:13:28,301][INFO] xixi
[2012-09-18 23:13:28,301][INFO] A.py
[2012-09-18 23:13:28,344][INFO] B1.py
[2012-09-18 23:13:28,344][INFO] B2.py
分析

首先,python A.py 这时,运行到main,调用函数mylog初始化log信息。这时可以用gLogger来输出信息。调用xixi,之所以可以用,因为函数相当于将代码贴过来,这时gLogger已经定义过了。然后再输出A.py的信息。然后系统调用B,B已经事先初始化了。这时gLogger必然处处可用。

2.6 我的习惯

我一般是将logging等相关内容写在一个文件里,如下所示:

module_mylog.py

import os,sys
def mylog():
    import logging.config
    gLogger = logging.getLogger()
    logdir = "log/"
    logfile = "load.log"
    os.system("mkdir -p " + logdir)
    log_file = "./%s/%s"%(logdir,logfile)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
    handler = logging.handlers.RotatingFileHandler(log_file)
    handler.setFormatter(formatter)
    gLogger.addHandler(handler)
    gLogger.setLevel(logging.INFO)
    return gLogger
gLogger = mylog()
其他任何文件要公用这个log时,都只需import就可以:

A.py

from module_myverifylog import gLogger

if __name__ == "__main__":
    gLogger.info("A.py")

B.py

from module_myverifylog import gLogger

if __name__ == "__main__":
    gLogger.info("B.py")

不用担心其他文件都import它都会重新运行,实际上只会运行一次,这是当做全局变量来做的。这样A.py和B.py的log都会在一个日志里了。

### Python `logging.config` 使用方法及配置示例 #### fileConfig 方法简介 通过 `fileConfig()` 可以从外部配置文件加载日志设置。此方法接受两个主要参数:一个是配置文件路径,另一个是可选的关键字参数,默认值通常不需要更改[^2]。 ```python import logging.config # 加载配置文件并初始化日志记录器 logging.config.fileConfig('logging.ini') logger = logging.getLogger('root') # 记录一条消息 logger.info("This is an info message.") ``` 这种方法适合于希望将日志配置分离到独立文件中的场景,便于管理和维护不同环境下的日志级别、格式化样式等属性[^4]。 #### dictConfig 方法详解 对于更复杂的配置需求,则可以采用基于字典对象的方式来进行配置——即 `dictConfig()` 函数。它允许开发者直接在代码内部构建完整的日志系统结构描述,并传递给该函数来应用这些设定[^1]。 下面是一个简单的例子展示如何利用 YAML 文件作为源数据并通过 Python 的 `yaml` 库解析成字典再传入 `dictConfig()`: ```python import logging.config import yaml import os class Logger(): def __init__(self, logger_name=''): self.logger_name = logger_name cur_dir = os.path.dirname(__file__) log_conf_path = os.path.join(cur_dir, 'logconf', 'trflog.yaml') with open(log_conf_path, 'r', encoding="utf8") as f: config_dict = yaml.safe_load(f.read()) # 初始化日志配置 logging.config.dictConfig(config_dict) def get_logger(self): return logging.getLogger(self.logger_name) if __name__ == "__main__": my_logger = Logger().get_logger() my_logger.error("An error occurred!") ``` 这段代码展示了怎样封装一个类用于管理多个模块共享的日志实例,同时也体现了灵活调整日志行为的能力[^3]。 #### 日志配置建议 为了确保项目中所有组件都能正确访问所需的日志设施,在应用程序启动阶段尽早执行一次全局性的日志初始化操作是非常重要的。特别是当使用相对路径指定日志输出位置时,这一点尤为重要,因为它能防止因工作目录变化而导致错误的日志存储地点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值