Python日志模块logging的使用方法总结

目录
  • 导语
  • 关于开发日志
  • 关于logging基础使用
  • 关于logging进阶使用
    • 记录器
    • 处理器
    • 格式器
    • 配置记录
  • 实战
    • 生成记录器
    • 请求处理装饰器
  • 总结

导语

日常开发中,定位程序异常,追溯事件发生场景都需要通过日志记录的方式。可以说一个好的开发日志设计可以让开发人员在后续项目维护的过程中节省时间成本,提升解决问题的效率。

目前在网上已经有许多关于Python日志操作的文章,部分文章总结的非常到位,Python官方也有日志常用的手册。自己写这篇文章是主要围绕Python官方的logging模块展开,结合自己学习过程以及项目开发中应用场景,总结归纳下Python日志使用,方便自己梳理相关知识,更好的理解;

关于开发日志

对于开发日志,很多程序员误区可能就是停留在直接print打印到后台日志中,好的地方方便快捷,但是坏的地方就是日志输出的内容十分混乱,不方便排查。面对不同级别的事件,以及需要执行的任务时,采取的日志操作动作是不一样的。

对此结合Python官方文档总结以下执行任务对应的工具:


需要执行的任务


任务对应的工具


直接打印程序结果


print


记录程序普通操作(比如请求记录,状态监控)


logging.info()


程序发生特殊事件引发的警告信息


logging.warning()


程序发生特殊事件引发错误


直接抛出异常(raise Exception)


报告错误而不引发异常


logging.error()、logging.exception()、logging.critical() 分别使用特定错误

日志功能事件级别对应应用场景(以严重性递增)


级别


应用场景


DEBUG


细节信息,仅当诊断问题适用


INFO


确认程序预期运行,记录程序正常运行状态


WARNING


表明有已经或即将发生的意外


ERROR


由于严重的问题,程序某些功能不能使用


CRTICAL


严重的错误,程序已不能继续执行

logging模块默认级别是WARNING,意味着只会追踪该级别以上的事件,除非更改日志配置;

关于logging基础使用

日志记录保存到文件

import logging
logging.basicConfig(filename="example.log", level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S",
encoding='utf-8')
# 记录日志信息
logging.debug("test DEBUG")
logging.info("test Info")
logging.warning("test Warning")
logging.warning('%s before you %s', 'Look', 'leap!')
logging.error("test Error")

代码注解:

  • 3.9版本中才更新了encoding,encoding参数在更早的Python版本中没有指定时,编码会使用open()的默认值;
  • level是设置默认日志追踪级别的阈值,默认级别是WARNING
  • filename是日志文件的存放路径;

(上述脚本如果连续多次运行,连续运行的消息将追缴到指定的example.log日志文件,如果想每次都是重新开始,即example.log日志不保存之前的日志信息,则修改filemode参数为'w';)

关于logging进阶使用

结合Python官方文档,日志库采用模块化的方法,并提供几类组件:记录器、处理器、过滤器和格式器。

  • 记录器:暴露了应用程序代码直接使用的接口。
  • 处理器:将日志记录(由记录器创建)发送到适当的目标。
  • 过滤器:提供了更细粒度的功能,用于确定要输出的日志记录。
  • 格式器:指定最终输出中日志记录的样式。

官方文档中记录器和处理在日志信息记录流程:

解析:

  • 首先是判断Logger对象执行的方法是否大于设置的最低严重性,大于则创建LogRecord对象,小于则终止;
  • 注册的Filter对象进行过滤,如果为False不记录日志;
  • 将LogRecord对象传递到当前注册到Logger对象中的Handler对象;判断Handler对象设置的级别大于Logger对象则证明有效,以及注册到Handler对象中Filter过滤后是否返回True;
  • 最后判断当前是否还有父Logger对象,如果是重复第三步,知道当前Logger设置为root Looger;

记录器

关于记录器,主要的任务总结有三个:

  • 暴露接口给应用程序记录消息;
  • 根据严重性(默认严重级别)或者过滤器决定要处理的日志信息;
  • 将日志信息发送传递给对应日志处理器;

关于记录器方法总结为两类,配置和消息发送.

记录器配置方法:

  • Logger.setLevel():设置记录器处理的最低严重性日志信息(这就如果后续日志处理器设置的日志级别比记录器低是无效的);
  • Logger.addHandler()和Logger.removeHandler():从记录器对象中增加和删除日志处理器对象;
  • Logger.addFilter()和Logger.removeFilter():从记录器对象中增加和删除过滤器;

记录器常用创建信息方法:

  • Logger.debug() 、 Logger.info() 、 Logger.warning() 、 Logger.error() 和 Logger.critical() ;
  • Logger.exception()和以上的方法有点不同,只在异常处理程序中调用此方法,同时还记录当前堆栈跟踪信息;

处理器

关于处理器,简单的可以理解为将特定严重级别的日志信息发送到特定的位置,常用的处理类型主要有两个:

  • FileHandler
  • StreamHandler

由于内置处理对象常用的配置方法:

  • setLevel()方法,设置处理器中的最低严重性,即决定处理器该发送哪些级别的日志信息;
  • addFormatter,选择该处理器使用的Formatter对象;
  • addFilter和removeFilter,在处理器上增加和删除过滤器对象;

格式器

格式器配置日志消息的最终顺序、结构和内容,格式器类的构造函数有三个可选参数:

  • 消息格式字符串
  • 日期格式字符串
  • 样式指示符

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

备注:

  • fmt消息格式字符串一般不为空,为空默认就只打印message信息;
  • datefmt默认日期格式为:%Y-%m-%d %H:%M:%S;
  • style参数可选的范围为:%、{、$这三个,主要用于fmt消息中字符串替换;

关于style:

fm = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"%Y-%m-%d %H:%M:%S", style='{')
fm = Formatter("{asctime} - {name} - {levelname} - {message}",
"%Y-%m-%d %H:%M:%S", style='{')
fm = Formatter("$asctime - $name - $levelname - $message",
"%Y-%m-%d %H:%M:%S", style='$')

(这三种style使用方式,效果都一样)

配置记录

开发人员可以通过三种方式配置日志记录:

  • 使用提供的接口,显示创建记录器,处理器,格式器等直接配置;
  • 通过fileConfig()函数读取已经创建好的配置文件;
  • 创建好配置函数字典传递到dictConfig()函数;

关于fileConfig()读取的配置文件(官方示例):

[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

(关于读取的配置文件格式类似ini格式)

实战

关于logging模块,这里介绍一下我目前最常用的业务场景:调用方请求一个后端的rest api接口,我需要记录调用方请求的时间,地址,请求参数,处理请求后的结果,以及我需要将报错的信息保存到指定的文件里,方便排查。

为了后期使用方便,在不更改原有处理函数的基础下增加日志记录的功能,我会选择将日志记录操作封装在一个装饰器函数。

所以我只需将这部分功能分成两部分:生成记录器、请求处理的装饰器函数

生成记录器

# -*- coding: utf-8 -*-
from logging import handlers
from datetime import date
import logging
def init_logger():
"""
生成记录器
:return:
"""
app_logger = logging.getLogger(APP_NAME)
app_logger.setLevel(logging.INFO)
fmt = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S")
# 正常日志打印到控制台
console = logging.StreamHandler()
console.setFormatter(fmt)
console.setLevel(logging.INFO)
# 异常日志记录到log文件
today = date.today()
file_name = "logs/exceptions_" + str(today) + ".log"
fh = handlers.TimedRotatingFileHandler(filename=file_name, when='D', backupCount=30, encoding='utf-8')
fh.setLevel("ERROR")
fh.setFormatter(fmt)
app_logger.addHandler(console)
app_logger.addHandler(fh)
return app_logger

代码解析:

  • APP_NAME是预设好的项目名称,可根据实际业务进行调整;
  • 关于普通的StreamHandler前面已经提到了使用的方法,我这里之所选择,是由于这个项目时Flask框架,后期部署通过uWSGI部署后端服务,我希望正常请求直接就打印在uwsgi的日志文件中,所以普通请求的处理器就选择了StreamHandler
  • 关于异常日志处理器,这里用到特殊的TimeRotatingFileHandler,这个内置的处理器可以根据不同的时间跨度进行保存日志,就可以将异常日志信息按照一天的时间进行保存,注意设置最低严重性是ERROR

请求处理装饰器

from functools import wraps
from flask import request
app_logger = init_logger()
def rest_log(return_type="dict"):
def decorator(func):
@wraps(func)
def inner(*args, **kwargs):
# 组装打印的Message消息日志格式(请求URL,目标主机,请求方法,请求参数,响应内容)
log_params = {
"request": request.base_url,
"host": request.host,
"method": request.method
}
req_data = {}
if request.method == "POST":
req_data = dict(request.json)
elif request.method == "GET":
req_data = dict(request.args)
log_params.update({"params": req_data})
# 请求处理函数
try:
result = func(*args, **kwargs)
except Exception as e:
# 异常信息处理
err_msg = str(e)
result = {"ret_code": 500, "ret_info": err_msg}
app_logger.error(log_params, exc_info=True)
if return_type == "tuple":
result = (result, 500)
if return_type == "tuple":
log_params['result'] = result[0].data
else:
log_params['result'] = result
app_logger.info(log_params)
return result
return inner
return decorator

代码解析:

  • 主要分为三部分:HTTP请求request解析、异常请求信息处理、请求结果处理;
  • app_logger.error(log_params, exc_info=True)中的exc_info可以将异常信息添加到日志信息中,即app_logger.exception()的效果;
  • 关于return_type参数是考虑到flask支持返回元组,即返回响应对象,响应状态码。考虑到日常使用场景会出现这种情况;

简单使用示例:

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

from flask import request, Blueprint
from common.LogUtils import rest_log
test_api = Blueprint("TestApi", __name__)
@test_api.route("/log/test", methods=["GET"])
@rest_log()
def test_log():
name = request.args.get("name", "")
number = request.args.get('number', "")

if not name or not number:
raise Exception("number和name参数都不能为空")

response = {
"data": {
"name": f"Hello, {name}",
"number": number
},
"ret_code": 200,
"ret_info": "success"
}
return response

备注:

  • rest_log装饰器不能放在test_api.route的前面,因为只有当路由注册函数执行后,才能从request中获取到对应的信息(base_url,host,method)

控制台日志打印效果:

2022-05-22 12:01:01 INFO: {'request': 'http://127.0.0.1:23102/log/test', 'host': '127.0.0.1:23102', 'method': 'GET', 'params': {'name': 'zhangsn', 'number': '22'}, 'result': {'data': {'name': 'Hello, zhangsn', 'number': '22'}, 'ret_code': 200, 'ret_info': 'success'}}

异常日志打印:

2022-05-22 11:47:38 ERROR: {'request': 'http://127.0.0.1:23102/log/test', 'host': '127.0.0.1:23102', 'method': 'GET', 'params': {}}
Traceback (most recent call last):
File "C:\Users\admin\TestLogging\common\LogUtils.py", line 63, in inner
result = func(*args, **kwargs)
File "C:\Users\admin\TestLogging\controller\TestLogging.py", line 18, in test_log
raise Exception("number和name参数都不能为空")
Exception: number和name参数都不能为空

总结

以上就是关于logging日志模块的初步使用总结,后续如果在日常工作的场景中遇到什么坑,也会继续更新,欢迎大家的讨论和建议!

到此这篇关于Python日志模块logging的使用方法总结的文章就介绍到这了,更多相关 Python日志模块 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python 日志模块logging的使用场景及示例

    前言 日志是对于软件执行所发生的事件的一种追踪记录方式.日常使用过程中对代码执行的错误和问题会进行查看日志来分析定位问题所在.平常编写代码以及调试也经常用到.通常的新手的做法是直接print打印,但是打印的结果只在控制台显示.今天我们学习一种高级的日志打印和记录模块logging. logging提供了一系列的函数,它们是debug(), info(), warning(), error(), 和critical(). 他们的使用场景请看下表 你想要执行的任务 此任务的最好的工具 对于命令行或程

  • Python中的logging模块实现日志打印

    目录 方法1:配置并输出日志到标准输出 方法2:配置输出到日志文件 前言: 大家在写代码的时候,经常会使用print打印日志方便排查问题,然而print的问题就是太过简单,缺少时间.日志级别等格式化信息. Python自带的logging模块,很简单就能实现日志的配置和打印,它有两种用法,方法1是把日志输出到标准输出,其实就是命令行界面,方法2则是输出日志到文件,更加方便. 方法1:配置并输出日志到标准输出 import logging   LOG_FORMAT = "%(asctime)s -

  • 详解 python logging日志模块

    目录 1.日志简介 2.日志级别 3.修改日志级别 4.日志记录到文件 5.指定日志格式 6.记录器(logger) 7.处理器(Handler) 8.处理器操作 9.格式器(formatter) 10.logging.basicConfig 11.日志配置 转自微信公众号: Python之禅 1.日志简介 说到日志,无论是写框架代码还是业务代码,都离不开日志的记录,他能给我们定位问题带来极大的帮助. 记录日志最简单的方法就是在你想要记录的地方加上一句 print , 我相信无论是新手还是老鸟都

  • 如何理解python接口自动化之logging日志模块

    一.logging模块介绍 ​前言:我们之前运行代码时都是将日志直接输出到控制台,而实际项目中常常需要把日志存储到文件,便于查阅,如运行时间.描述信息以及错误或者异常发生时候的特定上下文信息. ​Python中自带的logging模块提供了标准的日志接口,在debug时使用往往会事半功倍.为什么不直接使用print去输出呢?这种方式对简单的脚本来说有用,对于复杂的系统来说相当于一个花瓶摆设,大量的print输出很容易被遗忘在代码里,并且print是标准输出,这很难从一堆信息里去判断哪些是你需要重

  • Python logging日志模块 配置文件方式

    在一些微服务或web服务中我们难免需要日志功能,用来记录一些用户的登录记录,操作记录,以及一些程序的崩溃定位,执行访问定位等等; Python内置 非常强大的日志模块 ==> logging 今天给大家分享一下以配置文件形式进行配置log日志 ; Centos6.7 Python3.6 logging0.5.1.2 logging模块有三个比较重要的功能组件: 1.loggers 配置文件可定义一些输出日志的appname 2.handler 过滤器,比如设置日志的分隔大小,输出位置,日志文件创

  • Python接口自动化浅析logging日志原理及模块操作流程

    目录 一.日志介绍 01 为什么需要日志? 02 什么是日志? 03 日志的用途是什么? 04 日志的级别分为哪些? 05 日志功能的实现 二.Logging模块 01 logging模块介绍 02 logging模块优势 03 logging日志框架的组成 04 logging函数中的具体参数 05 简单的日志小例子 06 自定义logger日志 在上一篇Python接口自动化测试系列文章:Python接口自动化浅析pymysql数据库操作流程,主要介绍pymysql安装.操作流程.语法基础及

  • Python日志模块logging的使用方法总结

    目录 导语 关于开发日志 关于logging基础使用 关于logging进阶使用 记录器 处理器 格式器 配置记录 实战 生成记录器 请求处理装饰器 总结 导语 日常开发中,定位程序异常,追溯事件发生场景都需要通过日志记录的方式.可以说一个好的开发日志设计可以让开发人员在后续项目维护的过程中节省时间成本,提升解决问题的效率. 目前在网上已经有许多关于Python日志操作的文章,部分文章总结的非常到位,Python官方也有日志常用的手册.自己写这篇文章是主要围绕Python官方的logging模块

  • Python日志模块logging基本用法分析

    本文实例讲述了Python日志模块logging基本用法.分享给大家供大家参考,具体如下: 1. 基础用法 python提供了一个标准的日志接口,就是logging模块.日志级别有DEBUG.INFO.WARNING.ERROR.CRITICAL五种(级别依次升高),分别对应的函数为debug().info().warning().error().critical(). >>> import logging >>> logging.debug("ni hao&

  • Python日志模块logging用法

    一.概述 步骤 创建logger对象 创建handler对象 创建formatter对象 把formatter绑定到handler对象上 把handler对象绑定到logger对象上 设置级别 测试 二.低配logging 日志总共分为以下五个级别,这个五个级别自下而上进行匹配 debug-->info-->warning-->error-->critical,默认最低级别为warning级别. critical=50.error =40 .arning =30.info = 20

  • python标准日志模块logging的使用方法

    最近写一个爬虫系统,需要用到python的日志记录模块,于是便学习了一下.python的标准库里的日志系统从Python2.3开始支持.只要import logging这个模块即可使用.如果你想开发一个日志系统, 既要把日志输出到控制台, 还要写入日志文件,只要这样使用: 复制代码 代码如下: import logging# 创建一个loggerlogger = logging.getLogger('mylogger')logger.setLevel(logging.DEBUG)# 创建一个ha

  • Python日志模块logging简介

    logging分为4个模块: loggers, handlers, filters, and formatters. ●loggers: 提供应用程序调用的接口 ●handlers: 把日志发送到指定的位置 ●filters: 过滤日志信息 ●formatters: 格式化输出日志 Logger Logger.setLevel() 设置日志级别 Logger.addHandler()和Logger.removeHandler() 增加和删除日志处理器 Logger.addFilter()和Log

  • python日志模块logbook使用方法

    python自带了日志模块logging,可以用来记录程序运行过程中的日志信息.同时python还有logbook模块用来取代logging模块,在很多的项目中logbook模块使用也是比较的多,因此本文介绍一下python logbook模块的使用方法. 1,安装 pip install logbook 官方的使用文档,这里 2,使用方法如下: 文件 logconf.py 初始化日志以及设置日志格式等参数: import sys import os import logbook import

  • Python常用模块logging——日志输出功能(示例代码)

    用途 logging模块是Python的内置模块,主要用于输出运行日志,可以灵活配置输出日志的各项信息. 基本使用方法 logging.basicConfig(level=logging.DEBUG, format='levelname:%(levelname)s filename: %(filename)s ' 'outputNumber: [%(lineno)d] thread: %(threadName)s output msg: %(message)s' ' - %(asctime)s'

  • python日志模块loguru详解

    目录 前言 使用步骤 安装库 简单使用方法 配置 异常追溯 总结 前言 在部署一些定时运行或者长期运行的任务时,为了留存一些导致程序出现异常或错误的信息,通常会才用日志的方式来进行记录这些信息.python内置的logging标准库博主是没用过,今天给大家介绍loguru,loguru 库的使用可以说是十分简单,希望通过本文大家再也不用通过print来排查代码了. 使用步骤 安装库 pip install loguru 简单使用方法 from loguru import logger logge

  • 2022最新Python日志库logging总结

    目录 1.日志级别 2.logging 流程 3.日志输出格式 4.基本使用 5.自定义 Logger 6.Logger 配置 7.实战中的问题 在部署项目时,不可能直接将所有的信息都输出到控制台中,我们可以将这些信息记录到日志文件中,这样不仅方便我们查看程序运行时的情况,也可以在项目出现故障时根据运行时产生的日志快速定位问题出现的位置. 1.日志级别 Python 标准库 logging 用作记录日志,默认分为六种日志级别(括号为级别对应的数值),NOTSET(0).DEBUG(10).INF

随机推荐