为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕丝7291255 2023-04-25 16:08:30
在我的 Flask 应用程序中,我使用该库实现了一个日志系统logging。它当前在以下函数中运行:if __name__ == "__main__":    """[Runs the webserver.    Finally block is used for some logging management. It will first shut down    logging, to ensure no files are open, then renames the file to 'log_'    + the current date, and finally moves the file to the /logs archive    directory]    """    try:        session_management.clean_uploads_on_start(UPLOAD_FOLDER)        app.run(debug=False)    finally:        try:            logging.shutdown()            new_log_file_name = log_management.rename_log(app.config['DEFAULT_LOG_NAME'])            log_management.move_log(new_log_file_name)        except FileNotFoundError:            logging.warning("Current log file not found")        except PermissionError:            logging.warning("Permissions lacking to rename or move log.")我发现如果强制关闭 cmd 提示符或服务器崩溃,则文件不会重命名和移动。我认为在服务器启动之前将重命名并移入函数的初始“try”块可能会更好,但我遇到了问题,因为我有一个配置文件(在此脚本中导入)具有以下代码:logging.basicConfig(filename='current_log.log', level=logging.INFO,                    filemode='a',                    format='%(asctime)s:%(levelname)s:%(message)s')我试过做类似下面的事情,但我仍然遇到权限错误,但我认为我仍然遇到错误,因为 log_management 脚本也导入了配置。此外,我找不到启动日志系统的函数,类似于在系统结束时使用的 logging.shutdown() ,否则我会关闭它,移动文件(如果存在)并重新启动它。  try:        session_management.clean_uploads_on_start(UPLOAD_FOLDER)        log_management.check_log_on_startup(app.config['DEFAULT_LOG_NAME'])        import config        app.run(debug=False)    finally:        try:            logging.shutdown()            new_log_file_name = log_management.rename_log(app.config['DEFAULT_LOG_NAME'])            log_management.move_log(new_log_file_name)        except FileNotFoundError:            logging.warning("Current log file not found")        except PermissionError:            logging.warning("Permissions lacking to rename or move log.")# (in another script)def check_log_on_startup(file_name):    if os.path.exists(file_name):        move_log(rename_log(file_name))非常欢迎任何建议,因为我觉得我在一堵砖墙上!
查看完整描述

1 回答

?
繁花如伊

TA贡献2012条经验 获得超12个赞

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


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

这会导致在现有日志上隐式创建一个打开的文件对象。FileHandler根据您使用的文件系统,这可能不会让人高兴。


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


作为替代方案,您可以通过子类化标准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_management,至少就您在代码中显示的功能而言。rename_log,move_log并且check_log_on_startup都封装在CustomFileHandler. 也无需显式调用logging.shutdown().


一些注意事项:

找不到等效的启动函数的原因logging.shutdown()是在导入logging模块时启动/初始化了日志系统。除其他外,它实例化隐式根记录器并通过atexit注册logging.shutdown为退出处理程序。 后者是无需显式调用上述解决方案的原因。Python 解释器将在准备因退出处理程序注册而关闭解释器时在完成期间调用它。然后遍历已注册处理程序的列表并调用它们的方法,这将在干净关闭期间执行日志归档。
logging.shutdown()logging.shutdown()close()

根据您选择的移动(和重命名)旧日志文件的方法,上述解决方案可能需要一些额外的异常保护措施。os.rename如果目标路径已经存在,即当您已经在同一天停止并启动您的进程时,将引发异常,同时os.replace会静默覆盖现有文件。

因此,我建议不仅按当前日期而且按时间命名归档日志。
在上面,将当前日期添加到存档文件名是通过datetime's完成的strftime,因此 'log_ %Y%m%d ' 作为archive_name自定义文件处理程序参数的默认值。前面的字符%是有效的格式代码,替换为调用它的对象strftime()的相应部分。datetime要将当前时间附加到存档日志文件名,您只需将相应的格式代码附加到archive_name,例如:'log_%Y%m%d_ %H%M%S ',这将导致日志名称,例如log_20200819_123721.


查看完整回答
反对 回复 2023-04-25
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信