简体   繁体   English

在python中带有时间戳的自定义记录器

[英]Custom logger with time stamp in python

I have lots of code on a project with print statements and wanted to make a quick a dirty logger of these print statements and decided to go the custom route. 我在一个带有打印语句的项目中有很多代码,想要快速创建这些打印语句的肮脏记录器,并决定采用自定义路线。 I managed to put together a logger that prints both to the terminal and to a file (with the help of this site), but now I want to add a simple time stamp to each statement and I am running into a weird issue. 我设法将一个记录器打印到终端和文件上(在此站点的帮助下),但是现在我想为每个语句添加一个简单的时间戳,并且遇到了一个奇怪的问题。

Here is my logging class. 这是我的测井课程。

class Logger(object):
    def __init__(self, stream):
        self.terminal = stream
        self.log = open("test.log", 'a')

    def write(self, message):
        self.terminal.flush()
        self.terminal.write(self.stamp() + message)
        self.log.write(self.stamp() + message)

    def stamp(self):
        d = datetime.today()
        string = d.strftime("[%H:%M:%S] ")
        return string

Notice the stamp method that I then attempt to use in the write method. 请注意然后尝试在write方法中使用的stamp方法。

When running the following two lines I get an unexpected output: 运行以下两行时,我得到意外的输出:

sys.stdout = Logger(sys.stdout)
print("Hello World!")

Output: 输出:

[11:10:47] Hello World![11:10:47]

This what the output also looks in the log file, however, I see no reason why the string that I am adding appends to the end. 这也是输出在日志文件中显示的内容,但是,我看不出我要添加的字符串附加到末尾的原因。 Can someone help me here? 有人可以帮我吗?

UPDATE See answer below. 更新请参见下面的答案。 However, for quicker reference the issue is using "print()" in general; 但是,为了便于参考,该问题通常使用“ print()”。 replace it with sys.stdout.write after assigning the variable. 分配变量后,将其替换为sys.stdout.write。

Also use "logging" for long-term/larger projects right off the bat. 对于长期/较大的项目,也请立即使用“日志记录”。

It calls the .write() method of your stream twice because in cpython print calls the stream .write() method twice. 它调用.write()你流的方法两次,因为在CPython的print调用流.write()方法的两倍。 The first time is with the object, and the second time it writes a newline character. 第一次与对象在一起,第二次它与对象写入换行符。 For example look at line 138 in the pprint module in cpython v3.5.2 例如,查看cpython v3.5.2中pprint模块中的第138行

def pprint(self, object):
    self._format(object, self._stream, 0, 0, {}, 0)
    self._stream.write("\n")  # <- write() called again!

You can test this out: 您可以测试一下:

>>> from my_logger import Logger  # my_logger.py has your Logger class
>>> import sys
>>> sys.stdout = Logger(stream=sys.stdout)
>>> sys.stdout.write('hi\n')
[14:05:32] hi

You can replace print(<blah>) everywhere in your code using sed . 您可以使用sed在代码中的任何地方替换print(<blah>)

$ for mymodule in *.py; do
> sed -i -E "s/print\((.+)\)/LOGGER.debug(\1)/" $mymodule
> done

Check out Python's Logging builtin module . 查看Python的Logging内置模块 It has pretty comprehensive logging including inclusion of a timestamp in all messages format. 它具有非常全面的日志记录,包括以所有消息格式包含时间戳。

import logging
FORMAT = '%(asctime)-15s %(message)s'
DATEFMT = '%Y-%m-%d %H:%M:%S'
logging.basicConfig(format=FORMAT, datefmt=DATEFMT)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

logger.debug('message: %s', 'message')

This outputs 2016-07-29 11:44:20 message: message to stdout . 这将输出2016-07-29 11:44:20 message: messagestdout There are also handlers to send output to files. 还有一些处理程序可以将输出发送到文件。 There is a basic tutorial , an advanced tutorial and a cookbook of common logging recipes . 有一个基本的教程 ,一个高级的教程和一个常用的日志记录食谱

There is an example of using simultaneous file and console loggers in the cookbook. 食谱中有一个同时使用文件和控制台记录器的示例。

import logging

LOGGER = logging.getLogger(__name__)  # get logger named for this module
LOGGER.setLevel(logging.DEBUG)  # set logger level to debug

# create formatter
LOG_DATEFMT = '%Y-%m-%d %H:%M:%S'
LOG_FORMAT = ('\n[%(levelname)s/%(name)s:%(lineno)d] %(asctime)s ' +
              '(%(processName)s/%(threadName)s)\n> %(message)s')
FORMATTER = logging.Formatter(LOG_FORMAT, datefmt=LOG_DATEFMT)

CH = logging.StreamHandler()  # create console handler
CH.setLevel(logging.DEBUG)  # set handler level to debug
CH.setFormatter(FORMATTER)  # add formatter to ch
LOGGER.addHandler(CH)  # add console handler to logger

FH = logging.FileHandler('myapp.log')  # create file handler
FH.setLevel(logging.DEBUG)  # set handler level to debug
FH.setFormatter(FORMATTER)  # add formatter to fh
LOGGER.addHandler(FH)  # add file handler to logger

LOGGER.debug('test: %s', 'hi')

This outputs: 输出:

[DEBUG/__main__:22] 2016-07-29 12:20:45 (MainProcess/MainThread)
> test: hi

to both console and file myapp.log simultaneously. 同时访问控制台和文件myapp.log

You probably need to use newline character. 您可能需要使用换行符。

class Logger(object):
    def __init__(self, stream):
        self.terminal = stream
        self.log = open("test.log", 'a')

    def write(self, message):
        self.terminal.flush()
        self.terminal.write(self.stamp() + message + "\n")
        self.log.write(self.stamp() + message + "\n")

    def stamp(self):
        d = datetime.today()
        string = d.strftime("[%H:%M:%S] ")
        return string

Anyway, using built-in logging module will be better. 无论如何,使用内置的日志记录模块会更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM