web-dev-qa-db-fra.com

Enregistrement de trace de pile complète avec Monolog

J'utilise Monolog en tant que bibliothèque autonome dans mon application et récemment, j'ai rencontré un problème. Disons que, à un moment donné de mon application, une exception est capturée et je souhaite la journaliser:

$mylogger->error('Exception caught', array('exception' => $exception));

Cela fonctionne parfaitement, sauf une petite chose - il ne se connecte pas trace complète de la pile. Est-il possible de consigner la trace de pile complète de l'exception à l'aide des outils de formatage intégrés à monolog?

36
Wild One

En fait, depuis la version 1.12.0, il est possible d'inclure stacktrace dans votre fichier journal: il existe une nouvelle méthode de LineFormatter appelée includeStacktraces.

Pour utiliser cela, vous devez écraser le comportement par défaut du formateur Monolog:

config.yml

monolog:
    handlers:
        main:
            formatter: your.monolog.service.id
            (rest of config is as usual)

services.yml

services:
    your.monolog.service.id:
        class: Monolog\Formatter\LineFormatter
        calls:
            - [includeStacktraces]

Vérifiez github pour plus d’informations: Demande de tirage

29
Tomasz Madeyski

J'ai une solution très simple !!!

$mylogger->error((string) $exception);
17
Amir

Non, vous ne pouvez pas enregistrer la trace de la pile à l'aide des outils de formatage intégrés. Voir ma question ici .

Si vous examinez LineFormatter.php, vous constatez que la méthode normalizeException est chargée de récupérer les données sur les exceptions. Donc, je devais créer un nouveau formateur qui étendait LineFormatter. Voici le code:

<?php

namespace Monolog\Formatter;

use Exception;

class ExceptionLineFormatter extends LineFormatter
{
    protected function normalizeException(Exception $e)
    {
        return 'Message: ' . $e->getMessage() . 
                'Stack Trace: '. $e->getTraceAsString();
    }
}

Et j'ai initialisé mon logger comme ceci:

$logFile = 'MyLogFile.txt';
$handler = new StreamHandler($logFile);
$handler->setFormatter(new ExceptionLineFormatter);
$log = new Logger('MyLogger');
$handler = self::getStreamHander();
$log->pushHandler($handler);

Cela imprimera votre trace de pile.

10
Rayhan Muktader

Ajout à La réponse de Tomasz Madeyski , voici comment vous pouvez l'utiliser via un code uniquement:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\ErrorHandler;
use Monolog\Formatter\LineFormatter;

$formatter = new LineFormatter(LineFormatter::SIMPLE_FORMAT, LineFormatter::SIMPLE_DATE);
$formatter->includeStacktraces(true); // <--

$stream = new StreamHandler('error.log');
$stream->setFormatter($formatter);

$logger = new Logger('logger');
$logger->pushHandler($stream);
6
SeinopSys

getTraceAsString vous donnera le tableau Stack Trace en tant que chaîne délimitée par "Fin de ligne". Exploser sur PHP_EOL puis foreach à travers le tableau en enregistrant chaque élément. J'espère que cela t'aides.

<?php
function test() {
    throw new Exception;
}

try {
    test();
} catch(Exception $e) {
    $array = explode(PHP_EOL, $e->getTraceAsString());
    foreach($array as $line){
        $mylogger->error($line);
}

Devrait produire quelque chose comme ceci:

#0 index.php(14): test()
#1 {main}
1
php_bob

Si vous souhaitez consigner stacktrace only lorsque Exception est levée, vous pouvez le faire dans la AppServiceProvider:

public function register()
{
     $logger = Log::getMonolog();
     $logger->pushProcessor(function ($record) {
        if (isset($record['context']['exception']))
        {
            $record['extra']['stacktrace'] = $record['context']['exception']->getTraceAsString();
        }

        return $record;
    });
}

Cela ajoutera le stacktrace à la colonne extra, qui pourra ensuite être utilisée par LineFormatter.

1
eithed

Vous pouvez simplement utiliser le fichier de configuration (Symfony Bundle)} _ avec le paramètre "include_stacktraces":

monolog:
    handlers:
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: info
            channels: ["!event"]
            max_files: 10
            include_stacktraces: true <--- SET TO TRUE

@seethis commit

@seele schéma complet (configuration)

1
kxxxxoo

La réponse Upvoted fonctionne , mais vous n'êtes pas obligé de créer un service personnalisé pour cela.

Le monolog.formatter.line existe déjà sur la pile complète Symfony 3.4. Vous pouvez simplement y ajouter un appel de méthode grâce à la variable CompilerPassInterface:

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use use Symfony\Component\HttpKernel\Kernel;

class AppKernel extends Kernel implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $container->getDefinition('monolog.formatter.line')->addMethodCall('includeStacktraces');
    }
}

Le gestionnaire monolog ne semble pas recevoir le service par défaut, vous devez donc le spécifier. Exemple:

monolog:
    handlers:
        main:
            type: rotating_file
            max_files: 12
            date_format: 'Y-m'
            path: '%kernel.logs_dir%/%kernel.environment%.log'
            level: debug
            formatter: monolog.formatter.line
0
Soullivaneuh