web.py中使用wsgilog 打印日志

web.py中使用wsgilog打印日志

web.py中使用我们常规的log方式会出现一些问题,例如,如下代码会在log日志中打印两行记录,具体原因可能和web.py框架内部实现有关。

#!/usr/bin/env python
# encoding: utf-8

import sys
import json
import pickle
import traceback

import web

urls = (
  '/ad_word_pv', 'AdWordPV',

def getFileRotatingLog(logFilePath, logLevel="info"):
    '''
    生成n个相同大小的日志文件. 
    '''
    logger = None
    logger = logging.getLogger()
    if logLevel == "debug":
        logger.setLevel(logging.DEBUG)
    else:   
        logger.setLevel(logging.INFO)
    rh = logging.handlers.RotatingFileHandler(logFilePath, 'a', 10*1024*1024, 5)
    formatStr = "[%(asctime)s] %(filename)s:%(lineno)d(%(funcName)s): [%(levelname)s] %(message)s"
    format = logging.Formatter(formatStr)
    rh.setFormatter(format)
    logger.addHandler(rh)
    return logger
    
logger = getFileRotatingLog("logs/svr.log", "info")

web.config.debug = True

class AdWordPV:
    def __init__(self,):
        pass

    def GET(self):
        logger.info("request word pv") # 将在日志文件中输出两行一模一样的日志 #
        resp = {}
        return json.dumps( resp )   

if __name__ == "__main__": 
    app = web.application(urls, globals())
    web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr)
    app.run() 



在web.py中打印日志一般使用的是 wsgilog 模块。

wsgilog的使用网上资料较少,这里简单介绍一下wsgilog在我的项目中的使用。

wsgilog是python的一个模块,可以从 https://pypi.python.org/pypi/wsgilog/ 下载进行安装。

下面介绍在 web.py 中如何使用 wsgilog 打印日志,具体是参考 http://webpy.org/cookbook/logging 和分析wsgilog源码得到的结果。

在wsgilog的安装包文件 wsgilog-0.3/wsgilog/__init__.py 可以看到 WsgiLog 这个类的定义。

import pdb
import sys
import logging
from cgitb import html
from logging.handlers import HTTPHandler, SysLogHandler
from logging.handlers import TimedRotatingFileHandler, SMTPHandler
__all__ = ['WsgiLog', 'log']
# File rotation constants
BACKUPS = 1
INTERVAL = 'h'
# Default logger name (should be changed)
LOGNAME = 'wsgilog.log'
# Default 'environ' entries
CATCHID = 'wsgilog.catch'
LOGGERID = 'wsgilog.logger'
# Current proposed 'environ' key signalling no middleware exception handling
THROWERR = 'x-wsgiorg.throw_errors'
# HTTP error messages
HTTPMSG = '500 Internal Error'
ERRORMSG = 'Server got itself in trouble'
# Default log formats
DATEFORMAT = '%a, %d %b %Y %H:%M:%S'
LOGFORMAT = '%(name)s: %(asctime)s %(levelname)-4s %(message)s'
def _errapp(environ, start_response):
    '''Default error handling WSGI application.'''
    start_response(HTTPMSG, [('Content-type', 'text/plain')], sys.exc_info())
    return [ERRORMSG]
def log(**kw):
    '''Decorator for logging middleware.'''
    def decorator(application):
        return WsgiLog(application, **kw)
    return decorator
class WsgiLog(object):
    '''Class for WSGI logging and event recording middleware.'''
    def __init__(self, application, **kw):
        self.application = application
        # Error handling WSGI app
        self._errapp = kw.get('errapp', _errapp)
        # Flag controlling logging
        self.log = kw.get('log', True)
        # Log if set
        if self.log:
            # Log error message
            self.message = kw.get('logmessage', ERRORMSG)
            # Individual logger for WSGI app with custom name 'logname'
            self.logger = logging.getLogger(kw.get('logname', LOGNAME))
            # Set logger level
            self.logger.setLevel(kw.get('loglevel', logging.DEBUG))
            # Log formatter
            format = logging.Formatter(
                # Log entry format
                kw.get('logformat', LOGFORMAT),
                # Date format
                kw.get('datefmt', DATEFORMAT))
            # Coroutine for setting individual log handlers
            def setlog(logger):
                logger.setFormatter(format)
                self.logger.addHandler(logger)
            # Log to STDOUT
            if 'tostream' in kw:
                setlog(logging.StreamHandler())
            # Log to a rotating file that with periodic backup deletions
            if 'tofile' in kw:
                setlog(TimedRotatingFileHandler(
                    # Log file path
                    kw.get('file', LOGNAME),
                    # Interval to backup log file
                    kw.get('interval', INTERVAL),
                    # Number of backups to keep
                    kw.get('backups', BACKUPS)))
            # Send log entries to an email address
            if 'toemail' in kw:
                setlog(SMTPHandler(
                    # Mail server
                    kw.get('mailserver'),
                    # From email address
                    kw.get('frommail'),
                    # To email address
                    kw.get('toemail'),
                    # Email subject
                    kw.get('mailsubject')))
            # Send log entries to a web server
            if 'tohttp' in kw:
                setlog(HTTPHandler(
                    # Web server host
                    kw.get('httphost'),
                    # Web URL
                    kw.get('httpurl'),
                    # HTTP method
                    kw.get('httpmethod', 'GET')))
            # Log to syslog
            if 'tosyslog' in kw:
                setlog(SysLogHandler(
                    # syslog host
                    kw.get('syshost', ('localhost', 514)),
                    # syslog user
                    kw.get('facility', 'LOG_USER')))
            assert self.logger.handlers, 'At least one logging handler must be configured'
            # Redirect STDOUT to the logger
            if 'toprint' in kw:
                sys.stdout = LogStdout(self.logger,
                    # Sets log level STDOUT is displayed under
                    kw.get('prnlevel', logging.DEBUG))
        # Flag for turning on PDB in situ
        self.debug = kw.get('debug', False)
        # Flag for sending HTML-formatted exception tracebacks to the browser
        self.tohtml = kw.get('tohtml', False)
        # Write HTML-formatted exception tracebacks to a file if provided
        self.htmlfile = kw.get('htmlfile')

我们可以看到 tofile 表示将日志写入文件,同时可以看到 file, interval, backups, logformat, datefmt 等参数,wsgilog 写入日志到文件只支持每隔一段时间生成一个日志文件,即 TimeRotatingFileHandler。

我们一般这么使用 wsgilog:

首先定义一个类Log继承WsgiLog类,如下 MyLog.py 文件
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#

import sys, logging
from wsgilog import WsgiLog
import config

class Log(WsgiLog):
    def __init__(self, application):
        WsgiLog.__init__(
            self,
            application,
            logformat = config.logformat,
            datefmt = config.datefmt,
            tofile = True,
            file = config.file,
            interval = config.interval,
            backups = config.backups
            )

其中日志配置文件 config.py 如下

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#

import logging

file = "logs/webpy.log" # 日志文件路径 #
logformat = "[%(asctime)s] %(filename)s:%(lineno)d(%(funcName)s): [%(levelname)s] %(message)s" # 日志格式 #
datefmt = "%Y-%m-%d %H:%M:%S" # 日志中显示的时间格式 #
loglevel = logging.DEBUG
interval = "d" # 每隔一天生成一个日志文件#
backups = 3 # 后台保留3个日志文件 #


然后,我们在主程序中将Log类传入应用,在具体的程序中使用 web.ctx.environ['wsgilog.logger'].info( "xxx" ) 即可打印日志。

#!/usr/bin/env python
# encoding: utf-8

import sys
import json
import pickle
import traceback
import time

import web

urls = (
  '/ad_word_pv', 'AdWordPV',

print urls

web.config.debug = True

class AdWordPV:
    def __init__(self,):
        self.logger = web.ctx.environ['wsgilog.logger'] # 使用日志 #
        
    def GET(self):
        btime = time.time()
        self.logger.info("request word pv")
        resp = {"errcode":0, "data":[test]}
        etime = time.time()
        use_time = etime - btime
        self.logger.info("get word pv used %s seconds" % use_time)
        return json.dumps( resp )

if __name__ == "__main__": 
    from MyLog import Log
    app = web.application(urls, globals())
    web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr)
    app.run(Log) # 将Log类传入 #



阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页