Python日志记录 - 将日期设置为文件名

时间:2017-08-01 19:22:44

标签: python logging

我正在努力在我的Python项目中实现日志记录,并且遇到了一些障碍。我正在尝试设置我的日志记录,以便处理程序和格式化程序都组织到一个配置文件中。我现在要做的是设置我的fileHandler,以便创建一个类似于这样的日志文件:YYYY_MM_DD.log显然Y代表年份,M代表月份,D代表着这一天。

这是我尝试使用我的配置文件:

[loggers]
keys=root,MainLogger

[handlers]
keys=fileHandler, consoleHandler

[formatters]
keys=logFormatter, consoleFormatter

[logger_root]
level=DEBUG
handlers=fileHandler

[logger_MainLogger]
level=DEBUG
handlers=fileHandler, consoleHandler
qualname=MainLogger
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=consoleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=logFormatter
args=(datetime.now().strftime('%Y_%m_%d.log'), 'a')

[formatter_logFormatter]
format=%(asctime)s | %(levelname)-8s | %(lineno)04d | %(message)s

[formatter_consoleFormatter]
format=%(asctime)s | %(levelname)-8s | %(fillname)s-%(funcName)s-%(lineno)04d | %message)s

我用来测试配置的文件非常简单:

import logging
import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('MainLogger')
logger.debug("TEST")

我目前得到的具体错误是:

configparser.InterpolationSyntaxError: '%' must be followed by '%' or '(', found: "%Y_%m_%d.log'), 'a')"

我已尝试更改%Y%m%d,因为错误说明了,但这并不能解决问题。我如何设置配置文件,以便我的日志文件看起来像我想要的那样?

我应该注意当我将文件名更改为test.log时一切正常,所以这是我似乎唯一的错误。

10 个答案:

答案 0 :(得分:4)

您无法在配置文件中使用datetime,因为它不知道它的含义。但是,您可以在python文件中添加Filehandler

import logging.config
from datetime import datetime

logging.config.fileConfig('aaa.conf')
logger = logging.getLogger('MainLogger')

fh = logging.FileHandler('{:%Y-%m-%d}.log'.format(datetime.now()))
formatter = logging.Formatter('%(asctime)s | %(levelname)-8s | %(lineno)04d | %(message)s')
fh.setFormatter(formatter)

logger.addHandler(fh)
logger.debug("TEST")

这样您就可以在处理程序中将日期设置为文件名。

这是配置文件,请注意您在上一个格式化程序中输入了拼写错误,您放置了fillname而不是filename而忘记了(中的message。< / p>

[loggers]
keys=root,MainLogger

[handlers]
keys=consoleHandler

[formatters]
keys=consoleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_MainLogger]
level=DEBUG
handlers=consoleHandler
qualname=MainLogger
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=consoleFormatter
args=(sys.stdout,)

[formatter_consoleFormatter]
format=%(asctime)s | %(levelname)-8s | %(filename)s-%(funcName)s-%(lineno)04d | %(message)s

这应该可以正常工作。

答案 1 :(得分:4)

这对我有用。

更新此: args =(datetime.now()。strftime(&#39;%Y_%m_%d.log&#39;),&#39; a&#39;)

args =(__ import __(&#34; datetime&#34;)。datetime.now()。strftime(&#39;%Y_%m_%d.log&#39;),&#39; a&#39; ;)

参考(例3):http://python-reference.readthedocs.io/en/latest/docs/functions/eval.html

答案 2 :(得分:3)

也许您可以使用Python TimedRotatingFileHandler代替。您可以设置每天创建新日志文件的时间间隔,并将日期作为后缀。

文档 -

请注意,当天的日志文件没有日期。此文件处理程序仅在新的一天开始时添加日期后缀。

此外,它使用的后缀是&#34;%Y-%m-%d&#34;,这与您想要的略有不同。但是有一个关于如何改变它的问题here

答案 3 :(得分:1)

也许在之后尝试更改名称​​您已加载配置文件:

from datetime inport datetime

logging.config.fileConfig('logging.conf')
logging.basicConfig(filename = datetime.now().strftime('%Y_%m_%d.log'))

答案 4 :(得分:1)

在格式字符串中使用双'%'字符与Abhishek建议的方法结合使用,得出了我的情况下可行的解决方案(Python 3.5):

然后,配置文件中的文件处理程序应类似于此文件处理程序:

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=defaultFormatter
args=(__import__("datetime").datetime.now().strftime('/your_path/your_file_name_%%Y-%%m-%%d_%%H-%%M-%%S.log'), 'a')

答案 5 :(得分:1)

我想通过配置文件保持我所有的日志可配置,并且对这里通过代码手动添加处理程序的答案不满意。我想出的解决方案是创建一个继承 FileHandler 的处理程序类,它在调用 FileHandler 构造函数之前将日期附加到文件名参数:

import os
from logging import FileHandler
from datetime import datetime

class TimestampedFileHandler(FileHandler):
    def __init__(self, filename, mode='a', encoding=None, delay=False):
        filename, extension = os.path.splitext(filename)
        filename = f"{filename}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}{extension}"
        FileHandler.__init__(self, filename, mode, encoding, delay)

然后,您可以在配置文件中使用 TimestampedFileHandler,并与其他处理程序一起设置其级别、格式化程序和参数。

答案 6 :(得分:0)

这使用配置文件中的内容,但不直接访问该文件。您可以创建自己的文件处理程序,然后将其添加到记录器中。

import logging
from datetime import datetime

# Create logger.
logger = logging.getLogger('MainLogger')
logger.setLevel(logging.DEBUG)

# Create filehandler with desired filename.
fh = logging.FileHandler('{}.log'.format(datetime.now().strftime('%Y_%m_%d')))
fh.setLevel(logging.DEBUG)
log_formatter = logging.Formatter('%(asctime)s | %(levelname)-8s | %(lineno)04d | %(message)s')
fh.setFormatter(log_formatter)

# Add filehandler to logger.
logger.addHandler(fh)

请注意,a(append)是FileHandler的默认mode参数。

答案 7 :(得分:0)

这也有效

from dateime import datetime
log_file = str(datetime.utcnow().strftime('%m_%d_%Y_%I_%M_%S')) + '.log'
logging.basicConfig(filename=log_file, format='%(levelname)s | %(asctime)s | %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.DEBUG)

日志文件名称:04_30_2018_10_03_01.log

答案 8 :(得分:0)

这篇文章很老,但是对于仍在为logging.conf动态命名文件名而困扰的任何人 在调用logging.config.fileConfig()时,您可以传递变量并在日志配置文件中使用它们。 例如:

  

logging.conf

args=('my_log_%(date)s.log','w')
  

python.py

import logging.conf
logging.conf.fileConfig('logging.conf', defaults={'date':datetime.now()}

您可能想在此处使用日期格式。

以相同的方式,可以使用任意数量的变量。

答案 9 :(得分:0)

我对python产品的解决方案是保留配置文件的路径到固定日志文件,例如:

[handler_fileHandler] <br>
class=FileHandler <br>
level=DEBUG <br>
formatter=defaultFormatter <br>
args=('../projectnamespace/data/logs/logfile.log',)

并且每天我都会将日志文件移动到较旧的文件夹日志中,这样可以避免拥有庞大的日志文件供以后阅读...。

log_path = str((Path(__file__).parent / 'data' / 'logs' / 'logfile.log').absolute())

log_file_date_created = None 
if platform.system() == 'Windows':
    log_file_date_created = datetime.fromtimestamp(os.path.getctime(log_path))
else:
    stat = os.stat(log_path)
    try:
        log_file_date_created = stat.st_birthtime
    except AttributeError:
        # running in Linux. No easy way to get creation dates here,
        # we get when its content was last modified.
        return stat.st_mtime

if log_file_date_created != None and abs(datetime.today().day - log_file_date_created.day) >= 1:
    file_date = str(log_file_date_created.strftime("%m_%d_%Y")) + '_logfile.log'
    log_path_new_name = str((Path(__file__).parent / 'data' / 'logs' / 'older' /  file_date ).absolute())
    os.replace(log_path, log_path_new_name)