DBIx::Class で sql_maker が生成した SQL をロギングする方法
DBIC いろいろ使って検証を続けているのですが、O/R Mapper って当たり前だけど万能じゃぁないなぁ〜とすごく思う今日この頃。正直、リレーションとか張りまくってる場合、自前で JOIN とか View 定義して書いた方が遙かに効率の良い SQL が記述できる。
複雑な SQL を表現するには、O/R Mapper だと逆に見づらいなぁ〜と思ったり。
とはいえ、単純な SQL の場合はやはり便利。コードも見た目、OO っぽくてかっこいいし。
でも、どうにも解析できなかったことが一つ。DBIC しか見てないんですが、sql_maker が生成した SQL をロギングする方法がわかりません。なんかコードを深追いしていくと、
に行き着いちゃいます。でもよけいなデバッグ情報多すぎで使い物にならないので、ちょっとした Hack で実現。
メンドウなので、モジュールにしてなくってとってつけたような感じで実現。たとえば、Catalyst だと MyApp.pm で
use UNIVERSAL::require; our $REGISTER_FLG = 0; 〜中略〜 __PACKAGE__->setup; &_register_dbi_logging() unless($REGISTER_FLG); sub _register_dbi_logging { my $log_yaml = helpdesk->path_to('log.yml'); no strict 'refs'; my $superclass = DBIx::Class::Storage::DBI->can('_execute'); *{"DBIx::Class::Storage::DBI::_execute"} = sub { my ($self, $op, $extra_bind, $ident, @args) = @_; my ($sql, @bind) = $self->sql_maker->$op($ident, @args); Log::Dispatch::Config->require or die $@; Log::Dispatch::Configurator::YAML->require or die $@; my $yaml = Log::Dispatch::Configurator::YAML->new($log_yaml); Log::Dispatch::Config->configure($yaml); my $log = Log::Dispatch::Config->instance; $sql = qq{"$sql ",}; map { $sql .= qq{"$_",}; } @bind; $log->info($sql); &$superclass(@_); }; $REGISTER_FLG = 1; }
なんて感じで、実装しちゃいました。
ログ設定は、Log::Dispatch::Config と Log::Dispatch::Configurator::YAML 使って設定しています。
ロギングは DBIx::Class::Storage::DBI::_execute を上書きしてロギング機能を追加して、元々のメソッドを call するなんてよく使う?姑息なやり方です。
これで、SQL が execute される度に勝手にロギングされていくので、アプリ側でロギングについて考える必要は無くなります。何かあったときにログから調査。そんな考えが DBIC には抜けているようなので作ってみたところです。
コメントやシェアをお願いします!