首页 > 解决方案 > Python 日志记录失败,网络驱动器上的日志文件(Windows 10)

问题描述

我想使用 python 的日志记录模块记录到网络驱动器上的文件。我的问题是日志记录在某个随机点失败,给了我这个错误:

--- Logging error ---
Traceback (most recent call last):
  File "c:\programme\anaconda3\lib\logging\__init__.py", line 1085, in emit
    self.flush()
  File "c:\programme\anaconda3\lib\logging\__init__.py", line 1065, in flush
    self.stream.flush()
OSError: [Errno 22] Invalid argument
Call stack:
  File "log_test.py", line 67, in <module>
    logger_root.error('FLUSH!!!'+str(i))
Message: 'Minute:120'
Arguments: ()
--- Logging error ---
Traceback (most recent call last):
  File "c:\programme\anaconda3\lib\logging\__init__.py", line 1085, in emit
    self.flush()
  File "c:\programme\anaconda3\lib\logging\__init__.py", line 1065, in flush
    self.stream.flush()
OSError: [Errno 22] Invalid argument
Call stack:
  File "log_test.py", line 67, in <module>
    logger_root.error('FLUSH!!!'+str(i))
Message: 'FLUSH!!!120'
Arguments: ()

我在装有 Windows 10(版本 1909)的虚拟机上,我使用 Python 3.8.3 并记录 0.5.1.2。该脚本在存储日志文件的网络驱动器上的虚拟环境中运行。我正在编写一个脚本,它可以自动执行一些数据质量控制任务,但我不能 100% 确定脚本最终会在哪里(网络驱动器、本地驱动器等),所以它应该能够在所有可能的情况下登录. 错误不会出现在脚本中的同一位置/行,而是随机出现。有时程序(总共约 120 分钟)完成时根本没有出现错误。

到目前为止我尝试了什么:

我相信日志文件在某个时候已关闭,因此无法向其中写入新的日志消息。我写了一个简单的脚本,它基本上只记录日志来检查它是否与我的原始脚本或日志记录过程本身有关。由于“only-logs-script”也随机失败,当它在网络驱动器上运行而不是在我的本地驱动器上运行时,我认为它与网络驱动器的连接有关。我想过将整个日志记录存储在内存中,然后写入文件,但 MemoryHandler 也会在脚本开头打开文件,因此在某些时候会失败。

这是我的“only-logs-script”(log_test.py)代码:

import logging
import logging.handlers
import os
import datetime
import time

##################################################################
# setting up a logger to create a log file with information about this programm
logfile_dir = 'logfiles_test'
CHECK_FOLDER = os.path.isdir(logfile_dir)

# if folder doesn't exist, create it
if not CHECK_FOLDER:
    os.makedirs(logfile_dir)
    print("created folder : ", logfile_dir)
log_path = '.\\'+logfile_dir+'\\'
Current_Date = datetime.datetime.today().strftime ('%Y-%m-%d_')
log_filename = log_path+Current_Date+'logtest.log'

print(log_filename)

# Create a root logger
logger_root = logging.getLogger()

# Create handlers
f1_handler = logging.FileHandler(log_filename, mode='w+')
f2_handler = logging.StreamHandler() 

f1_handler.setLevel(logging.INFO)
f2_handler.setLevel(logging.INFO)

# Create formatters and add it to handlers
f1_format = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s \n')
f2_format = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s \n')

f1_handler.setFormatter(f1_format)
f2_handler.setFormatter(f2_format)

# create a memory handler
memoryhandler = logging.handlers.MemoryHandler(
                    capacity=1024*100,
                    flushLevel=logging.ERROR,
                    target=f1_handler,
                    flushOnClose=True
                    )


# Add handlers to the logger
logger_root.addHandler(memoryhandler)
logger_root.addHandler(f2_handler)

logger_root.setLevel(logging.INFO)
logger_root.info('Log-File initiated.')

fname = log_path+'test.log'
open(fname, mode='w+')

for i in range(60*4):
    print(i)
    logger_root.warning('Minute:'+str(i))
    print('Write access:', os.access(fname, os.W_OK))
    if(i%10==0):
        logger_root.error('FLUSH!!!'+str(i))
    time.sleep(60)

我的日志记录过程有什么可怕的问题还是因为网络驱动器?你们中有人对如何解决这个问题有任何想法吗?将整个信息存储在内存中并最终将其写入文件会解决问题吗?我将如何最好地实现这一目标?另一个想法是登录本地驱动器,然后在脚本完成后自动将文件复制到网络驱动器。非常感谢任何帮助,因为我已经尝试识别和解决这个问题好几天了。

谢谢!

标签: pythonpython-3.xwindowsloggingnetwork-drive

解决方案


由于这并没有真正去任何地方,我将发布我为“解决”我的问题所做的事情。这不是一个令人满意的解决方案,因为当代码失败时它会失败,但总比不记录要好。该解决方案的灵感来自这个问题的答案:将消息记录到带有日志记录的数组/列表中

所以这就是我所做的:

import io

#####################################
# first create an in-memory file-like object to save the logs to
log_messages = io.StringIO()

# create a stream handler that saves the log messages to that object
s1_handler = logging.StreamHandler(log_messages)
s1_handler.setLevel(logging.INFO)

# create a file handler just in case
f1_handler = logging.FileHandler(log_filename, mode='w+')
f1_handler.setLevel(logging.INFO)

# set the format for the log messages
log_format = '%(asctime)s | %(name)s | %(levelname)s | %(message)s \n'
f1_format = logging.Formatter(log_format)
s1_handler.setFormatter(f1_format)
f1_format = logging.Formatter(log_format)

# add the handler to the logger
logger_root.addHandler(s1_handler)
logger_root.addHandler(f1_handler)

#####################################
# here would be the main code ...

#####################################
# at the end of my code I added this to write the in-memory-message to the file
contents = log_messages.getvalue()
# opening a file in 'w'
file = open(log_filename, 'w')
# write log message to file
file.write("{}\n".format(contents))
# closing the file and the in-memory object
file.close()
log_messages.close()

显然,当代码失败但代码试图捕获大多数错误时,这会失败,所以我希望它会起作用。我摆脱了内存处理程序,但保留了一个文件处理程序,以便在真正失败的情况下,至少记录一些日志,直到文件处理程序失败。这远非理想,但对我来说很有效。如果您有其他建议/改进,我很乐意听到!


推荐阅读