每分钟单独的日志文件并不总是生成
separate logfiles for every minute not always generated
我正在尝试设置日志记录,其中每分钟的所有日志都将在一个单独的文件中结束。这是我的设置:
import logging
from logging.handlers import TimedRotatingFileHandler
import time
logging.basicConfig(
format="[%(asctime)s] %(levelname)s in %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[TimedRotatingFileHandler("test.log", when="m", interval=1, backupCount=10, utc=True)],
)
logging.Formatter.converter = time.gmtime
logger = logging.getLogger(__name__)
logger.error("asdf")
当我多次 运行 脚本时,这是我在 test.log.2020-01-01_22-16
中发现的:
[2022-01-01 22:15:46] ERROR in __main__: asdf
[2022-01-01 22:15:55] ERROR in __main__: asdf
[2022-01-01 22:16:06] ERROR in __main__: asdf
[2022-01-01 22:16:14] ERROR in __main__: asdf
[2022-01-01 22:16:15] ERROR in __main__: asdf
[2022-01-01 22:16:45] ERROR in __main__: asdf
[2022-01-01 22:16:56] ERROR in __main__: asdf
任何人都可以解释为什么 test.log.2020-01-01_22-15
根本不存在,而我认为存在于其中的记录却在 22:16
日志中找到了吗?
编辑:我发现只有整整一分钟没有记录任何内容时才会生成新文件。我能以某种方式实现我想要的吗?
的确,TimedRotatingFileHandler
documentation 是这么说的:
When computing the next rollover time for the first time (when the handler is created), the last modification time of an existing log file, or else the current time, is used to compute when the next rotation will occur.
TimedRotatingFileHandler.__init__
:
对应代码的正确翻译
if os.path.exists(filename):
t = os.stat(filename)[ST_MTIME]
else:
t = int(time.time())
它适用于长期 运行ning 应用程序。如果您想要让您的 short-运行ning 应用程序具有相同的行为,您将不得不编写一些自定义代码。
尽可能多地重复使用 TimedRotatingFileHandler
,我们可以利用修改时间作弊。
import logging
from logging.handlers import TimedRotatingFileHandler
import time
import datetime
import os
import re
import stat
def cheat_logfile_mtime():
filename = "test.log"
with open(filename, "rt") as logfile:
first_line = logfile.readline().rstrip()
pattern = re.compile(r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})]") # [2022-01-03 16:06:07]
match = pattern.match(first_line)
assert match is not None
logline_datetime_str = match.group(1)
local_timezone = datetime.datetime.now().astimezone().tzinfo
logline_datetime = datetime.datetime.fromisoformat(logline_datetime_str).replace(tzinfo=datetime.timezone.utc).astimezone()
file_mtime_datetime = datetime.datetime.fromtimestamp(os.stat(filename)[stat.ST_MTIME], tz=local_timezone)
now = datetime.datetime.now(tz=local_timezone)
one_minute_delta = datetime.timedelta(minutes=1)
if now - file_mtime_datetime < one_minute_delta < now - logline_datetime:
# the logfile was last modified less than one minute ago, but was first written more than one minute ago
os.utime("test.log", (logline_datetime.timestamp(), logline_datetime.timestamp()))
print("cheating the file mtime")
cheat_logfile_mtime()
logging.basicConfig(
format="[%(asctime)s] %(levelname)s in %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[TimedRotatingFileHandler("test.log", when="m", interval=1, backupCount=10, utc=True)],
)
logging.Formatter.converter = time.gmtime
logger = logging.getLogger(__name__)
logger.error("asdf")
这如您所愿:无论您启动应用程序多少次,日志文件都不会包含超过 1 分钟的实际日志。我每秒用 1 运行 测试它,在旋转之前在文件中得到 ~59 行。
它似乎尊重用户时区(我目前在 CET)。但它要求能够可靠地读写修改时间,这在网络驱动器或其他条件下可能无法实现。
我正在尝试设置日志记录,其中每分钟的所有日志都将在一个单独的文件中结束。这是我的设置:
import logging
from logging.handlers import TimedRotatingFileHandler
import time
logging.basicConfig(
format="[%(asctime)s] %(levelname)s in %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[TimedRotatingFileHandler("test.log", when="m", interval=1, backupCount=10, utc=True)],
)
logging.Formatter.converter = time.gmtime
logger = logging.getLogger(__name__)
logger.error("asdf")
当我多次 运行 脚本时,这是我在 test.log.2020-01-01_22-16
中发现的:
[2022-01-01 22:15:46] ERROR in __main__: asdf
[2022-01-01 22:15:55] ERROR in __main__: asdf
[2022-01-01 22:16:06] ERROR in __main__: asdf
[2022-01-01 22:16:14] ERROR in __main__: asdf
[2022-01-01 22:16:15] ERROR in __main__: asdf
[2022-01-01 22:16:45] ERROR in __main__: asdf
[2022-01-01 22:16:56] ERROR in __main__: asdf
任何人都可以解释为什么 test.log.2020-01-01_22-15
根本不存在,而我认为存在于其中的记录却在 22:16
日志中找到了吗?
编辑:我发现只有整整一分钟没有记录任何内容时才会生成新文件。我能以某种方式实现我想要的吗?
的确,TimedRotatingFileHandler
documentation 是这么说的:
When computing the next rollover time for the first time (when the handler is created), the last modification time of an existing log file, or else the current time, is used to compute when the next rotation will occur.
TimedRotatingFileHandler.__init__
:
if os.path.exists(filename):
t = os.stat(filename)[ST_MTIME]
else:
t = int(time.time())
它适用于长期 运行ning 应用程序。如果您想要让您的 short-运行ning 应用程序具有相同的行为,您将不得不编写一些自定义代码。
尽可能多地重复使用 TimedRotatingFileHandler
,我们可以利用修改时间作弊。
import logging
from logging.handlers import TimedRotatingFileHandler
import time
import datetime
import os
import re
import stat
def cheat_logfile_mtime():
filename = "test.log"
with open(filename, "rt") as logfile:
first_line = logfile.readline().rstrip()
pattern = re.compile(r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})]") # [2022-01-03 16:06:07]
match = pattern.match(first_line)
assert match is not None
logline_datetime_str = match.group(1)
local_timezone = datetime.datetime.now().astimezone().tzinfo
logline_datetime = datetime.datetime.fromisoformat(logline_datetime_str).replace(tzinfo=datetime.timezone.utc).astimezone()
file_mtime_datetime = datetime.datetime.fromtimestamp(os.stat(filename)[stat.ST_MTIME], tz=local_timezone)
now = datetime.datetime.now(tz=local_timezone)
one_minute_delta = datetime.timedelta(minutes=1)
if now - file_mtime_datetime < one_minute_delta < now - logline_datetime:
# the logfile was last modified less than one minute ago, but was first written more than one minute ago
os.utime("test.log", (logline_datetime.timestamp(), logline_datetime.timestamp()))
print("cheating the file mtime")
cheat_logfile_mtime()
logging.basicConfig(
format="[%(asctime)s] %(levelname)s in %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[TimedRotatingFileHandler("test.log", when="m", interval=1, backupCount=10, utc=True)],
)
logging.Formatter.converter = time.gmtime
logger = logging.getLogger(__name__)
logger.error("asdf")
这如您所愿:无论您启动应用程序多少次,日志文件都不会包含超过 1 分钟的实际日志。我每秒用 1 运行 测试它,在旋转之前在文件中得到 ~59 行。
它似乎尊重用户时区(我目前在 CET)。但它要求能够可靠地读写修改时间,这在网络驱动器或其他条件下可能无法实现。