Python logging 之 Handler

什么是Handler?

Handler instances dispatch logging events to specific destinations.

其实很简单, Handler决定了你的LogRecord最终出现的位置, 你的log信息是直接输出到终端(StreamHandler) 还是 保存到 log文件(FileHandler).

Handler是如何记录信息的?

常见的Handler就是我们常用的I/O操作, 类似于我们的print()以及file.write(), 以StreamHandler为例:

class StreamHandler(Handler):

    terminator = '\n'

    def __init__(self, stream=None):
        """
        Initialize the handler.

        If stream is not specified, sys.stderr is used.
        """
        Handler.__init__(self)
        if stream is None:
            stream = sys.stderr
        self.stream = stream
      
    def emit(self, record):
        """
        Emit a record.
        """
        try:
            msg = self.format(record)
            stream = self.stream
            stream.write(msg)
            stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)

log消息的输出是用emit()函数实现的, 本质就是sys.stderr.write(), 这样一看logging模块就非常简单了.

然后我们再看一下FileHandler的 emit():

class FileHandler(StreamHandler):
    """
    A handler class which writes formatted logging records to disk files.
    """
    def __init__(self, filename, mode='a', encoding=None, delay=False):

        if delay:
            #We don't open the stream, but we still need to call the
            #Handler constructor to set level, formatter, lock etc.
            Handler.__init__(self)
            self.stream = None
        else:
            StreamHandler.__init__(self, self._open())

    def emit(self, record):
        """
        Emit a record.
        """
        if self.stream is None:
            self.stream = self._open()
        StreamHandler.emit(self, record)

FileHandler继承自StreamHandler, 只是把stream替换为打开的文件, 所以我们的emit就变为了file.write().

flush()是做什么用的?

The internal buffers are buffers created by the runtime/library/language that you’re programming against and is meant to speed things up by avoiding system calls for every write. Instead, when you write to a file object, you write into its buffer, and whenever the buffer fills up, the data is written to the actual file using system calls.

当我们读写文件, 类似stdout或者是打开的文件, 我们的数据都在缓存中, flush保证将缓存中的数据写入文件, 这个操作一般在文件close()时自动执行.

Thread Safe

类似于读写文件的操作是位于临界区内, 多个线程同时操作会导致race condition, 所以在读写文件操作时, logging模块对这些操作进行了加锁:

    def flush(self):
        """
        Flushes the stream.
        """
        self.acquire()
        try:
            if self.stream and hasattr(self.stream, "flush"):
                self.stream.flush()
        finally:
            self.release()

总结

Handler作为logging模块中最常用的class之一, 通过了解其实现, 能够更好的帮助我们理解logging模块.

    原文作者:李宏杰0209
    原文地址: https://www.jianshu.com/p/d9621833c578
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞