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

我只是得到“从 id= 的 my_table 中选择 *?” 作为没有实际填充 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 回答
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);
});

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

于 2013-10-02T07:41:37.413 回答
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.login的文件中storage/logs/

于 2014-04-23T07:37:18.323 回答
6

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

步骤1

第一个问题是在每个 Ajax 请求上将更新的分析器数据发送到客户端。这可以使用 Laravel 应用程序的“之后”事件来解决。

应用程序/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::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;
    }
});

这是一种用新的分析器替换旧分析器的方法:

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。您将在网页上获得 SQL 查询和计时。

笔记

在测试代​​码时,可能会有一两个错误。这也不完全是我的做法。我没有在 json 响应中发送 HTML,而是使用来自分析器的实际数据扩展对象。在客户端,我使用mustache 模板呈现分析器。

于 2013-10-03T16:43:20.923 回答
2

虽然这个问题最初是针对 Laravel 4 的,但我仍然通过谷歌来到这里,但我使用的是 Laravel 5。

有一些新方法可以使用 Middleware 在 Laravel 5 中记录所有查询,但是如果您更喜欢这里的相同方法,这里是Collin James提供的相同代码,但适用于 Laravel 5

if (Config::get('database.log', false))
{
    Event::listen('Illuminate\Database\Events\QueryExecuted', function($query)
    {
        $bindings = $query->bindings;
        $time = $query->time;
        $name = $query->connection->getName();
        $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->sql);
        $query = vsprintf($query, $bindings);

        Log::info($query, $data);
    });
}
于 2016-05-03T16:16:45.833 回答
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 回答