4

I'm using configureMonologUsing() to add in two custom loggers. Doing the standard SOLID principal, I have two providers: ConsoleLoggerProvider and MailLogProvider.

Both of these have a register similar to:

public function register()
{
    app()->configureMonologUsing(function(\Monolog\Logger $monolog) {
        $monolog->pushHandler(new HandlerClass());
    });
}

However, I have noticed over logger will overwrite another logger... How do I stack these?

I've tried to use boot() as well, and that didn't work. I couldn't find any other way to add to the Monolog stack.

Preferable, I want to stack onto Laravel's built-in logger as well.

guice
  • 976
  • 4
  • 11
  • 31

4 Answers4

10

I (finally) found the answer my question:

Within my providers, instead of using configureMonologUsing(), I used Log::getMonolog()->pushHandler([..])

That works! All loggers, including built-in Laravel file logger, are firing. Finally!

(I've honestly been looking for days for a way to add onto the Monolog stack; I apparently wasn't searching by the right terms)

Boris Brdarić
  • 4,674
  • 2
  • 24
  • 19
guice
  • 976
  • 4
  • 11
  • 31
  • Here is the answer that uses the approach described in the docs: https://stackoverflow.com/a/57544771/470749 – Ryan Aug 18 '19 at 12:56
1

According to the Laravel documentation:

You should place a call to the configureMonologUsing method in your bootstrap/app.php file right before the $app variable is returned by the file.

In that case, thus should work for you: create two handler classes and add them to monolog this way (in your bootstrap/app.php):

$app->configureMonologUsing(function ($monolog) {
  $monolog->pushHandler(new EmailLogHandler);
  $monolog->pushHandler(new ConsoleLogHandler); 
}); 
return $app;
shalvah
  • 881
  • 10
  • 21
  • 3
    Only issue with this approach is it overwrites Laravel built-in logger, too. I just found another approach: using Log::getMonolog() instead of app() with configure using. That works, and retains Laravel's logger. – guice Jun 26 '17 at 23:38
  • Oh, yeah. Totally forgot about that. – shalvah Jun 26 '17 at 23:39
  • 1
    Please be careful never to link to "master" docs and instead link to versioned docs: https://laravel.com/docs/5.2/errors#configuration – Ryan Aug 18 '19 at 12:34
0

Following Laravel 5.2 docs, in bootstrap/app.php, I added the following code right before return $app;:

$app->configureMonologUsing(function($monolog) {//IMPORTANT: I think the order of pushHandler matters, and the ones defined last here will be the first to be called, which affects anything where bubble=false
    if (config('services.slack.send_errors_to_slack')) {
        $bubble = false; //I think that if I set the 'bubble' argument to false and handle the most severe logging levels first (which counterintuitively means lower in this function), less severe logging levels don't bother reporting the same message.
        $useShortAttachment = false;
        $includeContextAndExtra = true; //This is important because otherwise 404 errors wouldn't report the URL, give how 'report' function is coded within App\Exceptions\Handler.php.
        $handlerForWarningsToNotifyPhone = new \Monolog\Handler\SlackHandler(config('services.slack.token'), config('services.slack.channel_warnings'), 'Monolog', true, null, \Monolog\Logger::WARNING, $bubble, $useShortAttachment, $includeContextAndExtra);
        $monolog->pushHandler($handlerForWarningsToNotifyPhone);
        $handlerForErrorsToNotifyPhone = new \Monolog\Handler\SlackHandler(config('services.slack.token'), config('services.slack.channel_errors'), 'Monolog', true, null, \Monolog\Logger::ERROR, $bubble, $useShortAttachment, $includeContextAndExtra);
        $monolog->pushHandler($handlerForErrorsToNotifyPhone);
    }
    if (config('app.send_logs_to_loggy')) {
        $logglyHandler = new \Monolog\Handler\LogglyHandler(config('services.loggly.token'), config('app.send_logs_to_loggy')); //See \Monolog\Logger::INFO. Log level 200 is "info".
        $logglyHandler->setTag(config('services.loggly.tag'));
        $monolog->pushHandler($logglyHandler);
    }
    if (config('app.log_to_local_disk')) {
        $localHandler = new \Monolog\Handler\StreamHandler(storage_path("/logs/laravel.log"));
        $monolog->pushHandler($localHandler);
    }
});

It's just an example that may help you.

Be sure to edit your config files accordingly (e.g. so that app.log_to_local_disk, services.slack.send_errors_to_slack, etc are available).

http://stackoverflow.com/a/36259944/470749 was helpful.

Ryan
  • 22,332
  • 31
  • 176
  • 357
0

Here is how I able to configure on Laravel Lumen v5.4 in app.php:

$publisher = new \Gelf\Publisher(new \Gelf\Transport\HttpTransport(env('GRAYLOG_HOST'), env('GRAYLOG_PORT'), env('GRAYLOG_PATH')));

//WhatFailureGroupHandler does not break app execution 
//if some exceptions happen  happens while logging
$failureHandler = new \Monolog\Handler\WhatFailureGroupHandler([
 new \Monolog\Handler\GelfHandler($publisher)
]);

\Log::pushHandler($failureHandler);

\Log::getMonolog() as on accepted answer threw error.

Also tried to configure using $app->configureMonologUsing() which threw A facade root has not been set. error. But at the end, I found out that was because we need to return logger:

$app->configureMonologUsing(function ($monolog) {

    $publisher = new \Gelf\Publisher(new \Gelf\Transport\HttpTransport(env('GRAYLOG_HOST'), env('GRAYLOG_PORT'), env('GRAYLOG_PATH')));
    
    $failureHandler = new \Monolog\Handler\WhatFailureGroupHandler([new \Monolog\Handler\GelfHandler($publisher)]);

    $monolog->pushHandler($failureHandler);

    //fixes error: A facade root has not been set
    return $monolog;
});

All the examples of $app->configureMonologUsing() usage I have seen do not have a return statement, even in the other answers, which did not work for me.

Nuryagdy Mustapayev
  • 667
  • 1
  • 7
  • 27