How can Laravel 5's logging be changed to Monolog\Handler\BrowserConsoleHandler
?
What doesn't work in Laravel 5 but does work in a standalone PHP file:
use Illuminate\Support\Facades\Log;
use Monolog\Handler\BrowserConsoleHandler;
use Monolog\Logger;
// create a log channel
$log = Log::getMonolog();
// $log = new Logger('Testlogger'); //doesn't make any difference
$log->pushHandler(new BrowserConsoleHandler(\Psr\Log\LogLevel::INFO));
// add records to the log
$log->addWarning('Foo');
$log->addError('Bar');
All that happens is that my logs appear in the logfile but don't find their way to the browser. If I try the code in a single PHP file without framework it works, so I assume it's a Laravel problem.
I get it working with Firebug and FirePHP installed and $log->pushHandler(new FirePHPHandler());
instead of BrowserConsoleHandler
but this is not a solution since it sends the logs with headers but I already sent some debug-echos when the logger wants to send the headers.BrowserConsoleHandler
on the other hand adds a JavaScript snippet to the end of the site that perfectly fits my needs.
So, did anyone succeed in adding BrowserConsoleHandler
to Laravel's logging? How?
After reading plenty of source code and getting xdebug to work I finally figuered it out:
BrowserConsoleHandler
sends the script snipped after finishing the php script by register_shutdown_function()
. At this time, Laravel already sent the full response to the browser. So the script snipped from BrowseConsoleHandler
gets generated but never sent to the browser.
As a workaround you can build your own Middleware
(http://laravel.com/docs/5.0/middleware) that invokes the code generation manually and adds it to the response before it gets sent.
Create app/Http/Middleware/LogBrowserConsole.php:
<?php
namespace App\Http\Middleware;
use Illuminate\Contracts\Routing\Middleware;
use Illuminate\Support\Facades\Log;
use Monolog\Handler\BrowserConsoleHandler;
class LogBrowserConsole implements Middleware {
public function handle($request, \Closure $next)
{
// add BrowserConsoleHandler to Laravel's Logger
$log = Log::getMonolog();
$log->pushHandler(new BrowserConsoleHandler(\Psr\Log\LogLevel::INFO));
// invokes all your stuff like it would do without the middleware but with the new logger
$response = $next($request);
// after the request is done we care about the log entries
$handlers = $log->getHandlers();
$scriptSnippet = "";
foreach($handlers as $handler){ // only handle BrowserConsoleHandler
if($handler instanceof BrowserConsoleHandler){
ob_start(); //start output buffer so we can save echo to variable
$handler->send(); // create the scriptSnipped
$scriptSnippet .= ob_get_clean();
}
}
// write scriptSnippet to end of response content
$content = $response->getContent();
$response->setContent($content.$scriptSnippet);
return $response;
}
}
Register the Middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
'log.browserconsole' => 'App\Http\Middleware\LogBrowserConsole'
];
and invoke your Controller with the Middleware in app/Http/routes.php:
Route::get('test', ['middleware' => 'log.browserconsole', 'uses'=>'TestController@test']);
Alternatively, if you want to use the Middleware
for every request you can add it to
protected $middleware = [
'App\Http\Middleware\LogBrowserConsole'
];
in app/Http/Kernel.php.
Your Route would look like Route::get('test', 'TestController@test');
Now, your Log::debug()
etc. messages get sent to the logfile (the default LogHandler is still available, you just added another) and the script snipped from BrowserConsoleHandler
gets built and sent to the browser with all your log items.
Keep in mind to eventually change the log level \Psr\LogLevel::INFO
in app/Http/Middleware/LogBrowserConsole to fit your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With