Comment créer un fichier de log personnalisé dans Magento 2?

57

Dans Magento 1, il était courant de segmenter les journaux en différents fichiers (pour séparer les journaux des méthodes de paiement, etc.). C'est aussi simple que de changer le $fileparamètre de Mage::log.

Magento 2 a changé pour utiliser Monolog.

Il semble que Monolog (ou son implémentation dans Magento2) segmente tous les journaux de la structure entière pour les gestionnaires par gravité. Il y a quelques gestionnaires qui écrivent dans un fichier:

\Magento\Framework\Logger\Handler\Debug, \Magento\Framework\Logger\Handler\Exception,\Magento\Framework\Logger\Handler\System

Se connecter aux fichiers respectifs dans var / log comme dans Magento 1.

Je pourrais ajouter un gestionnaire pour une gravité particulière (IE, écrire des avis à var/log/notice.log). Étendre \Magento\Framework\Logger\Handler\Baseet enregistrer le gestionnaire dans di.xml.

Cet article décrit approximativement ce processus: http://semaphoresoftware.kinja.com/how-to-create-a-custom-log-in-magento-2-1704130912

Mais comment puis-je écrire tous les journaux (pas seulement une gravité) pour une classe (pas tous Magento) dans le fichier de mon choix?

On dirait que je vais devoir créer ma propre version de Magento\Framework\Logger\Monolog, mais alors comment tout va-t-il pour que cela fonctionne réellement?

Si c'est un gros non-non dans Magento 2, alors quelle est l'alternative? Je veux quelque chose pour séparer les journaux de cette extension dans le but de la déboguer lorsque cela est nécessaire sur les sites clients. Avoir ces informations écrites dans system.log, exception.log, etc. et enchevêtrées avec les journaux de tous les autres modules n'est pas pratique.

Ryan Hoerr
la source

Réponses:

101

Vous n'avez pas besoin de personnaliser ni d'essayer d'étendre la journalisation de Magento2. Comme vous l'avez dit, il utilise Monolog avec une légère personnalisation. Il suffit d’écrire votre propre enregistreur prolongeant Monolog avec très peu d’effort.

En supposant que votre module est en YourNamespace/YourModule:

1) Écrire une classe de logger en Logger/Logger.php:

<?php
namespace YourNamespace\YourModule\Logger;

class Logger extends \Monolog\Logger
{
}

2) Écrire la classe Handler en Logger/Handler.php:

<?php
namespace YourNamespace\YourModule\Logger;

use Monolog\Logger;

class Handler extends \Magento\Framework\Logger\Handler\Base
{
    /**
     * Logging level
     * @var int
     */
    protected $loggerType = Logger::INFO;

    /**
     * File name
     * @var string
     */
    protected $fileName = '/var/log/myfilename.log';
}

Remarque: il s'agit de la seule étape qui utilise le code Magento. \Magento\Framework\Logger\Handler\Baseétend les propriétés de Monolog StreamHandleret ajoute par exemple l’attribut $ fileName avec le chemin de base de Magento.

3) Enregistrer l'enregistreur dans l'injection de dépendance etc/di.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <type name="YourNamespace\YourModule\Logger\Handler">
        <arguments>
            <argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
        </arguments>
    </type>
    <type name="YourNamespace\YourModule\Logger\Logger">
        <arguments>
            <argument name="name" xsi:type="string">myLoggerName</argument>
            <argument name="handlers"  xsi:type="array">
                <item name="system" xsi:type="object">YourNamespace\YourModule\Logger\Handler</item>
            </argument>
        </arguments>
    </type>
</config>

Remarque: Ceci n'est pas strictement requis, mais permet à l'ID de transmettre des arguments spécifiques au constructeur. Si vous ne faites pas cette étape, vous devez alors ajuster le constructeur pour définir le gestionnaire.

4) Utilisez l’enregistreur dans vos cours Magento:

Cela se fait par injection de dépendance. Vous trouverez ci-dessous une classe fictive qui écrit uniquement une entrée de journal:

<?php
namespace YourNamespace\YourModule\Model;

class MyModel
{
    /**
     * Logging instance
     * @var \YourNamespace\YourModule\Logger\Logger
     */
    protected $_logger;

    /**
     * Constructor
     * @param \YourNamespace\YourModule\Logger\Logger $logger
     */
    public function __construct(
        \YourNamespace\YourModule\Logger\Logger $logger
    ) {
        $this->_logger = $logger;
    }

    public function doSomething()
    {
        $this->_logger->info('I did something');
    }
}
halk
la source
2
Je demandais quelque chose de similaire à l'un des architectes l'autre jour, alors merci pour cet exemple! Je me demandais d'ajouter un support basé sur le nom de classe afin que le framework DI puisse injecter le "bon" enregistreur à différentes classes et d'avoir des commutateurs dans l'Admin pour activer / désactiver les drapeaux sans changement de code comme celui-ci. Quelle serait l'utilité de ce type de fonctionnalité pour les utilisateurs?
Alan Kent
1
Manoj, si le modèle auquel vous faites référence a une classe de bloc avec logger, vous pouvez écrire une méthode publique qui transmettra ensuite le message au logger. Votre exemple ne fonctionnera pas car _logger est protégé s'il existe déjà
halk
3
À mon avis, l'approche actuelle est un pas en arrière par rapport à M1. La journalisation doit également être un outil de développement, elle ne sert pas uniquement à surveiller une application en direct. Je peux voir comment une bibliothèque simplifiée polyvalente facultative pourrait être créée pour être utilisée dans le développement annulant l'implémentation actuelle, puis remplacée pour la production
barbazul
2
@AlanKent Je suis d'accord avec barbazul: la possibilité de se connecter facilement au fichier de votre choix, en spécifiant rapidement le niveau dans M1, était excellente. Ce n'est pas aussi flexible (dynamiquement) ce qui est dommage. Ce serait bien d'avoir le nom de fichier comme paramètre pour les appels de consignateur par défaut. Merci pour la réponse halk!
Robbie Averill
2
Pour moi, ça prend toujours le fichier /var/log/system.log, pourquoi?
MagePsycho
20

Nous pouvons enregistrer des données dans un fichier comme celui-ci.

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/templog.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info("Info". $product->getSku() . "----- Id  ". $product->getId() );
$logger->info("preorder qty ". $product->getPreorderQty());
Pramod Kharade
la source
2
c'est simple et rapide
PMB
9

La manière la plus simple possible:

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/test.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your text message');
Yamen Ashraf
la source
6

Outre les réponses de Halk et de Pradeep Kumar: Si votre seul souci est de vous connecter à un autre fichier, il existe un moyen légèrement plus simple. Surtout si vous souhaitez incorporer cela à plusieurs modules ou si vous voulez différents fichiers journaux au sein de votre module. Avec cette méthode, vous n'avez pas à créer de gestionnaires personnalisés.

En supposant que votre module soit inséré MyNamespace/MyModuleet que la classe que vous souhaitez consigner dans un fichier personnalisé soit appelée MyClass. Si le constructeur de la classe injecte déjà, \Psr\Log\LoggerInterfacepassez à l’étape 2). Sinon, vous devez l'injecter dans le constructeur:

1) Injectez LoggerInterface dans votre classe MyClass.php:

<?php

namespace MyNamespace\MyModule;

use Psr\Log\LoggerInterface;

class MyClass
{
    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    public function __construct(
        LoggerInterface $logger
    ) {
        $this->logger = $logger;
    }
}

Si vous étendez une classe qui inclut déjà un enregistreur (comme \Magento\Framework\App\Helper\AbstractHelper), vous pouvez également écraser ce membre (généralement $_logger) au lieu d’en utiliser un autre. Ajoutez simplement $this->_logger = $logger après la directive constructeur du parent.

<?php

namespace MyNamespace\MyModule;

use Magento\Framework\App\Helper\Context;
use Psr\Log\LoggerInterface;

class MyClass extends \Magento\Framework\App\Helper\AbstractHelper
{
    public function __construct(
        Context $context,
        LoggerInterface $logger
    ) {
        parent::__construct(
            $context
        );

        $this->_logger = $logger;
    }
}

2) Configurez l'enregistreur via l'injection de dépendance etc/di.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="MyNamespace\MyModule\Logger\Handler" type="Magento\Framework\Logger\Handler\Base">
        <arguments>
            <argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
            <argument name="fileName" xsi:type="string">/var/log/mymodule.log</argument>
        </arguments>
    </virtualType>
    <virtualType name="MyNamespace\MyModule\Logger\Logger" type="Magento\Framework\Logger\Monolog">
        <arguments>
            <argument name="name" xsi:type="string">MyModule Logger</argument>
            <argument name="handlers" xsi:type="array">
                <item name="system" xsi:type="object">MyNamespace\MyModule\Logger\Handler</item>
            </argument>
        </arguments>
    </virtualType>

    <type name="MyNamespace\MyModule\MyClass">
        <arguments>
            <argument name="logger" xsi:type="object">MyNamespace\MyModule\Logger\Logger</argument>
        </arguments>
    </type>
</config>

Cela connectera tout à /var/log/mymodule.log.

Si vous devez vous connecter à un fichier différent pour une classe différente, vous pouvez simplement créer un autre enregistreur virtuel avec un autre gestionnaire virtuel et l'injecter dans cette classe.

T. Dreiling
la source
5

Si vous en avez besoin dans votre classe unique uniquement:

public function __construct(\Psr\Log\LoggerInterface $logger, \Magento\Framework\App\Filesystem\DirectoryList $dir) 
{
    $this->logger = $logger;
    $this->dir = $dir;

    $this->logger->pushHandler(new \Monolog\Handler\StreamHandler($this->dir->getRoot().'/var/log/custom.log'));
}
mshakeel
la source
pushHandler n'est pas exposé à la méthode sur l'interface et l'implémentation ne semble pas fonctionner ...
George
Votre version de Magento?
mshakeel le
Magento CE 2.2.0
George
Je vais l'essayer sur CE 2.2.0 et vous revenir. Je l'ai utilisé sur 2.1
mshakeel le
2

Essayez le module " praxigento / mage2_ext_logging ". Ce module ajoute la prise en charge "Monolog Cascade" à Magento 2. "Monolog Cascade" vous permet de configurer la sortie de votre journal avec un fichier de configuration unique. Vous pouvez imprimer vos journaux dans différents fichiers, bases de données, envoyer des alertes par courrier électronique, etc. sans modifier votre propre code.

Voici un exemple du fichier de configuration ('var / log / logging.yaml' par défaut):

disable_existing_loggers: true
formatters:
    dashed:
        class: Monolog\Formatter\LineFormatter
        format: "%datetime%-%channel%.%level_name% - %message%\n"
handlers:
    debug:
        class: Monolog\Handler\StreamHandler
        level: DEBUG
        formatter: dashed
        stream: /.../var/log/cascade_debug.log
    system:
        class: Monolog\Handler\StreamHandler
        level: INFO
        formatter: dashed
        stream: /.../var/log/cascade_system.log
    exception:
        class: Monolog\Handler\StreamHandler
        level: EMERGENCY
        formatter: dashed
        stream: /.../log/cascade_exception.log
processors:
    web_processor:
        class: Monolog\Processor\WebProcessor
loggers:
    main:
        handlers: [debug, system, exception]
        processors: [web_processor]
Alex Gusev
la source
1

S'il n'y a pas de changement de logique et qu'il suffit de modifier un nom de fichier de journal personnalisé, il n'est pas nécessaire de créer une classe de journalisation personnalisée, il suffit simplement de suivre les étapes ci-dessous.

1. en di.xml

 <type name="Magento\Framework\Logger\Monolog">
        <arguments>
            <argument name="name" xsi:type="string">test</argument>
            <argument name="handlers"  xsi:type="array">
                <item name="test" xsi:type="object">NAME_SPACE\Test\Model\Logger\Handler\Debug</item>
            </argument>
        </arguments>
    </type>

2. Gestionnaire

<?php
/**
 * Copyright © 2017 Alshaya, LLC. All rights reserved.
 * See LICENSE.txt for license details.
 *
 */
namespace NAME_SPACE\Test\Model\Logger\Handler;

use Magento\Framework\Logger\Handler\Base;

/**
 * Log handler for reports
 */
class Debug extends Base
{
    /**
     * @var string
     */
    protected $fileName = '/var/log/test.log';
}

où que vous ayez eu besoin de vous connecter les données dont vous avez besoin pour appeler le journal PSR par défaut
qui est

<?php
/**
 *
 * Copyright © 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace NAME_SPACE\Test\Controller\Index;

use Psr\Log\LoggerInterface;
class Index extends \Magento\Framework\App\Action\Action
{


    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * Show Contact Us page
     *
     * @return void
     */


    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        LoggerInterface $logger
    ) {
        parent::__construct($context);
        $this->logger = $logger;
    }


    public function execute()
    {
        $this->logger->critical((string) 'Test');
        $this->_view->loadLayout();
        $this->_view->renderLayout();
    }
}

Ainsi, l'exemple ci-dessus enregistrera toutes les données de débogage dans test.log si vous aviez besoin de changer de système, vous pouvez également ajouter la ligne ci-dessous dans di.xml

Pradeep Kumar
la source
0

J'ai essayé ceci ci-dessous le code d'objet d'enregistreur dans un module tiers où je veux obtenir les informations de journal là-bas que j'ai placées et les obtenir dans un fichier custom.log, vérifiez ce code, vous obtenez certainement les journaux dans votre fichier de journal personnalisé.

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/custom.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('Your log details: ' .$variable);

Si vous aviez besoin de plus d'informations, commentez ici, je vous répondrai. Je vous remercie.

Jdprasad V
la source