【问题标题】:Write header to a python log file, but only if a record gets written将标头写入 python 日志文件,但前提是写入记录
【发布时间】:2015-11-01 22:54:27
【问题描述】:
fh = logging.FileHandler('example.log',delay = True)
fh.setLevel(logging.INFO)

由于延迟为 True,除非记录某些内容,否则永远不会写入文件。 此时,文件中的第一行是第一条记录,它将包含 asctime、levelname 等元素

使用 python 2.7.10,是否有一种理智的方法可以在第一次写入不包含这些元素的记录时添加一行(或两行)?

我可以在使用它进行日志记录之前写入文件,但如果我这样做,我最终会得到空的日志,但对于标题。

所需的输出可能如下所示:

Using test.fil with option 7
2015-11-01 13:57:58,045 :log_example: INFO     fn:main result:process 4 complete --7 knights said ni
2015-11-01 13:57:58,045 :log_example: INFO     fn:main result:process 3 complete --3 bunnies attacked

谢谢,

【问题讨论】:

  • 我的想法立即转向了对 logging.Formatter 进行子类化,并在写入第一条消息后让 Formatter 本质上改变其格式。至少如果您正在寻找想法,我会从这里开始。

标签: python logging


【解决方案1】:

子类 FileHandler 来创建你自己的自定义 FileHandleWithHeader 如下所示:

import os
import logging

# Create a class that extends the FileHandler class from logging.FileHandler
class FileHandlerWithHeader(logging.FileHandler):

    # Pass the file name and header string to the constructor.
    def __init__(self, filename, header,  mode='a', encoding=None, delay=0):
        # Store the header information.
        self.header = header

        # Determine if the file pre-exists
        self.file_pre_exists = os.path.exists(filename)

        # Call the parent __init__
        logging.FileHandler.__init__(self, filename, mode, encoding, delay)

        # Write the header if delay is False and a file stream was created.
        if not delay and self.stream is not None:
            self.stream.write('%s\n' % header)

    def emit(self, record):
        # Create the file stream if not already created.
        if self.stream is None:
            self.stream = self._open()

            # If the file pre_exists, it should already have a header.
            # Else write the header to the file so that it is the first line.
            if not self.file_pre_exists:
                self.stream.write('%s\n' % self.header)

        # Call the parent class emit function.
        logging.FileHandler.emit(self, record)

# Create a logger and set the logging level.
logger = logging.getLogger("example")
logger.setLevel(logging.INFO)

# Create a file handler from our new FileHandlerWith Header class and set the
# logging level.
fh = FileHandlerWithHeader('example.log', 'This is my header',  delay=True)
fh.setLevel(logging.INFO)

# Add formatter to the file handler.
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
fh.setFormatter(formatter)

# Add the handler to the logger.
logger.addHandler(fh)

# Since the constructor of the FileHandlerWithHeader was passed delay=True
# the file should not exist until the first log as long as the log file did
# not pre-exist.
print "Ready to write to the the example.log file."
raw_input("Press Enter to continue...")

# Send 3 logs to the logger.
logger.info("First line in the file")
logger.info("Second line in the file")
logger.info("Third line in the file")

# The log file should now be created and only have a header at the begining of
# the file.
print "The example.log file should exist and have a header."

这个脚本应该在 Python 2.7 中运行。如果“example.log”文件已经存在,则不会重新创建头文件。

此解决方案需要了解 here 中找到的日志记录源代码 以及找到here的python日志包的一般用途。

【讨论】:

    【解决方案2】:

    我有一个更简单的想法。以下仅使用自定义格式化程序。格式化的第一条消息会吐出一个标头记录,然后再进行正常格式化。

    import logging
    
    class FormatterWithHeader(logging.Formatter):
        def __init__(self, header, fmt=None, datefmt=None, style='%'):
            super().__init__(fmt, datefmt, style)
            self.header = header # This is hard coded but you could make dynamic
            # Override the normal format method
            self.format = self.first_line_format
    
        def first_line_format(self, record):
            # First time in, switch back to the normal format function
            self.format = super().format
            return self.header + "\n" + self.format(record)
    
    def test_logger():
        logger = logging.getLogger("test")
        logger.setLevel(logging.DEBUG)
        formatter = FormatterWithHeader('First Line Only')
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(formatter)
        logger.addHandler(ch)
        logger.info("This line will kick out a header first.")
        logger.info("This line will *not* kick out a header.")
    

    【讨论】:

    • 这和 Joshua 的解决方案在不同的情况下都有优点。如果无论脚本运行多少次,标题都只会出现在文件的开头,那么 Joshua 的会是最好的。罗伯特的回答会在每次运行脚本时显示一个标题,即使它附加到现有日志,这更适合我的目的——尽管我一开始并没有想到这样做
    • 我无法在 python 2.7.16 上运行此代码:我将超级指令从 super() 修改为 super(FormatterWithHeader, self),但仍然出现 TypeError。这可能是因为logging.Formatter 是一个老式的类,但事实并非如此。我很迷茫
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 2022-08-17
    • 2022-07-06
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多