打開site-packages/tornado/log.py,最開頭的註釋文檔說明了tornado的日誌模塊是直接和logging模塊集成的python
"""Logging support for Tornado. Tornado uses three logger streams: * ``tornado.access``: Per-request logging for Tornado's HTTP servers (and potentially other servers in the future) * ``tornado.application``: Logging of errors from application code (i.e. uncaught exceptions from callbacks) * ``tornado.general``: General-purpose logging, including any errors or warnings from Tornado itself. These streams may be configured independently using the standard library's `logging` module. For example, you may wish to send ``tornado.access`` logs to a separate file for analysis. """
其中一共用到了三種被命名的loggerweb
access_log = logging.getLogger("tornado.access") app_log = logging.getLogger("tornado.application") gen_log = logging.getLogger("tornado.general")
access_log 用於記錄每個訪問請求app
app_log 用於記錄程序運行過程當中,全部未被處理的異常ide
gen_log 用於記錄tornado本身運行過程當中報的錯誤和警告tornado
先看下tornado的源代碼,access_log是在tornado.web.RequestHandler中調用的,打開site-packages/tornado/web.py, 日誌是在請求完成時調用log_request完成的post
def log_request(self, handler): """Writes a completed HTTP request to the logs. By default writes to the python root logger. To change this behavior either subclass Application and override this method, or pass a function in the application settings dictionary as ``log_function``. """ if "log_function" in self.settings: self.settings["log_function"](handler) return if handler.get_status() < 400: log_method = access_log.info elif handler.get_status() < 500: log_method = access_log.warning else: log_method = access_log.error request_time = 1000.0 * handler.request.request_time() log_method("%d %s %.2fms", handler.get_status(), handler._request_summary(), request_time)
其中的日誌格式是由handler._request_summary()來決定的this
def _request_summary(self): return "%s %s (%s)" % (self.request.method, self.request.uri, self.request.remote_ip)
所以咱們只須要繼承tornado.web.RequestHandler,而後重寫_request_summary就能夠配置本身的access_log格式了,下面是我本身寫的一個BaseHandlerspa
class BaseHandler(tornado.web.RequestHandler): def __init__(self, application, request, **kwargs): super(BaseHandler, self).__init__(application, request) self._operator_name = 'NO_LOGIN' def _request_summary(self): if self.request.method == 'post': return "%s %s (%s@%s)" % (self.request.method, self.request.uri, self._operator_name, self.request.remote_ip) return "%s %s %s(%s@%s)" % (self.request.method, self.request.uri, self.request.body.decode(), self._operator_name, self.request.remote_ip)
BaseHandler重寫了_request_summary,並給日誌增長了操做者信息和遠端IP信息日誌
一個logging.yaml例子,這裏只配置了tornado.access,其中的logs文件夾須要手動創建code
version: 1 loggers: root: level: DEBUG handlers: [console] tornado: level: DEBUG handlers: [console,log] propagate: no tornado.access: level: DEBUG handlers: [console, access] propagate: no log: level: DEBUG handlers: [console,log] propagate: no formatters: simple: format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' timedRotating: format: '%(asctime)s %(name)-12s %(levelname)-8s - %(message)s' handlers: console: class: logging.StreamHandler level: DEBUG formatter: simple access: class: logging.handlers.TimedRotatingFileHandler level: DEBUG formatter: simple filename: 'logs/access.log' when: 'midnight' interval: 1 backupCount: 180 log: class: logging.handlers.TimedRotatingFileHandler level: DEBUG formatter: timedRotating filename: 'logs/log.log' when: 'midnight' interval: 1 backupCount: 180 encoding: 'utf8'
tornado初始化以前記得初始化log配置
log_config = yaml.load(open('logging.yaml', 'r')) logging.config.dictConfig(log_config)