Python日志记录-启动时移动文件

Python日志记录-启动时移动文件,python,Python,在我的Flask应用程序中,我使用日志记录库实现了一个日志记录系统。它当前在以下函数中运行: 如果名称=“\uuuuu main\uuuuuuuu”: “”[运行Web服务器。 最后,该块用于一些日志管理。它将首先关闭 日志记录,以确保没有打开任何文件,然后将文件重命名为“log\ux” +当前日期,最后将文件移动到/logs存档 目录] """ 尝试: 会话\u管理。清理\u在\u开始时上载\u(上载\u文件夹) app.run(debug=False) 最后: 尝试: logging.sh

在我的Flask应用程序中,我使用
日志记录
库实现了一个日志记录系统。它当前在以下函数中运行:


如果名称=“\uuuuu main\uuuuuuuu”:
“”[运行Web服务器。
最后,该块用于一些日志管理。它将首先关闭
日志记录,以确保没有打开任何文件,然后将文件重命名为“log\ux”
+当前日期,最后将文件移动到/logs存档
目录]
"""
尝试:
会话\u管理。清理\u在\u开始时上载\u(上载\u文件夹)
app.run(debug=False)
最后:
尝试:
logging.shutdown()
新建日志文件名称=日志管理。重命名日志(app.config['DEFAULT\u log\u name'])
日志管理。移动日志(新日志文件名)
除FileNotFoundError外:
logging.warning(“未找到当前日志文件”)
除许可错误外:
警告(“缺少重命名或移动日志的权限”)
我发现,如果cmd提示符被强制关闭,或者服务器崩溃,文件不会被重命名和移动。我认为在服务器启动之前,最好将重命名和移动放在函数的初始“try”块中,但我遇到了问题,因为我有一个配置文件(在该脚本中导入),其中包含以下代码:

logging.basicConfig(filename='current\u log.log',level=logging.INFO,
filemode='a',
格式='(asctime)s:%(levelname)s:%(消息)s')
我尝试过做如下的事情,但仍然会遇到权限错误,但我认为仍然会遇到错误,因为日志管理脚本也会导入配置。此外,我找不到一个类似于logging.shutdown()的启动日志系统的函数,该函数在系统结束时使用,否则我会关闭它,移动文件(如果存在)并重新启动它


尝试:
会话\u管理。清理\u在\u开始时上载\u(上载\u文件夹)
日志管理。在启动时检查日志(app.config['DEFAULT\u log\u NAME'])
导入配置
app.run(debug=False)
最后:
尝试:
logging.shutdown()
新建日志文件名称=日志管理。重命名日志(app.config['DEFAULT\u log\u name'])
日志管理。移动日志(新日志文件名)
除FileNotFoundError外:
logging.warning(“未找到当前日志文件”)
除许可错误外:
警告(“缺少重命名或移动日志的权限”)
#(另一个脚本)
def启动时检查日志(文件名):
如果os.path.exists(文件名):
移动日志(重命名日志(文件名))

任何建议都很受欢迎,因为我感觉自己就像在一堵砖墙前

正如您已经发现的,如果流程不干净地终止,尝试在流程生命周期结束时执行清理可能会失败

在开始时执行清理的问题是,在尝试移动旧日志文件之前,您显然从导入中调用了
logging.basicConfig

这会导致隐式创建的
FileHandler
在尝试重命名和移动现有日志时在其上保留一个打开的文件对象。根据您使用的文件系统的不同,这可能不会令人高兴

如果要将对潜在旧日志文件的处理完全移动到应用程序的开始,则必须在调用
logging.basicConfig
之前执行重命名和移动,因此必须从导入中将其删除,并以某种方式将其添加到
log\u管理中

作为替代方案,您可以通过对标准
FileHandler
类进行子类化,将日志文件的整个处理移动到日志文件处理程序,例如:

import logging
import os
from datetime import datetime

class CustomFileHandler(logging.FileHandler):

    def __init__(self, filename, archive_path='archive', archive_name='log_%Y%m%d', **kwargs):
        self._archive = os.path.join(archive_path, archive_name)
        self._archive_log(filename)
        super().__init__(filename, **kwargs)

    def _archive_log(self, filepath):
        if os.path.exists(filepath):
            os.rename(filepath, datetime.now().strftime(self._archive))

    def close(self):
        super().close()
        self._archive_log(self.baseFilename)
使用此选项,您可以如下配置日志记录:

hdler = CustomFileHandler('current.log')
logging.basicConfig(level=logging.INFO, handlers=[hdler], 
                   format='%(asctime)s:%(levelname)s:%(message)s')
CustomFileHandler
将在初始化期间检查并可能存档旧日志。这将处理不干净的流程终止后的遗留问题,其中无法进行关机清理。由于父类初始值设定项是在尝试日志存档后调用的,因此日志上还没有导致
PermissionError
的打开句柄

重写的
close()
方法将在干净的进程关闭时执行归档

至少就代码中显示的功能而言,这样就不需要专用的
log\u管理
模块<代码>重命名日志
移动日志
和启动时检查日志都封装在
CustomFileHandler
中。也不需要显式调用
logging.shutdown()


一些注意事项:

您找不到与
logging.shutdown()
等效的启动函数的原因是,当您导入
logging
模块时,日志系统已启动/初始化。除此之外,还有it和via。
后者就是不需要使用上述解决方案显式调用
logging.shutdown()
的原因。由于退出处理程序注册,Python解释器在准备解释器关闭时,将在完成过程中调用它
logging.shutdown()
然后遍历已注册处理程序和的列表,这些处理程序将在干净的关机过程中执行日志存档

根据您选择的移动(和重命名)旧日志文件的方法,上述解决方案可能需要一些额外的异常保护措施
os.rename
如果目标路径已经存在,即当您之前在同一天停止并启动了进程,而
os.replace
将以静默方式覆盖现有文件时,则会引发异常。请参阅有关通过Python移动文件的更多详细信息

因此,我建议将归档日志命名为