Як створити спеціальний файл журналу в 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.

Я міг би додати обробник для певної суворості (IE, писати повідомлення 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, исключение.log і т. Д., І змішуватись з журналами кожного іншого модуля, не є практичним.

Відповіді:


99

Вам не потрібно налаштовувати або намагатися розширити журнал Magento2. Як ви вже говорили, він використовує Monolog лише з невеликими налаштуваннями. Досить написати власний реєстратор, що розширює Monolog, з дуже невеликими зусиллями.

Якщо ваш модуль знаходиться в YourNamespace/YourModule:

1) Запишіть клас реєстратора в 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розширює StreamHandlerMonolog і, наприклад, попереджує атрибут $ 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 могла вводити "правильний" реєстратор до різних класів і мати перемикачі в Адміністраторі, щоб увімкнути / вимкнути прапори без змін коду, як це Чим корисний такий функціонал для людей?
Алан Кент

1
Manoj, якщо шаблон, який ви переглядаєте, має клас блоків з реєстратором, то ви можете написати відкритий метод, який потім передає повідомлення в реєстратор. Ваш приклад не працює, оскільки _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) Введіть інтерфейс Logger у свій клас 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'));
}

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

Я спробував це нижче об'єктного коду реєстратора в сторонньому модулі, де я хочу отримати там інформацію про журнал, який я розмістив, і занести їх у файл 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);

Якщо вам потрібна додаткова інформація тут, я відповім. Дякую.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.