SQLのクエリをプロファイラーではなくログファイルで確認したい
Laravel 4のDBのクエリログを淡々と流す
前からしたかったことがちょうど投稿されていたので3用に編集してメモる。
同じく参照元Laravel 4 - logging SQL queries
Event::listen('laravel.query', function($query, $bindings, $time)
{
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding)
{
if ($binding instanceof \DateTime)
{
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
}
else if (is_string($binding))
{
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
Log::info($query . PHP_EOL . print_r($data, true));
});
変更箇所はイベント名の変更と引数の$name
が着火時になかったので削除。
あとログの出力が4では第2引数に配列を入れることができるが、3では無理なのでprint_r()
。ただし出力が縦長になるのでちょっと見難いか。
あとはapplication/config/database.php
を'profile' => true,
にしてやればいい。
Stack Overflow では丁寧にログ出力前にdatabase.profile
がtrue
か確認しているが、laravel.query
イベント自体がprofile
がtrue
じゃないと発生しないので省略。
クエリログだけ別ファイルに書き込む
ここまで通常のログファイルに書き込んだが、ここまでくればクエリログだけ別ファイルにしたい。
あった。
Laravel4、特定のログを別ファイルにする
いつもお世話になっています。
useFiles()
メソッドで変えるのかー
ま、Laravel3のLogクラスには無いのですが
Laravel3のログ書き込み先
public static function write($type, $message, $pretty_print = false)
{
$message = ($pretty_print) ? print_r($message, true) : $message;
// If there is a listener for the log event, we'll delegate the logging
// to the event and not write to the log files. This allows for quick
// swapping of log implementations for debugging.
if (Event::listeners('laravel.log'))
{
Event::fire('laravel.log', array($type, $message));
}
$message = static::format($type, $message);
File::append(path('storage').'logs/'.date('Y-m-d').'.log', $message);
}
/stroge/logs/日付.log
に書きこんでいる。
1日毎にローテーションしてくれるのは嬉しいけどlogsディレクトリまで指定されている。
Log
クラスを継承してwrite()
をオーバライドしてパスだけ変えれば良さそうな感じだが、妥協してpath('storage')
を変更して/storage/sql/logs/日付.log
に吐き出す。
出力先を変更したクエリログ
Event::listen('laravel.query', function($query, $bindings, $time)
{
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding)
{
if ($binding instanceof \DateTime)
{
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
}
else if (is_string($binding))
{
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
$path = path('storage');
set_path('storage', $path . 'sql' . DS);
Log::info($query . PHP_EOL . print_r($data, true));
set_path('storage', $path);
});
path()
,set_path()
は/paths.php
にある。
$GLOBALS['laravel_paths']['storage']
を書き換えしているだけ。
あとは/storage/sql
と/storage/sql/logs
ディレクトリを用意してやるだけだけど、存在チェックや無いなら作成などを追加するかいつも悩んでいる。
今回は手動で作成しておく。
消したりしないし元のwrite()
もチェックしてないし。
後はブラウザからアクセスしてログが作成されているか確認する。
profilerのログには表示したくない
ブラウザで確認するとデバッグ用のプロファイラー
にLOGとSQLタブでほぼ同じ内容が表示されている。
(そもそもプロファイラー上で確認できるSQLをログに残したかったのがスタートだから当然。)
SQLのログは多いし他のログが埋まるので、SQLのログ出力はプロファイラーに登録しない様に変更してみる。
public static function attach()
{
// First we'll attach to the query and log events. These allow us to catch
// all of the SQL queries and log messages that come through Laravel,
// and we will pass them onto the Profiler for simple storage.
Event::listen('laravel.log', function($type, $message)
{
Profiler::log($type, $message);
});
Event::listen('laravel.query', function($sql, $bindings, $time)
{
Profiler::query($sql, $bindings, $time);
});
// We'll attach the profiler to the "done" event so that we can easily
// attach the profiler output to the end of the output sent to the
// browser. This will display the profiler's nice toolbar.
Event::listen('laravel.done', function($response)
{
echo Profiler::render($response);
});
}
Log::write()
のEvent::fire('laravel.log')
をここで受け取ってる。
幸いにもEvent::fire('laravel.log')
するにはif (Event::listeners('laravel.log'))
とイベントの登録確認があるので、一時的に消してしまえばいい。
ただし、イベントの削除はあるが取得が無いのでプロパティから直接取得する。
Event::listen('laravel.query', function($query, $bindings, $time)
{
$data = compact('bindings', 'time', 'name');
// Format binding data for sql insertion
foreach ($bindings as $i => $binding)
{
if ($binding instanceof \DateTime)
{
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
}
else if (is_string($binding))
{
$bindings[$i] = "'$binding'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
$event = Event::$events['laravel.log'];
Event::clear('laravel.log');
$path = path('storage');
set_path('storage', $path . 'sql' . DS);
Log::info($query . PHP_EOL . print_r($data, true));
set_path('storage', $path);
Event::$events['laravel.log'] = $event;
});