python logging模块

logging模块使用场景

print已经无法满足需求
大型项目需要更详细的输出,便于排错
在java中类似log4j

程序开发的基本流程

  1. 画图, 把程序的基本模块和流程图画清楚
  2. 写程序前先写注释, 每一步要干的事
  3. 写代码

最好在调用一个函数或方法时

def fun(*args):
	logging("函数名start-功能-传入参数args")
	...
	logging("函数名end-返回值")
	return 返回值

可直接复制的代码

在同一个Python进程中

日志输出到同一个文件

下面这个函数可以写在工具模块中, 按需导入即可

def getLogger_file_1(logfile="", mode="w", log_level=20):
    """
    将所有日志输出到一个文件
    :param logfile: log文件地址, 不传入logfile就是当前'文件名.log'
    :param mode: 写入log文件的模式, w 或 a
    :param log_level: 默认info:20; debug:10,warning:30,error:40,critical:50
    :return: logger
    """
    import logging
    fmt_str = "%(asctime)s %(filename)s %(funcName)s:%(lineno)d %(levelname)s-->%(message)s"
    if logfile == "":
        logfile = __file__ + ".log"
    logging.basicConfig(level=log_level,
                        format=fmt_str,
                        datefmt='%a, %d %b %Y %H:%M:%S',
                        filename=logfile,
                        filemode=mode
                        )
    logging.FileHandler(filename=logfile, encoding="utf-8")  # 防止乱码

    return logging


日志输出到不同的文件

在同一个Python进程中

不同模块的logging输出到不同的日志文件

注意: 在每个需要写日志的模块中都需要这样的一个函数

def getLogger_file_2(logfile="", mode="w", log_level=20):
    """
    获取日志记录器,注意在每个模块下都要有这个方法
    :param logfile: log文件地址,不传入logfile就是当前'文件名.log'
    :param mode: 写入log文件的模式, w 或 a
    :param log_level: 默认info:20; debug:10,warning:30,error:40,critical:50
    :return: logger
    """
    import logging
    # ####### 1. 创建日志器
    # logging使用的是单例模式,同一python进程不同模块import的logging,如果没有特殊标识,调用的都是同一个logger
    logger = logging.getLogger(__name__)  # 可以使用__name__变量标识
    logger.setLevel(level=log_level)  # INFO: 20
    # ####### 2. 定义处理器, 控制台和文本
    if logfile == "":
        logfile = __file__ + ".log"
    file_handler = logging.FileHandler(logfile, mode=mode)  # 输出到文件
    logger.addHandler(file_handler)
    # ####### 3. 自定义日志输出格式
    fmt = logging.Formatter("%(asctime)s %(filename)s %(funcName)s:%(lineno)d %(levelname)s-->%(message)s")
    file_handler.setFormatter(fmt)
    return logger

logging日志级别

在这里插入图片描述

# 基本使用
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(name)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='/tmp/alert_phone_server.log',
                    filemode='w'
                    )               
logging.info("logging test")

参数

  • level 告警级别
  • format 输出格式
  • datefmt 时间格式
  • filename 日志文件
  • filemode 打开日志文件的模式 w 或 a

日志同时生成在控制台和文件

# -*- encoding: utf-8 -*-
"""
@Modify Time      @Author    @Version    @Description
------------      -------    --------    -----------
2021/9/4 8:41   xlgui      1.0          logging模块学习,日志同时输出在控制台和文件
"""
import logging
# ####### 1. 创建日志器
logger = logging.getLogger(__name__)  # 参数为空, 默认为root; 即 %(name)s 的值
logger.setLevel(20)  # INFO: 20
# ####### 2. 定义处理器, 控制台和文本
stream_handler = logging.StreamHandler()  # 输出到控制台的流
file_handler = logging.FileHandler("test_logging.log", mode='w')  # 输出到文件

# 还可以自定义输出到不同地方的日志格式
fmt1 = logging.Formatter(fmt="%(name)s - %(levelname)s - %(pathname)s --> %(message)s")  # 要查看可以自定义的日志格式, 可以ctrl+左击Formatter
fmt2 = logging.Formatter(fmt="%(filename)s -%(module)s - %(lineno)d -%(funcName)s -%(asctime)s -->%(message)s ")
"""
%(name)s 是 logging.getLogger(__name__) 中的__name__
%(levelname)s 日志输出等级
%(pathname)s  脚本的绝对路径
%(filename)s  脚本名
%(module)s  模块名
%(lineno)d  行号
%(funcName)s  函数名
%(message)s  日志
%(asctime)s  时间
%(thread)d          Thread ID (if available)
%(threadName)s      Thread name (if available)
%(process)d         Process ID (if available)
"""

fmt_str = "[%(asctime)s] %(filename)s %(funcName)s:%(lineno)d %(levelname)s-->%(message)s"
fmt = logging.Formatter(fmt_str)

stream_handler.setFormatter(fmt)
file_handler.setFormatter(fmt2)

logger.addHandler(stream_handler)
logger.addHandler(file_handler)


def test_func(t):
    logger.info("test_func-start")
    print(t)
    import time
    time.sleep(2)
    logger.info("test_func-end, return None")


if __name__ == '__main__':
    test_func("tttt")

高级应用

在这里插入图片描述

Handlers 处理器

在这里插入图片描述
在这里插入图片描述

滚动日志

可以使用logging.handlers模块来实现日志滚动。logging.handlers模块提供了一些预定义的日志处理器,包括支持滚动的处理器。

以下是一个示例,演示如何配置基于时间的日志滚动:

import logging
from logging.handlers import TimedRotatingFileHandler

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# 配置日志滚动处理器
handler = TimedRotatingFileHandler('app.log', when='midnight', interval=1, backupCount=7)
handler.suffix = "%Y-%m-%d_%H-%M-%S.log"  # 自定义日志文件后缀格式
handler.setLevel(logging.INFO)

# 配置日志格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

# 添加处理器到日志记录器
logger.addHandler(handler)

# 打印日志
logger.info('这是一条信息日志')
logger.warning('这是一条警告日志')
logger.error('这是一条错误日志')

在上述代码中,我们首先创建了一个名为logger的日志记录器,并将其日志级别设置为logging.INFO以仅记录INFO级别及以上的日志。

然后,我们使用TimedRotatingFileHandler创建一个基于时间的日志滚动处理器。在这个示例中,我们设置滚动的时间间隔为每天(when=‘midnight’),并保留7个备份文件。我们还使用suffix属性自定义了日志文件的后缀格式,以便按时间戳对日志文件进行命名。

然后,我们配置了日志格式,并将处理器添加到日志记录器中。

运行以上示例代码后,每天午夜时,日志文件将被滚动并备份,按照指定的命名格式创建新的日志文件。

除了基于时间的滚动,logging.handlers模块还提供了其他类型的滚动处理器,

  • 基于文件大小的滚动(RotatingFileHandler)
  • 根据日志条数滚动(MemoryHandler)

多进程下

需要为process设置name

multiprocessing.Process(target=f, name=p1_name)

日志

import logging
import multiprocessing
from logging.handlers import TimedRotatingFileHandler
import os

log_lock = multiprocessing.Lock()
_log_dict = dict()

log_dir = "logs"


def info(msg):
    msg = str(msg)
    with log_lock:
        name = f"{multiprocessing.current_process().name}"
        if name in _log_dict:
            logger = _log_dict[name]
        else:
            logger = logging.getLogger(name)
            logger.setLevel(logging.INFO)
            log_file = f'{log_dir}/{name}.info'
            handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=30, encoding='utf-8')
            handler.suffix = '%Y-%m-%d'
            logger.addHandler(handler)
            formatter = logging.Formatter('%(asctime)s - %(message)s')
            handler.setFormatter(formatter)
            _log_dict[name] = logger
        logger.info(msg)


def log_error(err):
    msg = str(err)
    with log_lock:
        name = f"ERROR.{multiprocessing.current_process().name}"
        if name in _log_dict:
            logger = _log_dict[name]
        else:
            logger = logging.getLogger(name)
            logger.setLevel(logging.INFO)
            log_file = f'{log_dir}/{name}.err'
            handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=30, encoding='utf-8')
            handler.suffix = '%Y-%m-%d'
            logger.addHandler(handler)
            formatter = logging.Formatter('%(asctime)s - %(message)s')
            handler.setFormatter(formatter)
            _log_dict[name] = logger
        logger.info(msg)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python中的logging模块提供了一种灵活且可配置的方式来记录信息。通过使用不同的handler、formatter和logger对象的组合,可以控制日志消息的输出方式、输出位置和格式。使用logging模块可以在代码中记录各种级别的消息,例如调试信息、警告、错误和致命错误。下面是一个简单的例子: ```python import logging # 创建一个logger logger = logging.getLogger('my_logger') logger.setLevel(logging.DEBUG) # 创建一个文件handler,用于写入日志文件 fh = logging.FileHandler('mylog.log') fh.setLevel(logging.DEBUG) # 创建一个控制台handler,用于输出到控制台 ch = logging.StreamHandler() ch.setLevel(logging.ERROR) # 定义日志输出格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) # 将handler添加到logger中 logger.addHandler(fh) logger.addHandler(ch) # 记录日志 logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message') ``` 上面的代码创建了一个logger对象,并添加了一个文件handler和一个控制台handler。文件handler会将日志信息写入到指定的文件中,控制台handler会将错误级别以上的日志信息输出到控制台。该例子还定义了日志信息的格式,最后通过调用logger对象的各个方法来记录不同级别的日志信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值