Use Monolog for logging


Symfony comes with an external library - called Monolog - that allows you to create logs that can be stored in a variety of different places.

Record a message

To record a message, remove the logger service from the container in the controller:

public function indexAction(){
    $logger = $this->get('logger');
    $logger->info('I just got the logger');
    $logger->error('An error occurred');     $logger->critical('I left the oven on!', array(
        // include extra "context" info in your logs / 在日志中附带额外的“上下文”信息
        'cause' => 'in_hurry',
    ));     // ...}

The logger service has different methods for different log levels/priorities. You can configure the logger to do different things based on the level of the message (such as sending an email when an error occurs).

Refer to LoggerInterface for a complete list of logger methods.

Where the log is stored

The configuration information for storing the log where is located in a specific environment Configuration files: config_dev.yml and config_prod.yml.

When you are in the dev environment, the log file entry is written into the var/logs/dev.log file by default. In the prod environment, the log is written to var/logs/prod.log, but only encounters an error or high Occurs only when priority logs are logged (such as error(), critical(), alert() or emergency()).

To control the storage location, you need to configure different handlers (controllers) to control the log entry points (entries), modify them if necessary, and finally store them.

Handlers: Write logs to different locations

logger comes with a set of handlers, each of which is used to write logs Entries are written to different locations (e.g., files, databases, Slack, etc.).

You also can configure the "channels" of the log, which are like categories. Each channel can have its own handlers, which means you can log different information to different places. Refer to How to write log information to different files.

Symfony presets some handlers in the config_dev.yml and config_prod.yml files. Check them out to see real-world use cases.

The following example uses two handlers: stream (for writing files) and syslog, the latter uses syslog Function to complete the log:

YAML:# app/config/config.ymlmonolog:
    handlers:        # this "file_log" key could be anything
        # 这个 "file_log" 键可以是任何(合法)字符
        file_log:
            type: stream            # log to var/logs/(environment).log
            # 写入到 var/logs/(environment).log
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            # log *all* messages (debug is lowest level)
            # 把 *全部* 信息写入(debug是最低级别)
            level: debug
        syslog_handler:
            type: syslog            # log error-level messages and higher
            # 记录 error-level(ERROR级别)或更高级别(的信息)
            level: error
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:monolog="http://symfony.com/schema/dic/monolog"    xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/monolog        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">     <monolog:config>
        <monolog:handler            name="file_log"            type="stream"            path="%kernel.logs_dir%/%kernel.environment%.log"            level="debug"        />
        <monolog:handler            name="syslog_handler"            type="syslog"            level="error"        />
    </monolog:config></container>
PHP:// app/config/config.php$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'file_log' => array(
            'type'  => 'stream',
            'path'  => '%kernel.logs_dir%/%kernel.environment%.log',
            'level' => 'debug',
        ),
        'syslog_handler' => array(
            'type'  => 'syslog',
            'level' => 'error',
        ),
    ),));

This example defines a group of handlers, which will be called in the order in which they are defined.

Handlers that can modify the log entry

Instead of writing the log to a file somewhere, Some handlers can be used to "in Filter and modify logs before sending them to other handlers. A built-in powerful handler named fingers_crossed is used by default in the prod environment. It stores all log information during the request process, but only passes them to the second handler if a piece of information reaches the action_level level. Look at the following routine:

YAML:# app/config/config.ymlmonolog:
    handlers:
        filter_for_errors:
            type: fingers_crossed            # if *one* log is error or higher, pass *all* to file_log
            # 如果 *一条* 日志是error或更高(的级别),把它们 *全部* 传入file_log
            action_level: error
            handler: file_log
         # now passed *all* logs, but only if one log is error or higher
        # 现在传入了 *全部* 日志,但只是那些error或更高级别的
        file_log:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"         # still passed *all* logs, and still only logs error or higher
        # 仍然传入了 *全部* 日志,并且仍然都是error或更高级别的
        syslog_handler:
            type: syslog
            level: error
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:monolog="http://symfony.com/schema/dic/monolog"    xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/monolog        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">     <monolog:config>
        <monolog:handler            name="filter_for_errors"            type="fingers_crossed"            action-level="error"            handler="file_log"        />
        <monolog:handler            name="file_log"            type="stream"            path="%kernel.logs_dir%/%kernel.environment%.log"            level="debug"        />
        <monolog:handler            name="syslog_handler"            type="syslog"            level="error"        />
    </monolog:config></container>
PHP:// app/config/config.php$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'filter_for_errors' => array(
            'type'         => 'fingers_crossed',
            'action_level' => 'error',
            'handler'      => 'file_log',
        ),
        'file_log' => array(
            'type'  => 'stream',
            'path'  => '%kernel.logs_dir%/%kernel.environment%.log',
            'level' => 'debug',
        ),
        'syslog_handler' => array(
            'type'  => 'syslog',
            'level' => 'error',
        ),
    ),));

Now, if a log entry (log entry, translation annotation: "a log file located somewhere") encounters an error or higher level ( information), then all log entries of the request will be saved into a file through the file_log handler. This means your log files will contain all relevant details of the problematic request - which makes debugging much easier!

The handler named "file_log" will not be included in the controller stack because it is used as a nested controller of the fingers_crossed handler .

If you want to overwrite the monolog configuration information through another configuration file, you need to redefine the entire handlers stack (controller stack). The configuration information in these two files cannot be merged because the order (of handlers) is critical and the order cannot be controlled once merged.

All built-in handlers

Monolog has built-in Many handlers for sending log emails, sending them to Loggly, or notifying you in Slack . These functions are documented in the MonologBundle. Please refer to Monolog Configuration for a complete list.

How to flip your log files

Over time, whether it is a development environment or a production environment, the log files will become extremely huge . A best practice in the solution is to use a Linux command such as logrotate to reverse the log file before it becomes huge.

Another option is to use the rotating_file handler to tell Monolog to rotate the log file. This controller creates new log files every day and automatically deletes old ones. To use it, set the type option in the controller to rotating_file:

PHP:// app/config/config_dev.php$container->loadFromExtension('monolog', array(
    'handlers' => array(
        'main' => array(
            'type'  => 'rotating_file',
            'path'  => "%kernel.logs_dir%/%kernel.environment%.log",
            'level' => 'debug',
            // max number of log files to keep
            // defaults to zero, which means infinite files
            'max_files' => 10,
        ),
    ),));
XAML:<!-- app/config/config_dev.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:monolog="http://symfony.com/schema/dic/monolog"    xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/monolog        http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">     <monolog:config>
        <!-- "max_files": max number of log files to keep             defaults to zero, which means infinite files -->
        <monolog:handler name="main"            type="rotating_file"            path="%kernel.logs_dir%/%kernel.environment%.log"            level="debug"            max_files="10"        />
    </monolog:config></container>
YAML:# app/config/config_dev.ymlmonolog:
    handlers:
        main:
            type:  rotating_file
            path:  '%kernel.logs_dir%/%kernel.environment%.log'
            level: debug            # max number of log files to keep
            # defaults to zero, which means infinite files
            # 要保留的日志文件的最大数量,默认是零,即,无限个文件
            max_files: 10