#4 logging 增加 TRACE 级别日志

2020-05-21

logging 内部的服务级别:

DEBUG       10
INFO        20
WARNING     30
ERROR       40
CRITICAL    50

根据使用习惯,INFO 是重要信息,DEBUG 是普通信息。线上也是开到 DEBUG 级别。
然后调试信息也是通过 DEBUG 服务打印,然后通过 conf.DEBUG_MODE 来区分是不是要打印这种 DEBUG 级别的调试信息。

觉得不甚方便,想了一下,有两种思路:

  1. 将普通信息也通过 INFO 日志打印,在日志内容中插入部分标识来表示是重要信息,比如 “&NOTICE”。
  2. 增加一个 TRACE 级别日志。

方案一感觉相对合理一些,但是对于已有项目还是方案二好。

实现

def trace(self, message, *args, **kwargs):
    if self.isEnabledFor(TRACE):
        self._log(TRACE, message, args, **kwargs)


TRACE = logging.TRACE = 5
logging.addLevelName(TRACE, 'TRACE')
logging.Logger.trace = trace

参考:syslog 日志级别

  • EMERG:系统不可用
  • ALERT:需要立即采取行动
  • CRIT:关键错误
  • ERR:一般错误
  • WARNING:警告
  • NOTICE:一般通知
  • INFO:信息性消息
  • DEBUG:调试级别的消息

参考:nodejs winston 日志级别

  • error:错误
  • warn:警告
  • info:一般信息
  • http:HTTP 请求
  • verbose:详细信息
  • debug:调试信息
  • silly:非常详细的调试信息

参考:java log4j 日志级别

  • FATAL:致命
  • ERROR:错误
  • WARN:警告
  • INFO:信息
  • DEBUG:调试
  • TRACE:跟踪

#3 Requests 的日志配置

2019-08-09
import http.client
import logging

import requests

LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(asctime)s [%(thread)s] [%(name)s:%(funcName)s#%(lineno)d] %(levelname)s %(message)s'
logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT)

LOG_HTTP = logging.getLogger("http.client")

def httpclient_log(*args):
    LOG_HTTP.log(logging.DEBUG, " ".join(args))

http.client.print = httpclient_log
http.client.HTTPConnection.debuglevel = 1

#2 logging 时间格式

2017-03-12
import logging
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(asctime)s %(levelname)s %(message)s'
logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT)
logging.info('hello world')

默认时间格式是 yyyy-mm-dd hh:mm:ss,xxx,如果我们要改这个格式可以用 datefmt 参数,遵循 time.strftime 的格式化参数格式。

问题有一个,毫秒从哪里来?

方法一:使用 msecs 占位符

最简单的办法:在格式字符串中使用 msecs 占位符,比如:

import logging
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(asctime)s.%(msecs)03d %(levelname)s %(message)s'
LOG_DATEFMT = '%H:%M:%S'
logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT, datefmt=LOG_DATEFMT)
logging.info('hello world')

方法二:改用 datetime 对象

import logging
from datetime import datetime

class MyFormatter(logging.Formatter):
    converter = datetime.fromtimestamp

    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            # s = time.strftime(datefmt, ct)
            s = ct.strftime(datefmt)
        else:
            # t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s,%03d" % (t, record.msecs)
        return s

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
console = logging.StreamHandler()
logger.addHandler(console)
formatter = MyFormatter(fmt='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S.%f')
console.setFormatter(formatter)
logging.info('hello world')