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 には抜けているようなので作ってみたところです。


コメントやシェアをお願いします!