Laravel 4 - 记录SQL查询

eri*_*bae 34 php laravel

关于在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);
});
Run Code Online (Sandbox Code Playgroud)

我只是得到"select*from my_table where id =?" 作为没有实际填充ID值的日志消息.

如果我使用

$queries = DB::getQueryLog();
$last_query = end($queries);
Log::error(print_r($last_query, true));
Run Code Online (Sandbox Code Playgroud)

我仍然没有填充ID的最终SQL查询.

最后,如果我使用像https://github.com/loic-sharma/profiler这样的日志记录工具- 由于我正在制作AJAX请求,它不会显示任何内容.

我用尽了我的选择吗?还有另一种更好的方法吗?

Col*_*mes 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);
    });
}
Run Code Online (Sandbox Code Playgroud)

感谢Jeemusu回答有关将绑定插入预处理语句的问题.

  • 这可能是一个单独的问题......但是有没有办法我们可以记录不是所有的查询,而是我们想要的具体问题? (2认同)

Jee*_*usu 11

您应该能够通过传递$bindings作为Event函数的第二个参数来找到绑定.

Event::listen('illuminate.query', function($sql, $bindings, $time){
    echo $sql;          // select * from my_table where id=? 
    print_r($bindings); // Array ( [0] => 4 )
    echo $time;         // 0.58 

    // To get the full sql query with bindings inserted
    $sql = str_replace(array('%', '?'), array('%%', '%s'), $sql);
    $full_sql = vsprintf($sql, $bindings);
});
Run Code Online (Sandbox Code Playgroud)

在Laravel 3.x中,我认为事件监听器被调用了 laravel.query


Mar*_*lln 9

继续@Collin詹姆斯回答.

如果你只想为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);
    });
}
Run Code Online (Sandbox Code Playgroud)

将它放在文件的顶部:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
Run Code Online (Sandbox Code Playgroud)

这会将您的所有查询记录到名为的文件sql-YYYY-mm-dd.logstorage/logs/.


Mat*_*röm 6

虽然接受的答案是正确的,但这个答案解释了如何在使用jQuery发出Ajax请求时更新loic-sharma探查器.使用这种方法,不需要读取文件日志.

步骤1

第一个问题是在每个Ajax请求上将更新的探查器数据发送到客户端.这可以使用Laravel应用程序的"after"事件来解决.

应用程序/ 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);
    }
});
Run Code Online (Sandbox Code Playgroud)

App::after过滤器将在每次Laravel要求运行.上面闭包的第一行确保只有在响应类型为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;
    }
});
Run Code Online (Sandbox Code Playgroud)

这是用新的方法替换旧的探查器的方法:

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);
};
Run Code Online (Sandbox Code Playgroud)

使用它

现在它就像返回响应一样简单:

return Response::json(array(
    'user' => Auth::user()
));
Run Code Online (Sandbox Code Playgroud)

Laravel将追加探查器HTML.javascript将捕获JSON响应并更新DOM.您将在网页上获得SQL查询和计时.

注意

在测试代​​码时,可能存在一两个错误.这也不是我怎么做的.我没有在json响应中发送HTML,而是使用分析器中的实际数据扩展对象.在客户端,我使用胡子模板渲染探查器.