Jak utworzyć niestandardowy plik dziennika w Magento 2?

57

W Magento 1 logi były dzielone na różne pliki (w celu oddzielenia dzienników dla metod płatności itp.). To tak proste, jak zmiana $fileparametru Mage::log.

Magento 2 zmieniło się na Monolog.

Wygląda na to, że Monolog (lub implementacja Magento2) segmentuje wszystkie logi dla całego frameworka na procedury obsługi według ważności. Istnieje kilka programów obsługi, które zapisują do pliku:

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

Logowanie do odpowiednich plików w var / log jak w Magento 1.

Mógłbym dodać moduł obsługi dla określonego poziomu ważności (IE, pisz powiadomienia do var/log/notice.log). Rozszerz \Magento\Framework\Logger\Handler\Basei zarejestruj program obsługi w di.xml.

W tym artykule z grubsza opisano ten proces: http://semaphoresoftware.kinja.com/how-to-create-a-custom-log-in-magento-2-1704130912

Ale jak przejść do zapisywania wszystkich dzienników (nie tylko jednego poziomu ważności) dla jednej klasy (nie wszystkich Magento) w wybranym pliku?

Wygląda na to, że będę musiał stworzyć własną wersję Magento\Framework\Logger\Monolog, ale w jaki sposób wszystko do siebie pasuje, aby to rzeczywiście działało?

Jeśli jest to duże nie-nie w Magento 2, to jaka jest alternatywa? Chcę coś, aby oddzielić dzienniki dla tego rozszerzenia w celu debugowania go w razie potrzeby na stronach klienckich. Zapisanie tych informacji w pliku system.log, wyjątku.log itp. I pomieszanie ich z dziennikami każdego innego modułu nie jest praktyczne.

Ryan Hoerr
źródło

Odpowiedzi:

99

Nie musisz dostosowywać ani próbować rozszerzać rejestrowania Magento2. Jak powiedziałeś, używa Monologa z niewielkimi modyfikacjami. Wystarczy napisać własny rejestrator rozszerzający Monolog przy bardzo małym wysiłku.

Zakładając, że moduł jest w YourNamespace/YourModule:

1) Napisz klasę Logger w Logger/Logger.php:

<?php
namespace YourNamespace\YourModule\Logger;

class Logger extends \Monolog\Logger
{
}

2) Napisz klasę modułu obsługi w 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';
}

Uwaga: jest to jedyny krok, który wykorzystuje kod Magento. \Magento\Framework\Logger\Handler\Baserozszerza Monologa StreamHandleri np. dołącza atrybut $ fileName do podstawowej ścieżki Magento.

3) Zarejestruj rejestrator we wstrzyknięciu zależności 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>

Uwaga: Nie jest to bezwzględnie wymagane, ale pozwala DI przekazywać określone argumenty do konstruktora. Jeśli nie wykonasz tego kroku, musisz dostosować konstruktor, aby ustawić moduł obsługi.

4) Użyj rejestratora w swoich klasach Magento:

Odbywa się to za pomocą wstrzykiwania zależności. Poniżej znajduje się fikcyjna klasa, która zapisuje tylko wpis w dzienniku:

<?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
źródło
2
Pewnego dnia poprosiłem o coś podobnego do jednego z architektów, więc dziękuję za ten przykład! Zastanawiałem się nad dodaniem obsługi opartej na nazwie klasy, aby środowisko DI mogło wstrzykiwać „właściwy” program rejestrujący do różnych klas, i mieć przełączniki w Administratorze, aby włączać / wyłączać flagi bez zmian kodu w ten sposób. Jak przydatna byłaby taka funkcjonalność dla ludzi?
Alan Kent
1
Manoj, jeśli szablon, do którego się odwołujesz, ma klasę bloków z rejestratorem, możesz napisać metodę publiczną, która następnie przekazuje komunikat do rejestratora. Twój przykład nie zadziała, ponieważ _logger jest chroniony, jeśli w ogóle istnieje
halk
3
Moim zdaniem obecne podejście jest krokiem wstecz od tego, co miał M1. Rejestrowanie powinno być także narzędziem programistycznym, służy nie tylko do monitorowania aplikacji na żywo. Widzę, jak można stworzyć opcjonalną, uniwersalną, uproszczoną bibliotekę, która będzie używana w rozwoju nadpisującym obecną implementację, a następnie zastąpiona produkcją
barbazul
2
@AlanKent Zgadzam się z barbazul tutaj - możliwość łatwego logowania do dowolnego pliku, który chciałeś, określenie poziomu w M1 było świetne. Nie jest to tak elastyczne (dynamicznie), co szkoda. Dobrze byłoby mieć nazwę pliku jako parametr domyślnych wywołań programu rejestrującego. Dzięki za odpowiedź halk!
Robbie Averill,
2
Dla mnie to zawsze zajmuje /var/log/system.log, jakiś pomysł dlaczego?
MagePsycho
20

Możemy rejestrować dane w takim pliku.

$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
źródło
2
to jest szybkie i łatwe
PMB
9

Najprostszy możliwy sposób:

$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
źródło
6

Oprócz odpowiedzi Halk i Pradeep Kumar: Jeśli rzeczywiście jedyną troską jest zalogowanie się do innego pliku, istnieje nieco łatwiejszy sposób. Zwłaszcza jeśli chcesz włączyć to do wielu modułów lub jeśli chcesz mieć różne pliki dziennika w swoim module. Dzięki tej metodzie nie musisz tworzyć własnych programów obsługi.

Zakładając, że moduł jest włączony MyNamespace/MyModulei wywoływana jest klasa, którą chcesz zalogować do pliku niestandardowego MyClass. Jeśli konstruktor klasy już wstrzykuje, \Psr\Log\LoggerInterfaceprzejdź do kroku 2). W przeciwnym razie musisz wstrzyknąć go do konstruktora:

1) Inject LoggerInterface w twojej klasie 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;
    }
}

Jeśli rozszerzysz klasę, która już zawiera program rejestrujący (podobny \Magento\Framework\App\Helper\AbstractHelper), możesz równie dobrze zastąpić tego członka (zwykle $_logger) zamiast używać osobnego. Po prostu dodaj $this->_logger = $logger po dyrektywie konstruktora nadrzędnego.

<?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) Skonfiguruj rejestrator za pomocą wstrzykiwania zależności 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>

Spowoduje to zalogowanie wszystkiego do /var/log/mymodule.log.

Jeśli musisz zalogować się do innego pliku dla innej klasy, możesz po prostu utworzyć inny wirtualny rejestrator za pomocą innego wirtualnego programu obsługi i wstrzyknąć go do tej klasy.

T. Dreiling
źródło
5

Jeśli potrzebujesz go tylko w ramach jednej klasy:

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
źródło
pushHandler nie ujawnia metody interfejsu, a implementacja nie działa ...
George
Twoja wersja Magento?
mshakeel
Magento CE 2.2.0
George
Spróbuję na CE 2.2.0 i skontaktuję się z Tobą. Użyłem go w wersji 2.1
mshakeel
2

Wypróbuj modułpraxigento / mage2_ext_logging ”. Moduł dodaje obsługę „Monolog Cascade” do Magento 2. „Monolog Cascade” pozwala na konfigurację logowania danych wyjściowych za pomocą pojedynczego pliku konfiguracyjnego. Możesz wydrukować dzienniki do różnych plików, baz danych, wysyłać powiadomienia e-mail itp. Bez modyfikacji własnego kodu.

To jest przykład pliku konfiguracyjnego (domyślnie „var / log / logging.yaml”):

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
źródło
1

Jeśli nie ma zmiany logiki i wystarczy zmienić niestandardową nazwę pliku dziennika, nie trzeba tworzyć niestandardowej klasy rejestratora, wystarczy wykonać poniższe kroki

1. w 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. Handler

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

gdziekolwiek trzeba było rejestrować dane, należy wywołać domyślny dziennik PSR
, czyli

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

więc powyższy przykład zarejestruje wszystkie dane debugowania do test.log, jeśli trzeba zmienić system, można dodać poniższy wiersz w di.xml

Pradeep Kumar
źródło
0

Próbowałem tego poniżej kodu obiektu rejestratora w module innej firmy, w którym chcę uzyskać informacje o dzienniku, które tam umieściłem i umieść je w pliku custom.log, sprawdź ten kod, na pewno dostaniesz dzienniki do niestandardowego pliku dziennika.

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

Jeśli potrzebujesz więcej informacji, skomentuj tutaj, odpowiem. Dziękuję Ci.

Jdprasad V.
źródło