首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >我应该如何在Python语言中链接HTTPHandler和RotatingFileHandler?

我应该如何在Python语言中链接HTTPHandler和RotatingFileHandler?
EN

Stack Overflow用户
提问于 2018-07-11 06:05:45
回答 1查看 746关注 0票数 0

我需要创建一个系统,在这个系统中,嵌入式系统中生成的日志消息被远程记录在服务器上,并存储在轮换的日志文件中。由于网络通信的限制,日志消息必须通过HTTP协议进行传输。该服务器已经运行了一个基于Flask的超文本传输协议服务器,因此我想将日志系统与基于Flask的web应用程序集成在一起。

Python logging模块为此提供了专用的HTTPhandler类。基于logging文档,我已经创建了第一个实现。

服务器部分:

代码语言:javascript
复制
from flask import Flask
from flask import Response
from flask import request
import logging
import logging.handlers
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'logging server'

@app.route('/log', methods=['POST'])
def handle_log():
    if request.method == 'POST':
       rd=request.form.to_dict()
       record = logging.makeLogRecord(rd)
       log1.handle(record)
       return "OK"

log1=logging.getLogger('MTEST')
log1.setLevel(logging.DEBUG)
fh=logging.handlers.RotatingFileHandler('logs','a',maxBytes=10000000,backupCount=10)
formatter = logging.Formatter('%(asctime)s %(name)-15s %(levelname)-8s %(message)s')
rfh.setFormatter(formatter)
log1.addHandler(rfh)
log1.error("First error generated locally")
app.run()

客户端部分:

代码语言:javascript
复制
import logging, logging.handlers
myLogger = logging.getLogger('MTEST')
myLogger.setLevel(logging.DEBUG)
httpHandler = logging.handlers.HTTPHandler('localhost:5000',url='/log',method="POST")
myLogger.addHandler(httpHandler)

myLogger.info('Small info message')
myLogger.debug('Small debug message')
myLogger.erro('Small error message')

然而,在该实现中,服务器报告了以下错误(我复制了四条几乎相同的错误消息中的一条),并且只记录了本地生成的错误消息。

代码语言:javascript
复制
Traceback (most recent call last):
  File "/usr/lib/python2.7/logging/handlers.py", line 76, in emit
    if self.shouldRollover(record):
  File "/usr/lib/python2.7/logging/handlers.py", line 156, in shouldRollover
    msg = "%s\n" % self.format(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 465, in format
    record.message = record.getMessage()
  File "/usr/lib/python2.7/logging/__init__.py", line 329, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting

我添加了打印传输到服务器的表单数据和创建的LogRecord对象的属性。看起来,args属性是作为空元组传输的,而不是创建的。为了解决这个问题,我修改了handle_log例程:

代码语言:javascript
复制
@app.route('/log', methods=['POST'])
def handle_log():
    if request.method == 'POST':
       rd=request.form.to_dict()
       rd['args']=""
       record = logging.makeLogRecord(rd)
       log1.handle(record)
       return "OK"

日志记录仍然不起作用,但是服务器产生的错误已经改变了:

代码语言:javascript
复制
Logged from file test1.py, line 9
127.0.0.1 - - [10/Jul/2018 23:52:51] "POST /log HTTP/1.0" 200 -
Traceback (most recent call last):
  File "/usr/lib/python2.7/logging/handlers.py", line 76, in emit
    if self.shouldRollover(record):
  File "/usr/lib/python2.7/logging/handlers.py", line 156, in shouldRollover
    msg = "%s\n" % self.format(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 467, in format
    record.asctime = self.formatTime(record, self.datefmt)
  File "/usr/lib/python2.7/logging/__init__.py", line 423, in formatTime
    ct = self.converter(record.created)
TypeError: a float is required

为了检查哪里出了问题,我添加了打印创建的LogRecord对象的过滤器:

代码语言:javascript
复制
from flask import Flask
from flask import Response
from flask import request
import logging
import logging.handlers
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'logging server'

@app.route('/log', methods=['POST'])
def handle_log():
    if request.method == 'POST':
       rd=request.form.to_dict()
       rd['args']=""
       record = logging.makeLogRecord(rd)
       log1.handle(record)
       return "OK"

class myflt(logging.Filter):
  def filter(self,rec):
    print(rec.__dict__)
    return 1

log1=logging.getLogger('MTEST')
log1.setLevel(logging.DEBUG)
rfh=logging.handlers.RotatingFileHandler('logs','a',maxBytes=10000000,backupCount=10)
formatter = logging.Formatter('%(asctime)s %(name)-15s %(levelname)-8s %(message)s')
rfh.setFormatter(formatter)
log1.addHandler(rfh)
log1.addFilter(myflt())
log1.error("First error generated locally")
app.run()

之后,我可以比较为本地生成的消息创建的LogRecord对象:

代码语言:javascript
复制
{'threadName': 'MainThread', 'name': 'MTEST', 'thread': 139678016341824, 'created': 1531259894.112536, 'process': 5595, 'processName': 'MainProcess', 'args': (), 'module': 'srv1', 'filename': 'srv1.py', 'levelno': 40, 'exc_text': None, 'pathname': 'srv1.py', 'lineno': 37, 'msg': 'First error generated locally', 'exc_info': None, 'funcName': '<module>', 'relativeCreated': 44.27504539489746, 'levelname': 'ERROR', 'msecs': 112.53595352172852}

以及对于远程生成的消息:

代码语言:javascript
复制
{'relativeCreated': u'12.3879909515', 'process': u'5597', 'module': u'test1', 'funcName': u'<module>', 'filename': u'test1.py', 'levelno': u'10', 'processName': u'MainProcess', 'lineno': u'9', 'msg': u'Small debug message', 'args': '', 'exc_text': u'None', 'name': u'MTEST', 'thread': u'140221336438592', 'created': u'1531259898.51', 'threadName': u'MainThread', 'msecs': u'511.312007904', 'pathname': u'test1.py', 'exc_info': u'None', 'levelname': u'DEBUG'}

看来,通过HTTPHandler传输日志记录会将所有数字转换为字符串,因此makeLogRecord函数无法在服务器中正确地重新创建LogRecord对象。

通过HTTPHandler传输日志消息的正确方式是什么,以便远程计算机中的RotatingFileHandler可以正确处理日志消息?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-11 06:28:23

我发现了一些东西,这似乎是一个可行的解决办法。在客户端创建的带有LogRecord对象属性的字典在传递到服务器之前被转换为JSON。然后,服务器对其进行解码并重新创建原始LogRecord

服务器部分:

代码语言:javascript
复制
from flask import Flask
from flask import Response
from flask import request
import logging
import logging.handlers
import json
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'logging server'

@app.route('/log', methods=['POST'])
def handle_log():
    if request.method == 'POST':
       rd=request.form.to_dict()
       rec=json.loads(rd['record'])
       record = logging.makeLogRecord(rec)
       log1.handle(record)
       return "OK"

class myflt(logging.Filter):
  def filter(self,rec):
    print(rec.__dict__)
    return 1

mfl=myflt()

log1=logging.getLogger('MTEST')
log1.setLevel(logging.DEBUG)
rfh=logging.handlers.RotatingFileHandler('logs','a',maxBytes=10000000,backupCount=10)
formatter = logging.Formatter('%(asctime)s %(name)-15s %(levelname)-8s %(message)s')
rfh.setFormatter(formatter)
log1.addHandler(rfh)
log1.addFilter(mfl)
log1.error("First error generated locally")
app.run()

客户端部分:

代码语言:javascript
复制
import logging, logging.handlers
import json

class myHTTPHandler(logging.handlers.HTTPHandler):
  def mapLogRecord(self,record):
    trec={'record':json.dumps(record.__dict__)}
    return trec

myLogger = logging.getLogger('MTEST')
myLogger.setLevel(logging.DEBUG)
httpHandler = myHTTPHandler('localhost:5000',url='/log',method="POST")
myLogger.addHandler(httpHandler)

myLogger.info('Small info message')
myLogger.debug('Small debug message')
myLogger.error('Small error message')

上面的实现是正确的,但是它看起来不必要的复杂。有没有更简单的方法来使用HTTPHandler通过HTTP协议与远程RotatingFileHandler通信?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51274534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档