Python logging模块切分和轮转日志

 2023-09-07 阅读 22 评论 0

摘要:Python logging模块切分和轮转日志 logging 模块可以实现日志的输出和写入文件,但实际工作中,对于日志是使用不仅限于输出那么简单。 logging基本使用参考:https://blog.csdn.net/weixin_43790276/article/details/99617949 logging 模块中实现了很多日志

Python logging模块切分和轮转日志

logging 模块可以实现日志的输出和写入文件,但实际工作中,对于日志是使用不仅限于输出那么简单。

logging基本使用参考:https://blog.csdn.net/weixin_43790276/article/details/99617949

logging 模块中实现了很多日志处理的方法,可以帮我们实现日志的管理功能。

一、logging 中常用的日志处理方法和类

1. StreamHandler:logging.StreamHandler,日志输出到流,可以是sys.stderr,sys.stdout或者文件,这个方法通常用来将日志信息输出到控制台

2. FileHandler:logging.FileHandler,日志输出到文件,指定文件,将日志信息写入到文件中

3. BaseRotatingHandler:logging.handlers.BaseRotatingHandler,基本的日志轮转方式,这个类是日志轮转的基类,后面日志按时间轮转,按大小轮转的类都继承于此。轮转的意思就是保留一定数量的日志量,如设置保持7天日志,则会自动删除旧的日志,只保留最近7天

4. RotatingHandler:logging.handlers.RotatingHandler,继承BaseRotatingHandler,支持日志文件按大小轮转

5. TimeRotatingHandler:logging.handlers.TimeRotatingHandler,继承BaseRotatingHandler,支持日志文件按时间轮转

6. SocketHandler:logging.handlers.SocketHandler,远程输出日志到TCP/IP sockets

7. DatagramHandler:logging.handlers.DatagramHandler,远程输出日志到UDP sockets

8. SMTPHandler:logging.handlers.SMTPHandler,远程输出日志到邮件地址

9. MemoryHandler:logging.handlers.MemoryHandler,日志输出到内存中的指定buffer

10. HTTPHandler:logging.handlers.HTTPHandler,通过"GET"或者"POST"远程输出到HTTP服务器

二、logging 控制台输出和文件写入

import logginglogger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)formatter = '%(asctime)s -<>- %(filename)s -<>- [line]:%(lineno)d -<>- %(levelname)s -<>- %(message)s'
file_handler = logging.FileHandler('log.txt')
file_handler.setLevel(level=logging.INFO)
log_formatter = logging.Formatter(formatter)
file_handler.setFormatter(log_formatter)console_handler = logging.StreamHandler()
console_handler.setLevel(level=logging.INFO)
console_formatter = logging.Formatter(formatter)
console_handler.setFormatter(console_formatter)logger.addHandler(file_handler)
logger.addHandler(console_handler)logger.info('info')
logger.error('error')

运行结果:

2019-10-02 22:46:43,056 -<>- logging_demo.py -<>- [line]:64 -<>- INFO -<>- info
2019-10-02 22:46:43,056 -<>- logging_demo.py -<>- [line]:65 -<>- ERROR -<>- error

上面的代码运行后,日志信息即写入了 log.txt 文件中,也打印到了控制台。如果日志文件中没有指定路径,则生成的日志文件与当前运行的py文件处于同一目录,指定了就会生成到指定的目录下。

通过 FileHandler() 方法来定义日志写入的文件,日志格式,日志等级,通过 StreamHandler() 方法定义日志打印到控制台的格式和等级。

然后通过 addHandler() 方法将两个日志处理对象添加到 logger 中,从而实现日志的打印和写文件。

三、日志文件按时间切分

import logging
from logging.handlers import TimedRotatingFileHandler
import timelogger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)formatter = '%(asctime)s -<>- %(filename)s -<>- [line]:%(lineno)d -<>- %(levelname)s -<>- %(message)s'
time_rotate_file = TimedRotatingFileHandler(filename='time_rotate', when='S', interval=2, backupCount=5)
time_rotate_file.setFormatter(logging.Formatter(formatter))
time_rotate_file.setLevel(logging.INFO)console_handler = logging.StreamHandler()
console_handler.setLevel(level=logging.INFO)
console_handler.setFormatter(logging.Formatter(formatter))logger.addHandler(time_rotate_file)
logger.addHandler(console_handler)while True:logger.info('info')logger.error('error')time.sleep(1)

运行结果:

2019-10-02 22:57:00,523 -<>- logging_demo.py -<>- [line]:89 -<>- INFO -<>- info
2019-10-02 22:57:00,528 -<>- logging_demo.py -<>- [line]:90 -<>- ERROR -<>- error
2019-10-02 22:57:01,528 -<>- logging_demo.py -<>- [line]:89 -<>- INFO -<>- info
2019-10-02 22:57:01,528 -<>- logging_demo.py -<>- [line]:90 -<>- ERROR -<>- error
...

上面的代码是无限循环,永远也不会停止,为了演示,我将写入文件的日志写信也打印到了控制台。运行代码后,将日志写到文件中,每个文件只保存两秒钟的数据,只保留最新的5个日志文件,文件名是 time_rotate 加时间字符串。

使用 logging.handlers 中的 TimedRotatingFileHandler 类,可以帮助我们实现日志按时间来切分和轮转。

在实际工作中,日志量是很大的,不可能将全部日志写到同一个文件中,这样无法删除旧的日志,且这个文件会越来越大,直到撑爆磁盘。日志按时间切分和轮转的方式根据具体情况来定,如按月切分,保留3年,按天切分,保留30天,按小时切分,保留7天等等,这些 TimedRotatingFileHandler 都可以帮助我们实现。

TimedRotatingFileHandler 的主要参数:

1. filename: 指定日志文件的名字,会在指定的位置创建一个 filename 文件,然后会按照轮转数量创建对应数量的日志文件,每个轮转文件的文件名为 filename 拼接时间,默认YY-mm-DD_HH-MM-SS,可以自定义。

2. when: 指定日志文件轮转的时间单位

    S - Seconds
    M - Minutes
    H - Hours
    D - Days
    midnight - roll over at midnight
    W{0-6} - roll over on a certain day; 0 - Monday

3. interval: 指定日志文件轮转的周期,如 when='S', interval=10,表示每10秒轮转一次,when='D', interval=7,表示每周轮转一次。

4. backupCount: 指定日志文件保留的数量,指定一个整数,则日志文件只保留这么多个,自动删除旧的文件。

四、日志文件按大小切分

import logging
from logging.handlers import RotatingFileHandler
import timelogger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)formatter = '%(asctime)s -<>- %(filename)s -<>- [line]:%(lineno)d -<>- %(levelname)s -<>- %(message)s'
size_rotate_file = RotatingFileHandler(filename='size_rotate', maxBytes=1*1024, backupCount=5)
size_rotate_file.setFormatter(logging.Formatter(formatter))
size_rotate_file.setLevel(logging.INFO)console_handler = logging.StreamHandler()
console_handler.setLevel(level=logging.INFO)
console_handler.setFormatter(logging.Formatter(formatter))logger.addHandler(size_rotate_file)
logger.addHandler(console_handler)while True:logger.info('info')logger.error('error')time.sleep(1)

运行结果:

2019-10-02 23:18:41,726 -<>- logging_demo.py -<>- [line]:115 -<>- INFO -<>- info
2019-10-02 23:18:41,726 -<>- logging_demo.py -<>- [line]:116 -<>- ERROR -<>- error
2019-10-02 23:18:42,727 -<>- logging_demo.py -<>- [line]:115 -<>- INFO -<>- info
2019-10-02 23:18:42,732 -<>- logging_demo.py -<>- [line]:116 -<>- ERROR -<>- error
...

运行代码后,将日志写到文件中,每个文件只保存 1kb 的数据,只保留最新的5个日志文件,文件名是 size_rotate 加编号,编号从1开始,最新的日志永远保存在 size_rotate.1 中,编号越大,日志时间越靠前。

使用 logging.handlers 中的 RotatingFileHandler 类,可以帮助我们实现日志按文件大小来切分和轮转。

日志按时间切分和轮转的方式根据具体情况来定,如一个文件最多 1G,100M等,保留文件数可以按需定义,这些 RotatingFileHandler 都可以帮助我们实现。

RotatingFileHandler 的主要参数:

1. filename: 指定日志文件的名字,会在指定的位置创建一个 filename 文件,然后会按照轮转数量创建对应数量的日志文件,每个轮转文件的文件名为 filename 拼接编号,编号从1开始。

2. maxBytes: 设置日志文件的大小,单位是字节,如 1kb 是1024,1M 是 1024*1024 ,1G 是 1024*1024*1024 。

3. mode: 设置文件的写入模式,默认 mode='a' ,即追加写入。

4. backupCount: 指定日志文件保留的数量,指定一个整数,日志文件只保留这么多个,自动删除旧的文件。

五、实现日志对象单例

在一个项目中,项目的代码是分很多功能模块的,在同一个项目中,最好保证使用的是同一个日志对象,所有日志都由同一个对象来输出,才能保证所有日志写到一个文件之中,这就需要使用单例来实现。

import logging
from logging.handlers import RotatingFileHandler
from threading import Lockclass LoggerProject(object):def __init__(self):self.mutex = Lock()self.formatter = '%(asctime)s -<>- %(filename)s -<>- [line]:%(lineno)d -<>- %(levelname)s -<>- %(message)s'def _create_logger(self):_logger = logging.getLogger(__name__)_logger.setLevel(level=logging.INFO)return _loggerdef _file_logger(self):size_rotate_file = RotatingFileHandler(filename='size_rotate', maxBytes=1024*1024, backupCount=5)size_rotate_file.setFormatter(logging.Formatter(self.formatter))size_rotate_file.setLevel(logging.INFO)return size_rotate_filedef _console_logger(self):console_handler = logging.StreamHandler()console_handler.setLevel(level=logging.INFO)console_handler.setFormatter(logging.Formatter(self.formatter))return console_handlerdef pub_logger(self):logger = self._create_logger()self.mutex.acquire()logger.addHandler(self._file_logger())logger.addHandler(self._console_logger())self.mutex.release()return loggerlog_pro1 = LoggerProject()
log_pro2 = LoggerProject()
logger1 = log_pro1.pub_logger()
logger2 = log_pro2.pub_logger()
logger1.info('aaa')
logger2.info('aaa')
print('logger1: ', id(logger1))
print('logger2: ', id(logger2))
print('log_pro1: ', id(log_pro1))
print('log_pro2: ', id(log_pro2))

运行结果:

2019-10-03 00:22:18,711 -<>- logging_demo.py -<>- [line]:161 -<>- INFO -<>- aaa
2019-10-03 00:22:18,711 -<>- logging_demo.py -<>- [line]:161 -<>- INFO -<>- aaa
2019-10-03 00:22:18,711 -<>- logging_demo.py -<>- [line]:162 -<>- INFO -<>- aaa
2019-10-03 00:22:18,711 -<>- logging_demo.py -<>- [line]:162 -<>- INFO -<>- aaa
logger1:  2190132262336
logger2:  2190132262336
log_pro1:  2190132262224
log_pro2:  2190132262280

将创建 logger 对象的代码封装到一个类中,然后定义一个返回 logger 对象的方法,实例化这个类的不同对象,id 不相同,但是通过它们调用类的方法返回的 logger 对象,id 值是相等的,是同一个实例。只是这个实例会在多个线程中运行,会造成线程安全问题,所以在代码中加了锁来避免线程安全问题。

这样创建出来的 logger 对象已经实现单例了,如果想连类的对象也实现单例,写一个单例装饰器装饰这个类就行了。

单例参考:https://blog.csdn.net/weixin_43790276/article/details/101390615

线程安全参考:https://blog.csdn.net/weixin_43790276/article/details/91069959

 

 

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/10335.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息