Python 日志 HTTPHandler 在 Django 中的断管错误
我在用Python的HTTPHandler把信息发送到一个客户的Django应用时遇到了一些问题。我有一个单独的守护进程,它是我基础设施的一部分,我希望它能把日志推送到Django,这样我就能把所有东西放在一个地方。
我使用的环境是:
- Ubuntu 10.04
- Django 1.2.4
- PostgreSQL 8.4
- Python 2.6.5
这是模型:
from django.db import models
# Create your models here.
class application(models.Model):
app_name = models.CharField(max_length= 20)
description = models.CharField(max_length = 500, null=True)
date = models.DateField()
def __unicode__(self):
return ("%s logs - %s") % (self.app_name, self.date.strftime("%d-%m-%Y"))
class log_entry(models.Model):
application = models.ForeignKey(application)
thread_name = models.CharField(max_length = 200,null = True)
name = models.CharField(max_length = 200,null = True)
thread = models.CharField(max_length=50, null = True)
created = models.FloatField(null = True)
process = models.IntegerField(null = True)
args = models.CharField(max_length = 200,null = True)
module = models.CharField(max_length = 256,null = True)
filename = models.CharField(max_length = 256,null = True)
levelno = models.IntegerField(null = True)
msg = models.CharField(max_length = 4096,null = True)
pathname = models.CharField(max_length = 1024,null = True)
lineno = models.IntegerField(null = True)
exc_text = models.CharField(max_length = 200, null = True)
exc_info = models.CharField(max_length = 200, null = True)
func_name = models.CharField(max_length = 200, null = True)
relative_created = models.FloatField(null = True)
levelname = models.CharField(max_length=10,null = True)
msecs = models.FloatField(null = True)
def __unicode__(self):
return self.levelname + " - " + self.msg
这是视图:
# Create your views here.
from django.shortcuts import render_to_response, get_list_or_404, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from inthebackgroundSite.log.models import log_entry, application
import datetime
@csrf_exempt
def log(request):
print request.POST
for element in request.POST:
print ('%s : %s') % (element, request.POST[element])
data = request.POST
today = datetime.date.today()
print today
app = application.objects.filter(app_name__iexact = request.POST["name"], date__iexact=today)
if not app:
print "didnt find a matching application. adding one now.."
print data["name"]
print today
app = application.objects.create(app_name = data["name"],
description = None,
date = today)
app.save()
if not app:
print "after save you cant get at it!"
newApplication = app
print app
print "found application"
newEntry = log_entry.objects.create(application = app,
thread_name = data["threadName"] ,
name = data["name"],
thread = data["thread"],
created = data["created"],
process = data["process"],
args = "'" + data["args"] + "'",
module = data["module"],
filename = data["filename"],
levelno = data["levelno"],
msg = data["msg"],
pathname = data["pathname"],
lineno = data["lineno"],
exc_text = data["exc_text"],
exc_info = data["exc_info"],
func_name = data["funcName"],
relative_created = data["relativeCreated"],
levelname = data["levelname"],
msecs = data["msecs"],
)
print newEntry
#newEntry.save()
return HttpResponse("OK")
这是在Python代码中发送消息的调用:
import os
import logging
import logging.handlers
import time
if __name__ == '__main__':
formatter = logging.Formatter("%(name)s %(levelno)s %(levelname)s %(pathname)s %(filename)s%(module)s %(funcName)s %(lineno)d %(created)f %(asctime)s %(msecs)d %(thread)d %(threadName)s %(process)d %(processName)s %(message)s ")
log = logging.getLogger("ShoutGen")
#logLevel = "debug"
#log.setLevel(logLevel)
http = logging.handlers.HTTPHandler("192.168.0.5:9000", "/log/","POST")
http.setFormatter(formatter)
log.addHandler(http)
log.critical("Finished MountGen init")
time.sleep(20)
http.close()
第一次我发送消息时,表是空的,运行得很好,创建了一个新的应用行和一条新的日志消息。但是第二次调用时,我却遇到了:
<QueryDict: {u'msecs': [u'224.281072617'], u'args': [u'()'], u'name': [u'ShoutGen'], u'thread': [u'140445579720448'], u'created': [u'1299046203.22'], u'process': [u'16172'], u'threadName': [u'MainThread'], u'module': [u'logtest'], u'filename': [u'logtest.py'], u'levelno': [u'50'], u'processName': [u'MainProcess'], u'pathname': [u'logtest.py'], u'lineno': [u'19'], u'exc_text': [u'None'], u'exc_info': [u'None'], u'funcName': [u'<module>'], u'relativeCreated': [u'7.23600387573'], u'levelname': [u'CRITICAL'], u'msg': [u'Finished MountGen init']}>
msecs : 224.281072617
args : ()
name : ShoutGen
thread : 140445579720448
created : 1299046203.22
process : 16172
threadName : MainThread
module : logtest
filename : logtest.py
levelno : 50
processName : MainProcess
pathname : logtest.py
lineno : 19
exc_text : None
exc_info : None
funcName : <module>
relativeCreated : 7.23600387573
levelname : CRITICAL
msg : Finished MountGen init
2011-03-02
[sql] SELECT ...
FROM "log_application"
WHERE (UPPER("log_application"."date"::text) = UPPER(2011-03-02)
AND UPPER("log_application"."app_name"::text) = UPPER(ShoutGen))
[sql] (5.10ms) Found 1 matching rows
[<application: ShoutGen logs - 02-03-2011>]
found application
[sql] SELECT ...
FROM "log_log_entry" LIMIT 21
[sql] (4.05ms) Found 2 matching rows
[sql] (9.14ms) 2 queries with 0 duplicates
[profile] Total time to render was 0.44s
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/django/core/servers/basehttp.py", line 281, in run
self.finish_response()
File "/usr/local/lib/python2.6/dist-packages/django/core/servers/basehttp.py", line 321, in finish_response
self.write(data)
File "/usr/local/lib/python2.6/dist-packages/django/core/servers/basehttp.py", line 417, in write
self._write(data)
File "/usr/lib/python2.6/socket.py", line 300, in write
self.flush()
File "/usr/lib/python2.6/socket.py", line 286, in flush
self._sock.sendall(buffer)
error: [Errno 32] Broken pipe
而且在log_log_entry表中没有插入额外的行。所以我现在真的不知道为什么会发生这种情况。
我查了一下,似乎“Broken pipe traceback”并不是问题,只是浏览器会出现的情况。但我并没有使用浏览器,所以不太确定问题出在哪里。
1 个回答
0
可能是因为出现了异常,导致事务回滚,从而撤销了你的更改。你有没有使用 TransactionMiddleware
?你可以试试在你的视图上加上 transaction.autocommit
装饰器。
如果“断管”错误一直出现,那就值得找找原因。HTTPHandler
会正常发送一个 POST 请求,并在 emit()
调用中等待响应(也就是你视图返回的“OK”),在这之前连接不应该断开。
你可以尝试用一个测试脚本向你的视图发送一个类似的 POST 请求,使用 httplib
和 urllib
,就像 HTTPHandler
自己做的那样。基本上,就是把一个字典进行 URL 编码,作为 POST 数据,就像处理 LogRecord
的字典一样。