“Python日志记录”的版本间的差异

来自CloudWiki
跳转至: 导航搜索
日志模块记录到文件
打印到控制台
第29行: 第29行:
 
CRITICAL:root:critical message
 
CRITICAL:root:critical message
 
</nowiki>
 
</nowiki>
 
+
第三方士大夫色粉
  
 
===日志模块记录到文件===
 
===日志模块记录到文件===

2021年5月10日 (一) 01:48的版本

日志模块

logging模块

运维工作有很多情况需要查问题、解决bug,而查问题和解决bug的过程离不开查看日志,我们编写脚本或程序时总是需要有日志输出,Python的logging模块就是为记录日志使用的,而且是线程安全的,意味着使用它完全不用担心因日志模块的异常导致程序崩溃。

默认情况下,Python的logging模块将日志打印到标准输出中,而且只显示大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL> ERROR > WARNING > INFO > DEBUG)。默认的日志格式:日志级别为Logger,名称为用户输出消息。

日志级别

各日志级别代表的含义如下。

  • DEBUG:调试时的信息打印。
  • INFO:正常的日志信息记录。
  • WARNING:发生了警告信息,但程序仍能正常工作
  • ERROR:发生了错误,部分功能已不正常。
  • CRITICAL:发生严重错误,程序可能已崩溃。

简单使用

打印到控制台

>>> import logging
>>> logging.debug('ddebug message')
>>> logging.info('info message')
>>> logging.warning('warning')
WARNING:root:warning
>>> logging.error('error message')
ERROR:root:error message
>>> logging.critical('critical message')
CRITICAL:root:critical message

第三方士大夫色粉

日志模块记录到文件

import logging
logging.basicConfig(
     filename="./lx_log1.log",  # 指定文件位置

)
logging.debug("debug message")
logging.info("info message")
logging.warning("warning message")
logging.error("error message")
logging.critical("critical message")

例题:将异常信息写入日志。

import logging
logging.basicConfig(
    filename=r'd:/log1.log'
)
while True:
    try:
    
        s= input("请输入美元数:")
        if s=='q':
            break;
        else:
            s = eval(s)
            r = 6.7*s
            print("换算为人民币为:",r)
            logging.info("info message:换算结果" +str(r))

    except NameError:
        print("用户输入错误")
        logging.error("用户输入错误")

logging.info("循环结束")

实践:程序执行完之后,看看lx_log1.log文件中都发生了什么

思考:为什么info message在文件中没有显示

logging模块的配置与使用

可见在logging.basicConfig()函数中可通过具体参数来更改logging模块的默认行为。

  • filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
  • filemode:文件打开方式,在指定了filename时使用这个参数,默认值为a,还可指定为w。
  • format:指定handler使用的日志显示格式。
  • datefmt:指定日期时间格式。
  • level:设置rootlogger的日志级别。
  • stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。


import logging
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s",  # 日志的格式
    datefmt=" %Y-%m-%d %H:%M:%S",  # 时间格式
    filename="./lx_log1.log",  # 指定文件位置
    filemode="a",
)
logging.debug("debug message")
logging.info("info message")
logging.warning("warning message")
logging.error("error message")
logging.critical("critical message")


例题2:

import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s",  # 日志的格式
    datefmt=" %Y-%m-%d %H:%M:%S",  # 时间格式
    filename="./lx_log1.log",  # 指定文件位置
    filemode="a",
)

while True:
    try:
        num = input("请输入一个整数: ")
        if num == 'q':
            break;
        num = eval(num)
        print(num**2)
        logging.info("info message:input an number" +str(num))
        
    
        
    except NameError:
        print("输入错误,请输入一个整数!")
        logging.error("input message:输入错误,请输入一个整数")

logging.info("end message:退出循环")

日志进阶配置

日志记录器

  • logger:记录器,应用程序代码能直接使用的接口。
  • handler:处理器,将(记录器产生的)日志记录发送至合适的目的地。
  • filter:过滤器,提供了更好的粒度控制,可以决定输出哪些日志记录。
  • formatter:格式化器,指明了最终输出中日志记录的布局。

日志事件信息在记录器(logger)、处理器(handler)、过滤器(filter)、格式化器(formatter)之间通过一个日志记录实例来传递。通过调用记录器实例的方法来记录日志,每一个记录器实例都有一个名字,名字相当于其命名空间,是一个树状结构。

例如,一个记录器叫scan,记录器scan.tex、scan.html、scan.pdf的父节点。记录器的名称。可以任意取,但一个比较好的实践是通过下面的方式来命名一个记录器。

  

import logging

# 创建logger,其名称为simple_example,名称为任意,也可为空
logger = logging.getLogger("lx_log2")
# 打印logger的名称
print(logger.name)
# 设置logger的日志级别
logger.setLevel(logging.INFO)

# 创建两个handler,一个负责将日志输出到终端,一个负责输出到文件,并分别设置他们的日志级别
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
fh = logging.FileHandler(filename="lx_log2.log", mode="a", encoding="utf-8")
fh.setLevel(logging.WARNING)

# 创建一个格式化器,可以创建不同的格式化器用于不同的handler,这里我们使用一个
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

# 设置两个handler的格式化器
ch.setFormatter(formatter)
fh.setFormatter(formatter)

# 为logger添加两个handler
logger.addHandler(ch)
logger.addHandler(fh)

# 在程序中记录日志
logger.debug("debug message")
logger.info("info message")
logger.warning("warn message")
logger.error("error message")
logger.critical("critical message")

例题3:

# -*- coding: utf-8 -*-

import logging

# 创建logger,其名称为simple_example,名称为任意,也可为空
logger = logging.getLogger("lx_log2")
# 打印logger的名称
print(logger.name)
# 设置logger的日志级别
logger.setLevel(logging.INFO)

# 创建两个handler,一个负责将日志输出到终端,一个负责输出到文件,并分别设置他们的日志级别
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
fh = logging.FileHandler(filename="lx_log2.log", mode="a", encoding="utf-8")
fh.setLevel(logging.DEBUG)

# 创建一个格式化器,可以创建不同的格式化器用于不同的handler,这里我们使用一个
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

# 设置两个handler的格式化器
ch.setFormatter(formatter)
fh.setFormatter(formatter)

# 为logger添加两个handler
logger.addHandler(ch)
logger.addHandler(fh)

# 在程序中记录日志
logger.debug("debug message")
logger.info("info message")
logger.warning("warn message")
logger.error("error message")
logger.critical("critical message")

try:
    while(True):
        num = input("请输入一个整数: ")
        if num == 'q':
            break;
        num = eval(num)
        print(num**2)
        logger.info("info message:input an number" +str(num))
        
    logger.info("info message:退出循环")
        
except NameError:
    print("输入错误,请输入一个整数!")
    logger.error("error message:输入错误,请输入一个整数")

基于配置文件的配置

日志的配置信息也可以来源于配置文件:

 import logging
import logging.config

logging.config.fileConfig('logging.conf')

#  创建一个logger
logger = logging.getLogger('simpleExample')

# 日志记录
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

配置文件:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

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

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


运行代码后我们会看到lx_log1.py文件的内容如下:

2018-06-07 21:09:51 lx_log1.py[line:9] DEBUG debug message
2018-06-07 21:09:51 lx_log1.py[line:10] INFO info message
2018-06-07 21:09:51 lx_log1.py[line:11] WARNING warning message
2018-06-07 21:09:51 lx_log1.py[line:12] ERROR error message
2018-06-07 21:09:51 lx_log1.py[line:13] CRITICAL critical message

参考文档:《Python自动化运维》