0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel 3のDBのクエリログを粛々と流す

Last updated at Posted at 2014-12-11

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.profiletrueか確認しているが、laravel.queryイベント自体がprofiletrueじゃないと発生しないので省略。

クエリログだけ別ファイルに書き込む

ここまで通常のログファイルに書き込んだが、ここまでくればクエリログだけ別ファイルにしたい。

あった。
Laravel4、特定のログを別ファイルにする
いつもお世話になっています。

useFiles()メソッドで変えるのかー
ま、Laravel3のLogクラスには無いのですが

Laravel3のログ書き込み先

/laravel/log.php
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のログには表示したくない

ブラウザで確認するとデバッグ用のプロファイラー
キャプチャ.PNG
にLOGとSQLタブでほぼ同じ内容が表示されている。
(そもそもプロファイラー上で確認できるSQLをログに残したかったのがスタートだから当然。)

SQLのログは多いし他のログが埋まるので、SQLのログ出力はプロファイラーに登録しない様に変更してみる。

プロファイラーのログ登録箇所/laravel/profiling/profiler.php

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;
});
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?