Wie erstelle ich eine benutzerdefinierte Log-Datei in Magento 2?

57

In Magento 1 war es üblich, Protokolle in verschiedene Dateien zu unterteilen (um Protokolle für Zahlungsmethoden usw. zu trennen). Das ist so einfach wie das Ändern der $fileParameter von Mage::log.

Magento 2 wurde geändert, um Monolog zu verwenden.

Es scheint, dass Monolog (oder die Implementierung von Magento2) alle Protokolle für das gesamte Framework nach Schweregrad für die Handler segmentiert. Es gibt einige Handler, die in eine Datei schreiben:

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

Protokollierung in die entsprechenden Dateien in var / log wie in Magento 1.

Ich könnte einen Handler für einen bestimmten Schweregrad hinzufügen (IE, Schreiben von Hinweisen an var/log/notice.log). Erweitern Sie \Magento\Framework\Logger\Handler\Baseund registrieren Sie den Handler in di.xml.

In diesem Artikel wird dieser Vorgang grob beschrieben: http://semaphoresoftware.kinja.com/how-to-create-a-custom-log-in-magento-2-1704130912

Aber wie schreibe ich alle Protokolle (nicht nur einen Schweregrad) für eine Klasse (nicht alle von Magento) in eine Datei meiner Wahl?

Es sieht so aus, als müsste ich meine eigene Version von erstellen Magento\Framework\Logger\Monolog, aber wie passt dann alles zusammen, damit das tatsächlich funktioniert?

Wenn dies in Magento 2 ein großes Nein ist, was ist dann die Alternative? Ich möchte, dass die Protokolle für diese Erweiterung getrennt werden, um sie bei Bedarf auf Clientsites zu debuggen. Es ist nicht praktikabel, diese Informationen in system.log, exception.log usw. zu schreiben und mit den Protokollen aller anderen Module zu verwechseln.

Ryan Hoerr
quelle

Antworten:

99

Sie müssen die Magento2-Protokollierung weder anpassen noch erweitern. Wie Sie sagten, wird Monolog mit nur geringen Anpassungen verwendet. Es reicht aus, mit wenig Aufwand einen eigenen Logger zu schreiben, der Monolog erweitert.

Angenommen, Ihr Modul befindet sich in YourNamespace/YourModule:

1) Schreibe Logger Klasse in Logger/Logger.php:

<?php
namespace YourNamespace\YourModule\Logger;

class Logger extends \Monolog\Logger
{
}

2) Schreiben Sie die Handler-Klasse 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';
}

Hinweis: Dies ist der einzige Schritt, bei dem Magento-Code verwendet wird. \Magento\Framework\Logger\Handler\Baseerweitert StreamHandlerMonologs und stellt z. B. dem $ fileName-Attribut den Magento-Basispfad voran.

3) Logger in Dependency Injection registrieren 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>

Hinweis: Dies ist nicht unbedingt erforderlich, ermöglicht es dem DI jedoch, bestimmte Argumente an den Konstruktor zu übergeben. Wenn Sie diesen Schritt nicht ausführen, müssen Sie den Konstruktor anpassen, um den Handler festzulegen.

4) Verwenden Sie den Logger in Ihren Magento-Klassen:

Dies erfolgt durch Abhängigkeitsinjektion. Unten finden Sie eine Dummy-Klasse, die nur einen Protokolleintrag schreibt:

<?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
quelle
2
Ich habe neulich etwas Ähnliches wie einer der Architekten gefragt, also danke für dieses Beispiel! Ich habe mich gefragt, ob ich Unterstützung basierend auf dem Klassennamen hinzufügen soll, damit das DI-Framework den "richtigen" Logger in verschiedene Klassen einspeisen kann, und Schalter im Admin zum Aktivieren / Deaktivieren von Flags ohne Codeänderungen wie diese. Wie nützlich wäre diese Art von Funktionalität für Menschen?
Alan Kent
1
Manoj, wenn die Vorlage, auf die Sie sich beziehen, eine Blockklasse mit Logger hat, können Sie eine öffentliche Methode schreiben, die die Nachricht dann an den Logger weiterleitet. Ihr Beispiel funktioniert nicht, da _logger geschützt ist, falls es überhaupt existiert
halk
3
Meiner Meinung nach ist der aktuelle Ansatz ein Schritt zurück von dem, was M1 hatte. Die Protokollierung sollte auch ein Entwicklertool sein und ist nicht nur für die Überwachung einer Live-Anwendung gedacht. Ich kann sehen, wie eine optionale vereinfachte Mehrzweckbibliothek für die Verwendung in der Entwicklung erstellt werden kann, die die aktuelle Implementierung überschreibt und dann für die Produktion ersetzt wird
barbazul
2
@ AlanKent Ich stimme barbazul hier zu - die Möglichkeit, sich einfach in jede gewünschte Datei einzuloggen und die Stufe in M1 schnell anzugeben, war großartig. Dies ist nicht so flexibel (dynamisch), was eine Schande ist. Wäre gut, den Dateinamen als Parameter für die Standardaufrufe des Loggers zu haben. Danke für die Antwort halk!
Robbie Averill
2
Für mich ist es immer die /var/log/system.log, eine Idee, warum?
MagePsycho
20

Wir können Daten in einer solchen Datei protokollieren.

$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
quelle
2
Dies ist schnell und einfach
PMB
9

Der einfachste Weg:

$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
quelle
6

Zusätzlich zu den Antworten von Halk und Pradeep Kumar: Wenn Sie tatsächlich nur in eine andere Datei einloggen möchten, gibt es einen etwas einfacheren Weg. Insbesondere, wenn Sie dies in mehrere Module integrieren möchten oder wenn Sie unterschiedliche Protokolldateien in Ihrem Modul verwenden möchten. Mit dieser Methode müssen Sie keine benutzerdefinierten Handler erstellen.

Angenommen, Ihr Modul befindet sich in MyNamespace/MyModuleund die Klasse, die Sie in einer benutzerdefinierten Datei protokollieren möchten, wird aufgerufen MyClass. Wenn der Konstruktor der Klasse bereits injiziert, fahren Sie \Psr\Log\LoggerInterfacemit Schritt 2 fort. Andernfalls müssen Sie es in den Konstruktor einfügen:

1) Injizieren Sie LoggerInterface in Ihre Klasse 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;
    }
}

Wenn Sie eine Klasse erweitern, die bereits einen Logger (wie \Magento\Framework\App\Helper\AbstractHelper) enthält, können Sie dieses Mitglied (normalerweise $_logger) auch überschreiben, anstatt ein separates zu verwenden. Fügen Sie einfach $this->_logger = $logger nach der übergeordneten Konstruktor-Direktive hinzu.

<?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) Logger über Dependency Injection konfigurieren 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>

Dies wird alles aufzeichnen /var/log/mymodule.log.

Wenn Sie sich in einer anderen Datei für eine andere Klasse anmelden müssen, können Sie einfach einen anderen virtuellen Logger mit einem anderen virtuellen Handler erstellen und in diese Klasse einfügen.

T. Dreiling
quelle
5

Wenn Sie es nur in Ihrer Einzelklasse brauchen:

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
quelle
pushHandler ist nicht Methode auf der Schnittstelle ausgesetzt und die Implementierung scheint nicht zu funktionieren ...
George
Deine Magento Version?
Mshakeel
Magento CE 2.2.0
George
Ich werde es auf CE 2.2.0 testen und mich bei Ihnen melden. Ich habe es auf 2.1
mshakeel
2

Versuchen Sie das Modul " praxigento / mage2_ext_logging ". Dieses Modul erweitert Magento 2 um die "Monolog Cascade" -Unterstützung. Mit "Monolog Cascade" können Sie Ihre Protokollausgabe mit einer einzigen Konfigurationsdatei konfigurieren. Sie können Ihre Protokolle in verschiedenen Dateien, Datenbanken, E-Mail-Benachrichtigungen usw. ausdrucken, ohne den eigenen Code zu ändern.

Dies ist ein Beispiel für die Konfigurationsdatei (standardmäßig '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
quelle
1

Wenn sich die Logik nicht ändert und nur der Name einer benutzerdefinierten Protokolldatei geändert werden muss, müssen Sie auch keine benutzerdefinierte Protokollklasse erstellen. Befolgen Sie dazu einfach die nachstehenden Schritte

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

Wo immer Sie die Daten protokollieren mussten
, müssen Sie das Standard-PSR-Protokoll aufrufen

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

Das obige Beispiel protokolliert alle Debug-Daten in test.log, wenn Sie das System ändern müssen. Sie können auch die folgende Zeile in di.xml hinzufügen

Pradeep Kumar
quelle
0

Ich habe den folgenden Logger-Objektcode in einem Drittanbieter-Modul ausprobiert, in dem ich die dort abgelegten Log-Informationen abrufen und in die custom.log-Datei laden möchte. Überprüfen Sie diesen Code. Sie erhalten die Logs definitiv in Ihre benutzerdefinierte Log-Datei.

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

Wenn Sie weitere Informationen Kommentar hier erforderlich, werde ich antworten. Danke.

Jdprasad V
quelle