2013-02-12 59 views
3

我正在使用SQLAlchemy的Pyramid web框架,连接到MySQL后端。我已经放在一起的应用程序工作,但我试图通过一些增强的日志记录和异常处理来添加一些波兰语。使用SQLAlchemy进行金字塔异常日志记录 - 未提交的命令

我基于事事休金字塔现场基本SQLAlchemy的教程,使用像这样的会议:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) 

使用DBSession到查询的伟大工程,如果我需要添加一些东西,并提交到数据库我会做类似

DBSession.add(myobject) 
DBSession.flush() 

所以我得到我的新ID。

然后我想添加日志到数据库,所以我跟着this tutorial。这似乎很好。我最初遇到了一些奇怪的事情,并且我不确定SQLAlchemy是如何工作的,所以我已经将“transaction.commit()”更改为“DBSession.flush()”来强制日志提交(这已得到解决下面!)。

接下来,我想添加自定义异常处理的意图,我可以把一个友好的错误页面,为任何未明确捕获并仍然记录的东西。因此,基于this documentation我创建的错误处理程序,如下所示:

from pyramid.view import (
    view_config, 
    forbidden_view_config, 
    notfound_view_config 
    ) 

from pyramid.httpexceptions import (
    HTTPFound, 
    HTTPNotFound, 
    HTTPForbidden, 
    HTTPBadRequest, 
    HTTPInternalServerError 
    ) 

from models import DBSession 

import transaction 
import logging 

log = logging.getLogger(__name__) 

#region Custom HTTP Errors and Exceptions 
@view_config(context=HTTPNotFound, renderer='HTTPNotFound.mako') 
def notfound(request): 
    log.exception('404 not found: {0}'.format(str(request.url))) 
    request.response.status_int = 404 
    return {} 

@view_config(context=HTTPInternalServerError, renderer='HTTPInternalServerError.mako') 
def internalerror(request): 
    log.exception('HTTPInternalServerError: {0}'.format(str(request.url))) 
    request.response.status_int = 500 
    return {} 

@view_config(context=Exception, renderer="HTTPExceptionCaught.mako") 
def error_view(exc, request): 
    log.exception('HTTPException: {0}'.format(str(request.url))) 
    log.exception(exc.message) 

    return {} 
#endregion 

所以现在我的问题是,异常被捕获和我的自定义除外图如预期出现。但是异常不会记录到数据库中。看起来这是因为DBSession事务在任何异常情况下回滚。所以我将日志处理程序改回“transaction.commit”。这具有实际上将我的异常日志提交到数据库的效果,但是现在任何日志语句之后的任何DBSession操作都会抛出“未绑定到会话的实例”错误......这是有道理的,因为根据我在transaction.commit ()会话被清除。控制台日志始终显示我想要记录的内容,包括将日志信息写入数据库的SQL语句。但是,除非我使用transaction.commit(),否则它不会提交异常,但如果我这样做,那么我会在transaction.commit()!之后终止任何DBSession语句。

Sooooo ....我该如何设置,以便我可以登录到数据库,但也捕获并成功地将异常记录到数据库中?我觉得我想让日志处理程序使用某种单独的数据库会话/连接/实例/东西,以便它是自包含的,但我不清楚这可能如何工作。

或者我应该设计一些我想完全不同的东西?

编辑: 我确实结束了一个单独的,特定于日志的会话,专门用于将提交日志信息添加到数据库。这似乎工作得很好,直到我开始将Pyramid控制台脚本集成到组合中,其中我遇到了脚本中的会话和数据库提交问题,而不一定像在实际的Pyramid Web应用程序中那样工作。

事后(我正在做什么)而不是记录到数据库我使用标准日志记录和FileHandlers(特定的TimedRotatingFileHandlers)并登录到文件系统。

回答

2

使用transaction.commit()也会对其他模型的更改产生意想不到的副作用,这并不太酷 - 使用ZopeTransactionExtension的“普通”金字塔会话设置背后的想法是,单个会话从开始时开始请求,那么如果一切都成功,那么会话被提交,如果有异常,那么所有事情都会回滚。保持这种逻辑并避免在请求中手动提交事情会更好。

(作为一个侧面说明 - DBSession.flush()不提交事务,它发出的SQL语句,但成交可稍后推出)

类的东西异常的记录,我想看看设置建立一个单独的会话,该会话不受金字塔的请求/响应周期(没有ZopeTransactionExtension)的约束,然后使用它创建日志记录。添加日志记录后,您需要手动提交交易:

record = Log("blah") 
log_session.add(record) 
log_session.commit() 
+0

谢谢!这是我认为可能工作的方向。你提到没有绑定到ZopeTransactionExtension,但它是值得在日志处理程序本身创建一个新的会话,类似于 LogSession = scoped_session(sessionmaker(extension = ZopeTransactionExtension())) 但保持ZTE自回滚行为仍然可能有用?或者中兴通讯与请求周期无关? – 2013-02-14 15:53:51

+1

我必须错过一些东西,但我不明白如果您尝试记录错误,在出现错误时如何回滚事务可能会有用。 – Sergey 2013-02-14 23:49:44