Come creare un file di registro personalizzato in Magento 2?


57

In Magento 1, era comune segmentare i registri in file diversi (per separare i registri per i metodi di pagamento, ecc.). È facile come cambiare il $fileparametro di Mage::log.

Magento 2 è stato modificato per utilizzare Monolog.

Sembra che Monolog (o l'implementazione di Magento2 di esso) segmenta tutti i registri per l'intero framework in base alla gravità. Ci sono alcuni gestori che scrivono nel file:

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

Registrazione nei rispettivi file in var / log come in Magento 1.

Potrei aggiungere un gestore per una particolare gravità (IE, scrivere avvisi in var/log/notice.log). Estendi \Magento\Framework\Logger\Handler\Basee registra il gestore in di.xml.

Questo articolo descrive approssimativamente tale processo: http://semaphoresoftware.kinja.com/how-to-create-a-custom-log-in-magento-2-1704130912

Ma come posso scrivere tutti i registri (non solo una severità) per una classe (non tutta Magento) nel mio file preferito?

Sembra che dovrò creare la mia versione di Magento\Framework\Logger\Monolog, ma come si adatta tutto affinché funzioni davvero?

Se questo è un grande no-no in Magento 2, qual è l'alternativa? Voglio qualcosa per separare i registri per questa estensione allo scopo di eseguirne il debug quando necessario sui siti client. Avere quelle informazioni scritte su system.log, exception.log, ecc. E confuse con i registri di ogni altro modulo non è pratico.

Risposte:


101

Non è necessario personalizzare o provare ad estendere la registrazione di Magento2. Come hai detto, usa Monolog con una leggera personalizzazione. È sufficiente scrivere il proprio logger estendendo Monolog con il minimo sforzo.

Supponendo che il tuo modulo sia in YourNamespace/YourModule:

1) Scrivi la classe Logger in Logger/Logger.php:

<?php
namespace YourNamespace\YourModule\Logger;

class Logger extends \Monolog\Logger
{
}

2) Scrivi la classe Handler in 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';
}

Nota: questo è l'unico passaggio che utilizza il codice Magento. \Magento\Framework\Logger\Handler\Baseestende Monolog's StreamHandlere ad esempio antepone l'attributo $ fileName con il percorso base di Magento.

3) Registrazione del logger nell'iniezione delle dipendenze 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>

Nota: questo non è strettamente necessario ma consente al DI di passare argomenti specifici al costruttore. Se non si esegue questo passaggio, è necessario regolare il costruttore per impostare il gestore.

4) Usa il logger nelle tue classi Magento:

Questo viene fatto da Dependency Injection. Di seguito troverai una classe fittizia che scrive solo una voce di registro:

<?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');
    }
}

2
L'altro giorno stavo chiedendo qualcosa di simile a uno degli architetti, quindi grazie per questo esempio! Mi chiedevo di aggiungere supporto in base al nome della classe in modo che DI framework potesse iniettare il logger "giusto" in classi diverse e avere interruttori nell'amministratore per attivare / disattivare i flag senza modifiche al codice come questo. Quanto sarebbe utile questo tipo di funzionalità alle persone?
Alan Kent,

1
Manoj, se il modello a cui ti riferisci ha una classe di blocco con logger, puoi scrivere un metodo pubblico che quindi passa il messaggio al logger. Il tuo esempio non funzionerà poiché _logger è protetto se esiste affatto
halk

3
Secondo me, l'attuale approccio è un passo indietro rispetto a quello che aveva M1. La registrazione dovrebbe anche essere uno strumento di sviluppo, non è pensato solo per il monitoraggio di un'applicazione live. Vedo come è possibile creare una libreria semplificata multiuso opzionale da utilizzare nello sviluppo ignorando l'implementazione corrente e quindi sostituendola per l'uso in produzione
barbazul,

2
@AlanKent Sono d'accordo con barbazul qui - la capacità di accedere facilmente a qualsiasi file tu volessi, specificando rapidamente il livello in M1 è stata grande. Questo non è flessibile (dinamicamente), il che è un peccato. Sarebbe bene avere il nome file come parametro per le chiamate predefinite del logger. Grazie per la risposta halk!
Robbie Averill,

2
Per me prende sempre il /var/log/system.log, qualche idea del perché?
MagoPsycho

20

Possiamo registrare i dati in file come questo.

$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());

2
questo è semplice e veloce
PMB il

9

Il modo più semplice possibile:

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

6

Oltre alle risposte di Halk e Pradeep Kumar: Se davvero l'unica preoccupazione è accedere a un altro file, esiste un modo leggermente più semplice. Soprattutto se si desidera incorporarlo in più moduli o se si desidera che diversi file di registro all'interno del modulo. Con questo metodo, non è necessario creare gestori personalizzati.

Supponendo che il modulo sia in MyNamespace/MyModulee la classe, che si desidera accedere a un file personalizzato, viene chiamata MyClass. Se il costruttore della classe inietta già, vai \Psr\Log\LoggerInterfaceal passaggio 2). Altrimenti è necessario iniettarlo nel costruttore:

1) Inject LoggerInterface nella tua 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;
    }
}

Se estendi una classe che include già un logger (come \Magento\Framework\App\Helper\AbstractHelper) potresti anche sovrascrivere quel membro (di solito $_logger) invece di usarne uno separato. Basta aggiungere $this->_logger = $logger dopo la direttiva del costruttore principale.

<?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) Configurare il logger tramite l'iniezione delle dipendenze 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>

Questo accederà a tutto /var/log/mymodule.log.

Se è necessario accedere a un file diverso per una classe diversa, è possibile semplicemente creare un altro logger virtuale con un altro gestore virtuale e iniettarlo in quella classe.


5

Se ne hai bisogno solo all'interno della tua singola classe:

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'));
}

pushHandler non è esposto metodo sull'interfaccia e l'implementazione non sembra funzionare ...
George

La tua versione di Magento?
mshakeel,

Magento CE 2.2.0
George

Lo proverò su CE 2.2.0 e ti ricontatterò. L'ho usato il 2.1
mshakeel il

2

Prova il modulo " praxigento / mage2_ext_logging ". Questo modulo aggiunge il supporto "Monolog Cascade" a Magento 2. "Monolog Cascade" consente di configurare l'output di registrazione con un singolo file di configurazione. È possibile stampare i log in diversi file, database, inviare avvisi e-mail e così via senza modificare il proprio codice.

Questo è un esempio del file di configurazione ('var / log / logging.yaml' per impostazione predefinita):

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]

1

Se non è stata apportata alcuna modifica alla logica e è necessario modificare solo il nome di un file di registro personalizzato, non è necessario creare la classe di registrazione personalizzata anche solo seguire i passaggi seguenti

1. in 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. Gestore

<?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';
}

dove mai avevi bisogno di registrare i dati è necessario chiamare registro PSR di default
che è

<?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();
    }
}

quindi l'esempio sopra registrerà tutti i dati di debug su test.log se hai bisogno di cambiare sistema e puoi aggiungere la riga sotto in di.xml


0

Ho provato questo sotto il codice oggetto logger in un modulo di terze parti in cui voglio ottenere le informazioni di registro lì inserite e inserirle nel file custom.log, controllare questo codice, sicuramente avrai i registri nel tuo file di registro personalizzato.

$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);

Se hai richiesto ulteriori informazioni qui, risponderò. Grazie.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.