35

Laravel 4 で SQL クエリをログに記録することに関して、すでにいくつかの質問があります。しかし、私はそれらのほとんどすべてを試しましたが、まだ思い通りに動作していません。

これが私の状況です

  1. 私のphpビューファイルで、サーバーにAJAXリクエストを行います
  2. AJAX リクエストが受信され、RAW パラメータ化された Postgres SQL クエリが実行されます (例:

    DB::select('select * from my_table where id=?', array(1))

私が使用する場合

Event::listen('illuminate.query', function($sql)
{
  Log::error($sql);
});

「select * from my_table where id=?」というメッセージが表示されます。ID 値が実際に入力されていないログ メッセージとして。

私が使用する場合

$queries = DB::getQueryLog();
$last_query = end($queries);
Log::error(print_r($last_query, true));

ID が入力された最終的な SQL クエリがまだありません。

最後に、 https://github.com/loic-sharma/profilerのようなログ ツールを使用すると、AJAX リクエストを行っているため、何も表示されません。

オプションを使い果たしましたか?他にもっと良い方法はありますか?

4

6 に答える 6

56

SQLクエリのロギングに現在使用しているものは次のとおりです。これをメインのルート ファイルにドロップしてから、'log' => true をデータベース構成に追加できるはずです。

if (Config::get('database.log', false))
{           
    Event::listen('illuminate.query', function($query, $bindings, $time, $name)
    {
        $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, $data);
    });
}

プリペアド ステートメントへのバインディングの挿入について、Jeemusu の回答に感謝します。

于 2013-10-05T02:40:32.760 に答える
9

@Collin Jamesの回答を続けます。

SQL専用の別のファイルにログを記録したい場合は、次のようにすることができます:

if (Config::get('database.log', false)) {
    Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
        $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 = new Logger('sql');
        $log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Y-m-d') . '.log', Logger::INFO));

        // add records to the log
        $log->addInfo($query, $data);
    });
}

これをファイルの先頭に置きます:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

これにより、すべてのクエリが という名前のファイルに記録さsql-YYYY-mm-dd.logstorage/logs/ます。

于 2014-04-23T07:37:18.323 に答える
6

受け入れられた回答は正しいですが、この回答では、 jQuery を使用して Ajax リクエストを行うときにloic-sharma プロファイラーを更新する方法について説明しています。このアプローチを使用すると、ファイル ログを読み取る必要がなくなります。

ステップ1

最初の問題は、Ajax 要求ごとに更新されたプロファイラー データをクライアントに送信することです。これは、Laravel アプリケーションの「after」イベントを使用して解決できます。

app/filters.php:

App::after(function($request, $response)
{
    // If it's a JsonResponse and the profiler is enabled, include it in the response.
    if($response instanceof \Illuminate\Http\JsonResponse && Profiler::isEnabled()) {

        $profiler = Profiler::getFacadeRoot();
        $profilerJson = json_encode($profiler->render());
        $content = substr($response->getContent(), 0, -1) . ',"profiler":' . $profilerJson . '}';
        $response->setContent($content);
    }
});

フィルターは、App::afterLaravel リクエストごとに実行されます。上記のクロージャーの最初の行は、応答が JsonResponse 型で、プロファイラーが有効な場合にのみ続行することを確認します。その場合は、プロファイラーをレンダリングし、HTML を JSON オブジェクトに追加します。

注: このコードは、返された JSON がオブジェクトであることを前提としています。したがって、配列では失敗します: Response::json(array(1,2,3)).

ステップ2

更新されたプロファイラー HTML がクライアントに送信されるようになったので、JavaScript を使用して新しいプロファイラー HTML で DOM を更新する必要があります。これは、クライアントが JSON 応答を受け取るたびに発生するはずです。jQuery は、これを実現するのに最適なグローバル Ajax イベント ハンドラーを提供します。

$(document).ajaxSuccess(function(event, request, settings) {
    try {
        json = jQuery.parseJSON(request.responseText);
        if(json.profiler) {
            renderProfiler(json.profiler);
        }
    } catch(error) {
        // Its not JSON.
        return;
    }
});

古いプロファイラーを新しいものに置き換える方法は次のとおりです。

renderProfiler = function(data) {
    // Remove previous 
    $anbu = $('.anbu');
    $anbu.prev().remove(); // Removes <style> tag of profiler
    $anbu.next().next().remove(); // Removes the inline script tag of profiler
    $anbu.next().remove(); // Removes jQuery script tag by the profiler
    $anbu.remove(); // Removes the <div> tag of profiler
    $(document.body).append(data);
};

それを使用する

次のように応答を返すのと同じくらい簡単です。

return Response::json(array(
    'user' => Auth::user()
));

Laravel はプロファイラーの HTML を追加します。JavaScript は JSON 応答をキャッチし、DOM を更新します。Web ページで SQL クエリとタイミングを確認できます。

ノート

コードがテストされている間、1 つまたは 2 つのバグが存在する可能性があります。これも私のやり方ではありません。JSON 応答で HTML を送信する代わりに、プロファイラーからの実際のデータでオブジェクトを拡張します。クライアント側では、口ひげのテンプレートを使用してプロファイラーをレンダリングします。

于 2013-10-03T16:43:20.923 に答える
1

それが私が使ってきたものです:

DB::listen(function ($query, $bindings, $time, $connection) {
    $fullQuery = vsprintf(str_replace(array('%', '?'), array('%%', '%s'), $query), $bindings);
    $result = $connection . ' (' . $time . '): ' . $fullQuery;

    dump($result);
    // You can of course log the $result
});
于 2015-10-10T00:54:00.073 に答える