首页 > 系统相关 >Python 多进程下日志打印

Python 多进程下日志打印

时间:2024-07-25 21:52:35浏览次数:9  
标签:stream Python lock self 打印 record file 日志

Python 多进程下日志打印

问题分析

使用 gunicorn 启动 Flask 时,如果直接使用 logging 的 RotatingFileHandler 模块会出现日志混乱,甚至日志丢失的情况。
在日志翻转时,可能出现一个进程将 log 文件翻转,而后又有进程也将 log 文件翻转,导致 log.1 文件并未达到设置的最大的文件大小,而第一个进程也继续再往 log.1 中输出日志。

改进方式

根据网上很多文档,使用 portalocker 创建文件锁,实现了一个简单的 handler 方便使用,暂时没有发现问题。
需要安装依赖:pip install portalocker

import logging
import logging.handlers
import os
import time
from logging.handlers import RotatingFileHandler

import portalocker


def get_lock_filename(log_file_name) -> str:
    """
    定义日志文件锁名称,类似于 `.__file.lock`,其中file与日志文件baseFilename一致
    :return:
    """
    if log_file_name.endswith('.log'):
        lock_file = log_file_name[:-4]
    else:
        lock_file = log_file_name
    lock_file += '.lock'
    lock_path, lock_name = os.path.split(lock_file)
    # hide the file on Unix and generally from file completion
    lock_name = '.__' + lock_name
    return str(os.path.join(lock_path, lock_name))


class ConcurrentRotatingFileHandler(RotatingFileHandler):
    def __init__(self, filename, *args, **kwargs):
        super().__init__(filename, *args, **kwargs)

        file_dir = os.path.split(filename)[0]
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)

        lock_filename = get_lock_filename(filename)
        self.concurrent_lock = portalocker.Lock(lock_filename, flags=portalocker.LOCK_EX)

    def _do_rollover(self, record):
        # 检查日志文件是否需要翻转
        base_stream = self._open()
        base_stream.seek(0, 2)
        msg = "%s\n" % self.format(record)
        base_stream_length = base_stream.tell() + len(msg)
        base_stream.close()
        if base_stream_length >= self.maxBytes:
            # print('current pid: %d, doRollover' % os.getpid())
            super().doRollover()
        else:
            if self.stream:
                self.stream.close()
                self.stream = None
            if not self.delay:
                self.stream = self._open()

    def emit(self, record):
        """
        Emit a record.

        Output the record to the file, catering for rollover as described
        in doRollover().
        """
        with self.concurrent_lock:
            try:
                if self.shouldRollover(record):
                    # print('current pid: %d, shouldRollover: %d' % (os.getpid(), self.shouldRollover(record)))
                    self._do_rollover(record)
                logging.FileHandler.emit(self, record)
            except Exception:
                self.handleError(record)

标签:stream,Python,lock,self,打印,record,file,日志
From: https://www.cnblogs.com/shouwangrenjian/p/18324204

相关文章

  • python 装饰器执行顺序的代码示例
    defdecoratorA(func):print(33)defwrapperA():print("EnteringA")print(func())print("ExitingA")print(44)returnwrapperAdefdecoratorB(func):print(11)defwrapperB():print("Ent......
  • 自定义IPython启动:打造个性化的交互式编程环境
    自定义IPython启动:打造个性化的交互式编程环境IPython,一个强大的交互式Python解释器,提供了丰富的定制选项,允许用户根据个人或团队的需求定制其行为和外观。设置自定义的启动命令是IPython定制功能的一部分,它可以让你在启动IPython时自动执行一系列操作,如导入模块、设置变量......
  • xml.etree.ElementTree 文档中文翻译; SVG矢量图;Python标准库
    更新中..简介xml.etree.ElementTree实现了一个简洁有效的用于解析和新建XML数据的API。其也被简称为ET。弃用:xml.etree.cElementTree自Python==3.3已被弃用警告:使用时需注意恶意构建的数据,请防范XML漏洞概念XML是一种继承性的分层数据格式,常用树来表示。ET有两个类,Ele......
  • Python--Pandas基础------2
    目录一、导入Excel文件1.导入xlsx文件2.导入csv文件3.head()与tail()4.info()6.shape二、修改变量列1.columns2.rename()三、筛选变量列四、删除变量列五、添加变量列一、导入Excel文件在Pandas中导入Excel文件是一个常见的操作,可以使用read_excel()函数来......
  • 我心中的王者:Python-第9章 字典(Dict)
    我心中的王者:Python-第9章字典(Dict)列表(list)与元组(tuple)是依序排列可称是序列数据结构,只要知道元素的特定位置,即可使用索引观念取得元素内容。这一章的重点是介绍字典(dict),它并不是依序排列的数据结构,通常可称是非序列数据结构,所以无法使用类似列表的数值(0,1,…......
  • Python知识点—math函数,方法全解,细致易懂
    代码中已标明函数的方法以及操作importmathformathsindir(math):ifnotmaths.startswith("__"):#打印math函数的方法,不显示以"__"开头的print(maths)print(math.pi)#π值3.141592653589793#无穷大print(math.inf>99999999999999999999999......
  • 02 Python基础
    变量名的本质就是内存地址i=1b1=2.34b2=Truelist1=[]dic1={}tuple1=()str1=""print(id(i))print(id(b1))print(id(b2))print(id(list1))print(id(dic1))print(id(tuple1))print(id(str1))20860943075682086095348080140707394149224208609......
  • Python 高阶语法
    前言:我们通过上篇文章学习了Python的基础语法,接下来我们来学习Python的高阶语法1.初识对象在Python中我们可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的面向对象包含3大主要特性:封装继承多态(内容靠后)1.1使用对象组织数据在程序中设计表格,我们......
  • SpringBoot 日志
    目录一、日志概述二、日志使用2.1打印日志2.2日志格式2.3日志级别2.4日志配置2.4.1日志级别2.4.2日志持久化2.4.3日志文件分割2.4.4配置日志格式三、更简单的日志输出3.1添加lombok依赖3.2输出日志一、日志概述在SpringBoot项目启动后,项目本身就......
  • python实现ftpServer
    使用python模拟一个fetServer importosimportsocketimportthreadingfrompyftpdlib.authorizersimportDummyAuthorizerfrompyftpdlib.handlersimportFTPHandlerfrompyftpdlib.serversimportFTPServer_source_root=os.path.dirname(os.path.dirname(os.path......