都说python logging多进程日志存在混乱报错等问题,我的程序,采用按时间每天切分那种,问题是每个进程的日志文件存储路径是不一样的,甚至就一个进程,为啥还会日志混乱或报错呢?
在windows系统下,会报日志被另一个进程占用
在linux系统下不报错,但是日志记录会混乱
请问原因是什么?解决方案是什么?
不管你windows单进程还是多进程,因为设计的时候我们都是基于文件名的,不管后台是不是隐藏的还是人为切换进程,我还是能锁定同一个文件名的文件,楼上提到的日志记录服务或将每个进程的日志文件存储在不同的目录中这个是可行的,并且已经得到了实际验证,在 Linux 上基于文件句柄的,多进程同时写入同一个文件时可能会出现混乱,但不会报错。
句柄的概念不知道你了解吗?Windows 内核将内存中的所有对象的地址列表维护成整数索引,这个整数就叫做句柄,逻辑上讲类似于“指针的指针”
Python logging模块在多进程环境下确实存在一些问题,主要是因为多个进程同时写入同一个日志文件会导致日志记录混乱或者报错。
对于你的问题,可能是因为每个进程的日志文件存储路径不同,导致多个进程同时写入不同的日志文件,从而导致日志记录混乱。此外,在Windows系统下,由于文件锁定机制的不同,可能会导致日志文件被另一个进程占用的问题。
解决方案可以考虑以下几点:
使用进程安全的日志处理器,例如QueueHandler
和QueueListener
,可以将日志消息放入队列中,然后由单独的线程或进程负责将消息写入日志文件。
使用文件锁定机制,例如fcntl
模块或win32file
模块,可以确保每个进程在写入日志文件时都能够获得独占的文件锁。
将日志文件存储路径设置为相同的路径,这样多个进程就可以同时写入同一个日志文件,避免日志记录混乱的问题。
考虑使用分布式日志处理系统,例如ELK
或Fluentd
,可以将日志消息发送到中央服务器进行集中处理和存储,避免多个进程同时写入同一个日志文件的问题。
总之,在多进程环境下,需要注意日志记录的并发性和安全性,选择合适的日志处理器和文件锁定机制,以及统一的日志文件存储路径,才能避免日志记录混乱或报错的问题。
我补充下,上述这些回答我之前搜索时都看到过。主要问题核心点
1 windows下,即使单进程,切分时还是会报进程被占用
2 windows下,多进程,每个进程的日志放在了不同路径下,按理说不应该进程被占用
3 我先不考虑队列,我就想弄清楚为啥
python的logger日志是仿照Java开发的,全都是仅仅保证线程安全,所以当你多个进程打开共享同一个文件句柄,所以都有读写自然会乱了 。
怎么解决? 有个很简单的办法,你通过系统消息队列,消息队列最经典的用法就是消费者 和生产者之间通过消息管道传递消息,消费者和生成者是不同的进程。生产者往管道写消息,消费者从管道中读消息参考下使用multiprocessing里面的Queue来实现消息队列
我的程序,采用按时间每天切分那种,问题是每个进程的日志文件存储路径是不一样的,甚至就一个进程
如照题主说的,不应该会有问题的。目录不一样+日切分,根本不会有错误:会报日志被另一个进程占用。
按照官方文档的介绍,logging 是线程安全的,也就是说,在一个进程内的多个线程同时往同一个文件写日志是安全的。但是(对,这里有个但是)多个进程往同一个文件写日志不是安全的。官方的说法是这样的:
Because there is no standard way to serialize access to a single file across multiple processes in Python. If you need to log to a single file from multiple processes, one way of doing this is to have all the processes log to a SocketHandler, and have a separate process which implements a socket server which reads from the socket and logs to file. (If you prefer, you can dedicate one thread in one of the existing processes to perform this function.)
为了使用多核CPU,为了解决这个问题,可以使用 ConcurrentLogHandler,ConcurrentLogHandler 可以在多进程环境下安全的将日志写入到同一个文件,并且可以在日志文件达到特定大小时,分割日志文件。
使用细节:https://blog.csdn.net/weixin_42567970/article/details/130224886
logger.py
import logging
from concurrent_log_handler import ConcurrentRotatingFileHandler
import os
from logging.handlers import TimedRotatingFileHandler
import time
import multiprocessing
def create_logger():
# 获取当前进程名
process_name = multiprocessing.current_process().name
logger = logging.getLogger(process_name)
logger.setLevel(logging.DEBUG)
# 创建日志文件夹
log_dir = os.path.join(os.getcwd(), 'log')
if not os.path.exists(log_dir):
os.mkdir(log_dir)
# 创建子进程日志文件夹
log_dir2 = os.path.join(log_dir, process_name)
if not os.path.exists(log_dir2):
os.mkdir(log_dir2)
# 创建日志格式
formatter_log = logging.Formatter(
"%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(processName)s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
# 创建 InfoLog 和 ErrLog 的 handler
info_handler = create_timed_rotating_file_handler(os.path.join(log_dir2, f"{process_name}_InfoLog"), formatter_log)
err_handler = create_rotating_file_handler(os.path.join(log_dir, "ErrLog"), formatter_log)
# 添加 handler 到 logger 中
logger.addHandler(info_handler)
logger.addHandler(err_handler)
# 同样的,创建一个Handler用于控制台输出日志
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)
ch.setFormatter(formatter_log)
logger.addHandler(ch)
return logger
# 事件日志,每个进程即一个设备一个日志
def create_timed_rotating_file_handler(file_path, formatter):
# 初始化 TimedRotatingFileHandler
handler = logging.handlers.TimedRotatingFileHandler(
filename=f"{file_path}_{get_current_date()}.txt", # 文件名
when="midnight", # 按天轮转
interval=1, # 1天
backupCount=10, # 最大保留文件数
encoding="utf-8"
)
handler.setFormatter(formatter)
handler.setLevel(logging.DEBUG)
return handler
# 错误日志,全部进程共用一个日志
def create_rotating_file_handler(file_path ,formatter):
# 初始化 ConcurrentRotatingFileHandler
handler = ConcurrentRotatingFileHandler(
filename=f"{file_path}.txt", #文件名
mode='a',
maxBytes=1024 * 1024 * 32, # 按32MB大小轮转
backupCount=5, # 最大保留文件数
encoding="utf-8"
)
handler.setFormatter(formatter)
handler.setLevel(logging.WARNING)
return handler
# 获取日期
def get_current_date():
current_time = time.localtime()
return f"{current_time.tm_year}{current_time.tm_mon:02d}{current_time.tm_mday:02d}"
# 生成一个logger
logger = create_logger()
test1.py
from logger import logger
import time
for x in range(1, 100):
logger.debug("--------------------")
logger.debug("This is a debug message")
logger.info("This is an info message")
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")
time.sleep(10)
在多进程环境下,使用 Python 的 logging 模块记录日志可能会遇到一些问题,如日志混乱或报错。这是因为多个进程同时尝试访问和写入同一个日志文件时可能导致的竞争条件。
在 Windows 系统下,由于文件锁定机制的不同,当一个进程正在写入日志文件时,其他进程可能无法访问该文件,导致报错。
在 Linux 系统下,多个进程可以同时访问同一个文件,但由于并发写入的问题,可能会导致日志记录的顺序混乱。
解决这些问题的一种常见方法是使用适合多进程环境的日志记录方案,例如:
使用第三方日志库:一些第三方日志库提供了对多进程环境的支持,例如 loguru
、structlog
、multiprocessing_logging
等。这些库通常会处理好日志文件的并发写入和切分等问题。
使用分布式日志系统:将日志记录到分布式的日志系统中,例如 ELK Stack
(Elasticsearch、Logstash、Kibana)或 Graylog
,这些系统能够处理多进程的日志收集、聚合和查询。
使用进程独立的日志文件:每个进程将日志记录到独立的日志文件中,避免多个进程同时访问同一个日志文件。你可以使用进程 ID 或其他唯一标识符来为每个进程生成不同的日志文件路径。
示例代码:
import logging
import os
import multiprocessing
def setup_logger():
process_id = multiprocessing.current_process().pid
log_file = f"log_{process_id}.txt" # 根据进程 ID 生成独立的日志文件名
log_path = os.path.join("logs", log_file) # 指定日志文件存储路径
logging.basicConfig(filename=log_path, level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
def worker_function():
setup_logger()
logging.debug("This is a debug message")
if __name__ == "__main__":
processes = []
for _ in range(5):
p = multiprocessing.Process(target=worker_function)
p.start()
processes.append(p)
for p in processes:
p.join()
在上述示例中,每个进程根据进程 ID 生成独立的日志文件路径,并将日志记录到对应的文件中。
请注意,在多进程日志记录中,还要考虑日志文件的切分和清理,以避免日志文件过大或占用过多存储空间。你可以设置日志切分的策略,例如按照日期切分、按照文件大小切分等。
综上所述,解决多进程日志混乱或报错的方法包括使用适合多进程环境的日志库、使用分布式日志系统或为每个进程生成独立的日志文件路径。选择适合你需求的方法,并根据具体情况进行相应的配置和调整。
该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
Python 的 logging 模块在多进程环境下确实存在一些问题,包括日志混乱、日志被占用等问题。这些问题主要是由于多个进程同时写入同一个日志文件导致的。以下是一些可能的原因和解决方案:
日志文件路径不唯一:您提到每个进程的日志文件存储路径是不一样的,这可能会导致日志混乱。建议您为每个进程指定一个唯一的日志文件路径,可以使用进程 ID 或者进程名称作为前缀来保证唯一性。
日志文件被占用:在 Windows 系统下,由于文件锁定机制的限制,可能会导致多个进程同时写入同一个日志文件时出现“日志文件被占用”的错误。您可以考虑使用 RotatingFileHandler 或者 TimedRotatingFileHandler 类来避免这个问题,它们会自动切换日志文件并释放文件锁定。
日志记录顺序混乱:在 Linux 系统下,多进程写入同一个日志文件时可能会导致日志记录的顺序混乱。这是因为多个进程同时写入同一个文件时,操作系统会根据一定的策略对写入顺序进行调度。如果您需要保证日志记录的顺序,可以考虑使用 QueueHandler 和 QueueListener 类来实现进程间的日志消息传输,这样可以保证所有的日志记录都通过主进程来写入日志文件。
日志格式问题:在多进程环境下,如果多个进程同时写入同一个日志文件,可能会导致日志格式混乱,例如同一个日志消息被拆成多个部分写入到日志文件中。为了避免这个问题,建议您使用线程安全的日志格式化方法,例如使用 QueueHandler 和 QueueListener 实现进程间的消息传输。
综上所述,要解决多进程日志混乱和报错问题,您需要为每个进程指定唯一的日志文件路径,并使用线程安全的日志处理方式。您可以参考 Python 官方文档中的多进程日志处理示例来进行实现。
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
你好,引用chatgpt部分指引作答:
Python的logging模块是线程安全的,但不是进程安全的。这意味着在多进程的情况下,如果多个进程同时写入同一个日志文件,可能会出现日志混乱或丢失的问题。这可能是你遇到的问题的原因。
主要问题核心点:
windows下,即使单进程,切分时还是会报进程被占用
这可能是因为你使用了TimedRotatingFileHandler来切分日志文件,而这个类在windows下有一个bug,就是在切分时会尝试删除旧的日志文件,但如果这个文件还被其他进程或程序占用,就会报错。你可以尝试使用其他的Handler类来切分日志文件,或者自定义一个Handler类来避免删除旧文件的操作。
windows下,多进程,每个进程的日志放在了不同路径下,按理说不应该进程被占用
这可能是因为你使用了logging.basicConfig()来配置日志模块,而这个函数在多进程环境下可能会有一些问题。你可以尝试使用其他的方式来配置日志模块,比如使用logging.config.dictConfig()或者logging.config.fileConfig()来从字典或文件中读取配置信息。
来自NewBing和LP的编写:
logging
模块是线程安全的,但并非进程安全的,这意味着在多进程的环境下,logging
模块可能会表现出不符合预期的行为。这就是你在多进程环境下遇到问题的原因。具体来说:
在Windows下,即使是单个进程,如果你在多个线程中尝试写入同一个日志文件,那么当一个线程在写入日志时,另一个线程尝试写入同一个文件,就可能导致"进程被占用"的错误。这是因为Windows下的文件锁定行为。
在Windows下,多进程,每个进程的日志放在了不同路径下。尽管你的日志文件存储在不同的路径下,但是logging
模块内部可能仍然共享某些资源,这就可能导致资源冲突。
在Linux下不报错,但日志记录会混乱。这可能是因为多个进程都试图同时写入同一日志文件,由于没有同步机制,所以日志信息可能会相互覆盖或者混乱。
解决方案:
logging
模块,最好的解决方案是使用进程间通信或者同步机制。例如,你可以使用multiprocessing
模块提供的队列或者管道来传递日志消息,然后创建一个专门的进程来处理这些日志消息并写入日志文件。Logger
实例,并确保没有共享任何Handler
。你也可以试试看将logging
模块的lock
属性设置为False
,以禁用其内部的锁定机制。但是请注意,这可能会导致日志消息的丢失或者混乱。希望这些信息可以帮助你解决问题!
基于new bing的编写,有帮助记得采纳!:
多进程共享同一个文件句柄会导致日志混乱或报错,因为多个进程同时写入同一个文件的时候,有可能会出现写入顺序混乱或者同时写入相同位置的情况,从而导致日志内容错乱或报错。此外,在Windows系统中,文件句柄不能被多个进程同时打开,这也会导致日志被占用。
为了避免这些问题,可以使用第三方库,比如QueueHandler和QueueListener来实现多进程日志记录,它们会先将日志消息放入队列中,然后由主进程将队列中的消息写入日志文件,这样可以避免多个进程同时写入同一个文件的问题。
另外,可以使用基于进程ID或线程ID的日志文件名来避免多个进程同时写入同一个文件的问题。例如,可以将日志文件名命名为“myapp_pid.log”,其中pid是当前进程的进程ID,这样每个进程都会输出到自己单独的日志文件中。
总之,要解决多进程日志记录的问题,可以采取以下措施:
使用QueueHandler和QueueListener等第三方库
使用基于进程ID或线程ID的日志文件名
避免多个进程同时写入同一个文件
希望以上回答对您有所帮助。
02 什么是日志?
日志
就是用于记录系统运行时的信息,对一个事件的记录,也称为Log。
03 日志的用途是什么?
日志的基本用途如下:
记录程序运行过程中的错误,方便跟踪定位问题,减少调试和维护成本;
通过日志能还原整个程序的执行过程,能了解程序的整体状态;
对用户行为分析和数据统计,知晓信息来自于哪个模块;
在设计测试框架的时候,也可以通过设计日志来记录框架的整个测试流程;
04 日志的级别分为哪些?
常见日志等级,如下:
DEBUG
:调试级别(Value=10),打印非常详细的日志信息,通常仅在Debug时使用,如算法中每个循环的中间状态;
INFO
:信息级别(Value=20),打印一般的日志信息,突出强调程序的运行过程 ,主要用于处理请求或者状态变化等日常事务;
ERROR
:错误级别(Value=40),打印错误异常信息,该级别的错误可能会导致系统的一些功能无法正常使用,如IO操作失败或者连接问题;
CRITICAL
:严重错误(Value=50),一个严重的错误,导致系统可能无法继续运行,如内存耗尽、磁盘空间为空,一般很少使用;
以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:
多进程下日志混乱主要有以下几个原因:
解决方案主要有:
具体的实现步骤可以是:
这些方案可以很好解决多进程环境下日志混乱和异常的问题。