2

There are two noisy console commands in my Laravel 5.3 app that I want to keep logs for but would prefer to have them write to a different log file from the rest of the system.

Currently my app writes logs to a file configured in bootstrap/app.php using $app->configureMonologUsing(function($monolog) { ...

Second prize is writing all console commands to another log file, but ideally just these two.

I tried following these instructions (https://blog.muya.co.ke/configure-custom-logging-in-laravel-5/ and https://laracasts.com/discuss/channels/general-discussion/advance-logging-with-laravel-and-monolog) to reroute all console logs to another file but it did not work and just caused weird issues in the rest of the code.

If this is still the preferred method in 5.3 then I will keep trying, but was wondering if there was newer method or a method to only change the file for those two console commands.

Rudolf Vavruch
  • 495
  • 2
  • 6
  • 13
  • 1
    I have never tried it but do you think this `Log::useFiles($path, $level)` could help? See: https://laravel.com/api/5.3/Illuminate/Log/Writer.html#method_useFiles – Wistar Nov 21 '16 at 16:06
  • @Wistar thanks for the suggestion, but that doesn't seem to make a difference. – Rudolf Vavruch Nov 21 '16 at 16:38
  • Others (see: http://stackoverflow.com/questions/32552450/laravel-how-to-log-info-to-separate-file) have report to be using this method. Have you tried what is suggested in the second answer? `Log::useDailyFiles(storage_path().'/logs/name-of-log.log');` `Log::info([info to log]);` – Wistar Nov 21 '16 at 16:43
  • @Wistar you are correct, I spoke too soon, it does work but it still writes to the original log file as well. – Rudolf Vavruch Nov 21 '16 at 16:54
  • That's probably because the default Monolog is called with `$app` before your code is executed. That results in all logs being stored in the default log file as well. One possibility is to override the default logging class. You could have a specific log file for let's say `Log::info()` and all the others logs could be written in your default file. See this: https://laracasts.com/discuss/channels/general-discussion/advance-logging-with-laravel-and-monolog . It's a bit more work – Wistar Nov 21 '16 at 17:05
  • Your solution should be in the answers not in the question – Wistar Nov 21 '16 at 17:55

2 Answers2

0

They are two approaches you could take

First, you could use Log::useFiles or Log::useDailyFiles like suggests here.

Log::useDailyFiles(storage_path().'/logs/name-of-log.log'); 
Log::info([info to log]);

The downside of this approach is that everything will still be log in your default log file because the default Monolog is executed before your code.

Second, to avoid to have everything in your default log, you could overwrite the default logging class. An exemple of this is given here. You could have a specific log file for let's say Log::info() and all the others logs could be written in your default file. The obvious downside of this approach is that it requires more work and code maintenance.

Community
  • 1
  • 1
Wistar
  • 3,770
  • 4
  • 45
  • 70
0

This is possible but first you need to remove existing handlers.

Monolog already has had some logging handlers set, so you need to get rid of those with $monolog->popHandler();. Then using Wistar's suggestion a simple way of adding a new log is with $log->useFiles('/var/log/nginx/ds.console.log', $level='info');.

public function fire (Writer $log)
{
    $monolog = $log->getMonolog();
    $monolog->popHandler();

    $log->useFiles('/var/log/nginx/ds.console.log', $level='info');
    $log->useFiles('/var/log/nginx/ds.console.log', $level='error');
    ...

For multiple handlers

If you have more than one log handler set (if for example you are using Sentry) you may need to pop more than one before the handlers are clear. If you want to keep a handler, you need to loop through all of them and then readd the ones you wanted to keep.

$monolog->popHandler() will throw an exception if you try to pop a non-existant handler so you have to jump through hoops to get it working.

public function fire (Writer $log)
{
    $monolog = $log->getMonolog();

    $handlers = $monolog->getHandlers();
    $numberOfHandlers = count($handlers);
    $saveHandlers = [];

    for ($idx=0; $idx<$numberOfHandlers; $idx++)
    {
        $handler = $monolog->popHandler();

        if (get_class($handler) !== 'Monolog\Handler\StreamHandler')
        {
            $saveHandlers[] = $handler;
        }
    }

    foreach ($saveHandlers as $handler)
    {
        $monolog->pushHandler($handler);
    }

    $log->useFiles('/var/log/nginx/ds.console.log', $level='info');
    $log->useFiles('/var/log/nginx/ds.console.log', $level='error');
    ...

For more control over the log file, instead of $log->useFiles() you can use something like this:

$logStreamHandler = new \Monolog\Handler\StreamHandler('/var/log/nginx/ds.console.log');

$pid = getmypid();

$logFormat = "%datetime% $pid [%level_name%]: %message%\n";
$formatter = new \Monolog\Formatter\LineFormatter($logFormat, null, true);
$logStreamHandler->setFormatter($formatter);

$monolog->pushHandler($logStreamHandler);
Community
  • 1
  • 1
Rudolf Vavruch
  • 495
  • 2
  • 6
  • 13