3

MySQL バックエンドに接続された SQLAlchemy で Pyramid Web フレームワークを使用しています。私がまとめたアプリは機能しますが、強化されたログ記録と例外処理によって、洗練されたものを追加しようとしています。

セッションを次のように使用して、Pyramid サイトの基本的な SQLAlchemy チュートリアルにすべて基づいています。

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

DBSession を使用してクエリを実行するとうまくいきます。データベースに何かを追加してコミットする必要がある場合は、次のようにします。

DBSession.add(myobject)
DBSession.flush()

というわけで新しいIDを取得。

次に、データベースにログを追加したかったので、このチュートリアルに従いました。それはうまくいったようです。私は最初、物事がコミットされるという奇妙なことに遭遇しました.SQLAlchemyがどのように機能しているのかわからなかったので、ログを強制的にコミットするために「transaction.commit()」を「DBSession.flush()」に変更しました(これは対処されています下!)。

次に、明示的にキャッチされなかったものすべてに分かりやすいエラー ページを配置してログに記録できるようにする目的で、カスタムの例外処理を追加したいと考えました。したがって、このドキュメントに基づいて、次のようなエラーハンドラーを作成しました。

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() を使用しない限り、例外でコミットしていません。

すっごい....データベースにログを記録するだけでなく、例外をキャッチしてデータベースに正常に記録できるようにするには、どのように設定すればよいでしょうか? ロギングハンドラーに、ある種の別のデータベースセッション/接続/インスタンス/何かを使用して自己完結型にしたい気がしますが、それがどのように機能するかは不明です。

それとも、まったく別の方法でやりたいことを設計する必要がありますか?

編集:私は、コミットログ情報をデータベースに追加することだけに特化した、別のログ固有のセッションを使用することになりました。これは、私が Pyramid コンソール スクリプトをミックスに統合し始めるまで、うまく機能しているように見えました。スクリプト内のセッションとデータベース コミットの問題に遭遇しました。実際の Pyramid Web アプリケーションのように機能するとは限りません。

後から考えると (そして私が今していること)、データベースにログを記録する代わりに、標準のログ記録と FileHandlers (具体的には TimedRotatingFileHandlers) を使用して、ファイル システムにログを記録します。

4

1 に答える 1

2

を使用transaction.commit()すると、他のモデルへの変更もコミットされるという意図しない副作用がありますが、これはあまりクールではありません - ZopeTransactionExtension を使用した「通常の」Pyramid セッション設定の背後にある考え方は、単一のセッションがリクエストの開始時に開始されるというものです。すべてが成功するとセッションがコミットされ、例外が発生した場合はすべてがロールバックされます。このロジックを維持し、リクエストの途中で手動でコミットすることは避けたほうがよいでしょう。

(補足として - DBSession.flush() はトランザクションをコミットせず、SQL ステートメントを発行しますが、トランザクションは後でロールバックできます)

例外ログのようなものについては、Pyramid の要求/応答サイクル (ZopeTransactionExtension なし) にバインドされていない別のセッションをセットアップし、それを使用してログ レコードを作成することを検討します。ログ レコードを追加した後、トランザクションを手動でコミットする必要があります。

record = Log("blah")
log_session.add(record)
log_session.commit()
于 2013-02-14T06:44:53.333 に答える