【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
tornado源代码分析
打开site-packages/tornado/log.py,最开头的注释文档说明了tornado的日志模块是直接和logging模块集成的
"""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. """
其中一共用到了三种被命名的logger
access_log = logging.getLogger("tornado.access")
app_log = logging.getLogger("tornado.application")
gen_log = logging.getLogger("tornado.general")
access_log 用于记录每一个访问请求
app_log 用于记录程序运行过程中,所有未被处理的异常
gen_log 用于记录tornado自己运行过程中报的错误和警告
自定义访问日志格式
先看下tornado的源代码,access_log是在tornado.web.RequestHandler中调用的,打开site-packages/tornado/web.py, 日志是在请求完成时调用log_request完成的
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()来决定的
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格式了,下面是我自己写的一个BaseHandler
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文件夹需要手动建立
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)
来源:oschina
链接:https://my.oschina.net/u/111188/blog/795743