记录日志是我们程序中必不可少的一个功能,但是日志文件如果没有合理的管理,时间长了几百兆的日志文件就很难分析了(都不想打开看),但是又不可能经常手动去管理它
日志轮转:根据时间或者文件大小控制日志的文件个数,不用我们手动管理
python中logging模块内置的有几个支持日志轮转的handler
常用的有TimedRotatingFileHandler根据时间轮转 RotatingFileHandler根据文件大小轮转
但是内置的这些handler是多线程安全的,而不支持多进程(可以修改源码加锁保证进程安全)
多进程的时候可以使用ConcurrentLogHandler(需要自行安装)按照文件大小轮转
1
|
pip install ConcurrentLogHandler
|
一、简单的日志轮转功能实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import logging
from cloghandler import ConcurrentRotatingFileHandler
from config import LOG_PATH, LOG_FILENAME, LOG_MAX_BYTES
def create_logger(log_path = os.getcwd(), # 存放日志的目录
level = logging.DEBUG,
formatter = logging.BASIC_FORMAT, # 日志输出格式
logger_name = "", # 可以使用logging.getlogger(logger_name)使用此logger
mode = 'a' ,
delay = 0 ,
debug = True ,
log_filename = LOG_FILENAME, # 保存日志的文件名(备份出的文件会以此名+.1、 .2命名)
encoding = None ,
maxBytes = LOG_MAX_BYTES, # 每个日志文件的最大容量
backupCount = 3 # 最多备份几个日志文件):
# 判断存放日志的文件夹是否存在 如果不存在新建
if not os.path.exists(log_path):
os.mkdir(log_path)
# 存放log的文件名
log_filename = os.path.join(log_path, log_filename)
# 创建一个logger
logger = logging.getLogger(logger_name)
# 设置日志等级
logger.setLevel(level)
# 创建一个滚动日志处理器
crfh = ConcurrentRotatingFileHandler(log_filename, mode = mode, maxBytes = maxBytes, backupCount = backupCount, delay = delay, debug = debug, encoding = encoding)
# 定义handler的输出格式
# 设定日志输出格式
crfh.setFormatter(formatter)
# 添加日志处理器
logger.addHandler(crfh)
# 返回logger对象
return logger
# 日志格式
formatter_log = logging.Formatter( '%(asctime)s - %(filename)s [line: %(lineno)d] 【%(levelname)s】 ----- %(message)s' )
# 生成一个logger
logger = create_logger(log_path = LOG_PATH, logger_name = "mylogger" , formatter = formatter_log)
|
这样就可以在其他模块导入logger进行使用了
1
|
logger.error( "error msg" )
|
有时候我们会记录一些数据到文件中,如果多个程序同时写入同一文件会把数据写乱 我们也可以使用这个模块来代替f.write()
1
2
3
4
5
|
from config import CHANNEL_PATH, CHANNEL_FILENAME, LOG_MAX_BYTES
# 只需要把日志的格式改为只存入信息就可以了
formatter_writer = logging.Formatter( '%(message)s' )
# 创建一个写入器(logger)
writer = create_logger(logger_name = "writer" ,log_path = CHANNEL_PATH, log_filename = CHANNEL_FILENAME, formatter = formatter_writer, level = logging.INFO)
|
这样就可以使用writer.info("msg")记录数据了
二、使用ini配置文件
创建文件xxx.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
[loggers]
keys = root,public
[handlers]
keys = consoleHandler,publicFileHandler
[formatters]
keys = my_formatter
[logger_root]
level = DEBUG
handlers = consoleHandler
[logger_public]
handlers = publicFileHandler
qualname = public
propagate = 0
[handler_consoleHandler]
class = StreamHandler
level = DEBUG
formatter = my_formatter
args = (sys.stdout,)
[handler_publicFileHandler]
class = cloghandler.ConcurrentRotatingFileHandler
level = INFO
formatter = my_formatter
kwargs = { "filename" : "./logs/public.log" , "maxBytes" : 1024 * 1024 * 10 , "backupCount" : 10 , "delay" : True , "debug" : True }
[formatter_my_formatter]
format = % (asctime)s - % (filename)s [line: % (lineno)d] [ % (levelname)s] - - - - - % (message)s
datefmt = % Y - % m - % d % H: % M: % S
|
创建mylogger.py
1
2
3
4
5
|
import logging
import logging.config
logging.config.fileConfig( "./xxx.ini" )
logger = logging.getLogger( "public" )
logger.info( "hello world!" )
|
补充:python日志轮转RotatingFileHandler动态加载导致不能记录日志问题
linux下:
Traceback (most recent call last): File “/usr/lib64/python2.7/logging/handlers.py”, line 77, in emit self.doRollover() File “/usr/lib64/python2.7/logging/handlers.py”, line 136, in doRollover os.rename(sfn, dfn) OSError: [Errno 13] Permission denied Logged from file utils.py, line 89
windows下:
Traceback (most recent call last): File “F:\Python27\lib\logging\handlers.py”, line 77, in emit self.doRollover() File “F:\Python27\lib\logging\handlers.py”, line 142, in doRollover os.rename(self.baseFilename, dfn) WindowsError: [Error 32] Logged from file utils.py, line 89
这是由于django开发模式时会同时启动两个进程加载settings.py,导致日志文件占用后无法重命名或者删除
都知道django开发模式下如果有文件变动会自动重新启动,所以同时又两个进程,一个是程序正常运行的进程,另一个是用来监听变更并重启服务的进程,他们都会加载一遍settings.py,可以在settings.py中加print然后启动会看到控制台又两次输出。
解决方式:
python C:\Users\pc\Desktop\yunserver-1.1\manage.py runserver --noreload 0.0.0.0:8000
使用不动态加载方式运行(这样可能会影响开发环境中动态加载)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://blog.csdn.net/qq_41864652/article/details/81317908