Как создать собственный файл журнала в Magento 2?

57

В Magento 1 было обычным делить журналы на разные файлы (разделять журналы для способов оплаты и т. Д.). Это так же просто, как изменить $fileпараметр Mage::log.

Magento 2 изменился, чтобы использовать Monolog.

Похоже, что Monolog (или его реализация в Magento2) сегментирует все журналы для всей среды по серьезности. Есть несколько обработчиков, которые пишут в файл:

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

Вход в соответствующие файлы в var / log как в Magento 1.

Я мог бы добавить обработчик для конкретной серьезности (например, писать уведомления для var/log/notice.log). Расширьте \Magento\Framework\Logger\Handler\Baseи зарегистрируйте обработчик в di.xml.

Эта статья приблизительно описывает этот процесс: http://semaphoresoftware.kinja.com/how-to-create-a-custom-log-in-magento-2-1704130912

Но как мне записать все журналы (не только одну серьезность) для одного класса (не все Magento) в мой файл выбора?

Похоже, мне придется создать свою собственную версию Magento\Framework\Logger\Monolog, но как же тогда все совместится, чтобы это на самом деле работало?

Если это большое нет-нет в Magento 2, то какова альтернатива? Я хочу что-то отделить журналы для этого расширения с целью отладки его при необходимости на клиентских сайтах. Записывать эту информацию в system.log, exception.log и т. Д. И перемешивать с журналами всех остальных модулей нецелесообразно.

Райан Херр
источник

Ответы:

101

Вам не нужно настраивать или пытаться расширить журналирование Magento2. Как вы сказали, он использует Monolog с небольшой настройкой. Достаточно написать собственный регистратор, расширяющий Monolog без особых усилий.

Предполагая, что ваш модуль находится в YourNamespace/YourModule:

1) Написать класс Logger в Logger/Logger.php:

<?php
namespace YourNamespace\YourModule\Logger;

class Logger extends \Monolog\Logger
{
}

2) Написать класс обработчика в 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';
}

Примечание. Это единственный шаг, в котором используется код Magento. \Magento\Framework\Logger\Handler\Baseрасширяет Monolog StreamHandlerи, например, добавляет атрибут $ fileName к базовому пути Magento.

3) Зарегистрируйте регистратор в внедрении зависимостей 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>

Примечание. Это не обязательно, но позволяет DI передавать конкретные аргументы в конструктор. Если вы не сделаете этот шаг, то вам нужно настроить конструктор для установки обработчика.

4) Используйте регистратор в ваших классах Magento:

Это делается путем внедрения зависимостей. Ниже вы найдете фиктивный класс, который записывает только запись в журнал:

<?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
Я спрашивал что-то похожее на одного из архитекторов на днях, так что спасибо за этот пример! Мне было интересно добавить поддержку, основанную на имени класса, чтобы структура DI могла внедрять «правильный» регистратор в разные классы, и иметь переключатели в Admin для включения / выключения флагов без изменений кода, как это. Насколько полезной была бы эта функциональность для людей?
Алан Кент
1
Маной, если шаблон, на который вы ссылаетесь, имеет класс блока с регистратором, то вы можете написать открытый метод, который затем передает сообщение регистратору. Ваш пример не будет работать, поскольку _logger защищен, если он вообще существует
халк
3
На мой взгляд, нынешний подход является шагом назад по сравнению с тем, что было у M1. Ведение журнала также должно быть инструментом разработчика, оно предназначено не только для мониторинга работающего приложения. Я вижу, как можно создать необязательную многоцелевую упрощенную библиотеку для использования в разработке, переопределяя текущую реализацию, а затем заменяя ее для производственного использования
barbazul
2
@AlanKent Я согласен с barbazul здесь - возможность легко войти в тот файл, который вы хотели, быстро указав уровень в M1, была великолепна. Это не так гибко (динамически), что позор. Было бы хорошо иметь имя файла в качестве параметра к вызовам регистратора по умолчанию. Спасибо за ответ халк!
Робби Аверилл
2
Для меня это всегда взять /var/log/system.log, есть идеи почему?
MagePsycho
20

Мы можем записать данные в файл, как это.

$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
это быстро и просто
PMB
9

Самый простой способ:

$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

В дополнение к ответам Халка и Прадипа Кумара: Если действительно ваша единственная задача - войти в другой файл, есть несколько более простой способ. Особенно, если вы хотите включить это в несколько модулей или если вы хотите, чтобы различные файлы журнала в вашем модуле. С этим методом вам не нужно создавать собственные обработчики.

Предполагая, что ваш модуль включен, MyNamespace/MyModuleи класс, который вы хотите записать в пользовательский файл, вызывается MyClass. Если конструктор класса уже внедряет, \Psr\Log\LoggerInterfaceперейдите к шагу 2). В противном случае вам нужно добавить его в конструктор:

1) Вставьте LoggerInterface в свой класс 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;
    }
}

Если вы расширяете класс, который уже включает в себя регистратор (например \Magento\Framework\App\Helper\AbstractHelper), вы можете также перезаписать этот элемент (обычно $_logger) вместо использования отдельного. Просто добавьте $this->_logger = $logger после директивы родительского конструктора.

<?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) Настройте регистратор через внедрение зависимостей 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>

Это будет регистрировать все, чтобы /var/log/mymodule.log.

Если вам нужно войти в другой файл для другого класса, вы можете просто создать другой виртуальный регистратор с другим виртуальным обработчиком и вставить его в этот класс.

Т. Дрейлинг
источник
5

Если вам это нужно только в одном классе:

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
источник
pushHandler не выставляет метод на интерфейс, и реализация, кажется, не работает ...
Джордж
Ваша версия Magento?
mshakeel
Magento CE 2.2.0
Джордж
Я попробую это на CE 2.2.0 и вернусь к вам. Я использовал его на 2.1
mshakeel
2

Попробуйте модуль " praxigento / mage2_ext_logging ". В этом модуле добавлена ​​поддержка «Monolog Cascade» в Magento 2. «Monolog Cascade» позволяет вам сконфигурировать выход журналирования с помощью одного файла конфигурации. Вы можете распечатывать свои журналы в различные файлы, базы данных, отправлять уведомления по электронной почте и т. Д. Без изменения собственного кода.

Это пример файла конфигурации (по умолчанию '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]
Алекс Гусев
источник
1

Если логическое изменение отсутствует и нужно только изменить пользовательское имя файла журнала, то не нужно создавать собственный класс логгера, просто следуйте инструкциям ниже

1. в 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. Обработчик

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

где когда-либо вам нужно было записать данные, которые вы должны вызвать журнал PSR по умолчанию,
который

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

так что в приведенном выше примере все отладочные данные будут записываться в test.log, если вам нужно изменить систему, также вы можете добавить строку ниже в di.xml

Прадип Кумар
источник
0

Я попробовал этот ниже объектный код logger в стороннем модуле, где я хочу получить информацию журнала там, которую я поместил и получить их в файл custom.log, проверить этот код, вы определенно получите журналы в свой пользовательский файл журнала.

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

Если вам потребуется дополнительная информация, я отвечу. Спасибо.

Jdprasad V
источник