docs

Various Yii 3.0 related documentation

View the Project on GitHub yiisoft/docs

Logging

Yii relies on PSR-3 interfaces for logging, so you could configure any PSR-3 compatible logging library to do the actual job.

Yii provides its own logger that’s highly customizable and extensible. Using it, you can log various types of messages, filter them, and gather them at different targets, such as files or emails.

Using the Yii logging framework involves the following steps:

In this section, the focus in on the first two steps.

Log Messages

To record log messages, you need an instance of PSR-3 logger. A class that writes log messages should receive it as dependency:

class MyService
{
    private $logger;
    
    public function __construct(\Psr\Log\LoggerInterface $logger)
    {
        $this->logger = $logger;    
    }
}

Recording log message is as simple as calling one of the following logging methods that correspond to log levels:

Each method has two arguments. First is a message. The Second is a context array that typically has structured data that doesn’t fit a message well but still does offer important information. In case you provide exception as context, you should pass in “exception” key. Another special key is “category”. Categories are handy to better organize and filter log messages.

class MyService
{
    private $logger;
    
    public function __construct(\Psr\Log\LoggerInterface $logger)
    {
        $this->logger = $logger;    
    }

    public function serve(): void
    {
        $this->logger->info('MyService is serving', ['context' => __METHOD__]);    
    }
}

When deciding on a category for a message, you may choose a hierarchical naming scheme, which will make it easier for log targets to filter messages based on their categories. A simple yet effective naming scheme is to use the PHP magic constant __METHOD__ for the category names. This is also the approach used in the core Yii framework code.

The __METHOD__ constant evaluates as the name of the method (prefixed with the fully qualified class name) where the constant appears. For example, it’s equal to the string 'App\\Service\\MyService::serve' if the above line of code is called within this method.

Info: The logging methods described above are actually shortcuts to the [[\Psr\Log\LoggerInterface::log()]].

Note that PSR-3 package provides \Psr\Log\NullLogger class that provides the same set of methods but doesn’t log anything. That means that you don’t have to check if logger is configured with if ($logger !== null) and, instead, can assume that logger is always present.

Log Targets

A log target is an instance of a class that extends the [[\Yiisoft\Log\Target]]. It filters the log messages by their severity levels and categories and then exports them to some medium. For example, a [[\Yiisoft\Log\Target\File\FileTarget|file target]]exports the filtered log messages to a file, while an [[Yiisoft\Log\Target\Email\EmailTarget|email target]] exports the log messages to specified email addresses.

You can register many log targets in an application by configuring them through the \Yiisoft\Log\Logger constructor:

use \Psr\Log\LogLevel;

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);

$emailTarget = new \Yiisoft\Log\Target\Email\EmailTarget($mailer, ['to' => 'log@example.com']);
$emailTarget->setLevels([LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL]);
$emailTarget->setCategories(['Yiisoft\Cache\*']); 

$logger = new \Yiisoft\Log\Logger([
    $fileTarget,
    $emailTarget
]);

In the above code, two log targets are registered:

Yii comes with the following built-in log targets. Please refer to the API documentation about these classes to learn how to configure and use them.

In the following, we will describe the features common to all log targets.

Message Filtering

For each log target, you can configure its levels and categories to specify, which severity levels and categories of the messages the target should process.

The target setLevels() method takes an array consisting of one or several of \Psr\Log\LogLevel constants.

By default, the target will process messages of any severity level.

The target setCategories() method takes an array consisting of message category names or patterns. A target will only process messages whose category can be found or match one of the patterns in this array. A category pattern is a category name prefix with an asterisk * at its end. A category name matches a category pattern if it starts with the same prefix of the pattern. For example, Yiisoft\Cache\Cache::set and Yiisoft\Cache\Cache::get both match the pattern Yiisoft\Cache\*.

By default, the target will process messages of any category.

Besides allowing the categories by the setCategories() method, you may also deny certain categories by the setExcept() method. If the category of a message is found or matches one of the patterns in this property, the target will NOT process it.

The following target configuration specifies that the target should only process error and warning messages under the categories whose names match either Yiisoft\Cache\* or App\Exceptions\HttpException:*, but not App\Exceptions\HttpException:404.

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);
$fileTarget->setCategories(['Yiisoft\Cache\*', 'App\Exceptions\HttpException:*']);
$fileTarget->setExcept(['App\Exceptions\HttpException:404']);

Message Formatting

Log targets export the filtered log messages in a certain format. For example, if you install a log target of the class [[\Yiisoft\Log\Target\File\FileTarget]], you may find a log message similar to the following in the log file:

2020-12-05 09:27:52.223800 [info][application] Some message

Message context:

time: 1607160472.2238
memory: 4398536
category: 'application'

By default, log messages have the following format:

Timestamp Prefix[Level][Category] Message Context

You may customize this format by calling [[\Yiisoft\Log\Target::setFormat()|setFormat()]] method, which takes a PHP callable returning a custom formatted message.

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');

$fileTarget->setFormat(static function (\Yiisoft\Log\Message $message) {
    $category = strtoupper($message->context('category'));
    return "({$category}) [{$message->level()}] {$message->message()}";
});

$logger = new \Yiisoft\Log\Logger([$fileTarget]);
$logger->info('Text message', ['category' => 'app']);

// Result:
// (APP) [info] Text message

In addition, if you’re comfortable with the default message format but need to change the timestamp format or add custom data to the message, you can call the [[\Yiisoft\Log\Target::setTimestampFormat()|setTimestampFormat()]] and [[\Yiisoft\Log\Target::setPrefix()|setPrefix()]] methods. For example, the following code changes the timestamp format and configures a log target to prefix each log message with the current user ID (IP address and Session ID are removed for privacy reasons).

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$userId = '123e4567-e89b-12d3-a456-426655440000';

// Default: 'Y-m-d H: i: s.u'
$fileTarget->setTimestampFormat('D d F Y');
// Default: ''
$fileTarget->setPrefix(static fn () => "[{$userId}]");

$logger = new \Yiisoft\Log\Logger([$fileTarget]);
$logger->info('Text', ['category' => 'user']);

// Result:
// Fri 04 December 2020 [123e4567-e89b-12d3-a456-426655440000][info][user] Text
// Message context: ...
// Common context: ...
The PHP callable that’s passed to the [[\Yiisoft\Log\Target::setFormat() setFormat()]]
and [[\Yiisoft\Log\Target::setPrefix() setPrefix()]] methods has the following signature:
function (\Yiisoft\Log\Message $message, array $commonContext): string;

Besides message prefixes, log targets also append some common context information to each of the log messages. You may adjust this behavior by calling target [[\Yiisoft\Log\Target::setCommonContext()|setCommonContext()]] method, passing an array of data in the key => value format that you want to include in the by the log target. For example, the following log target configuration specifies that only the value of the $_SERVER variable will be appended to the log messages.

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$fileTarget->setCommonContext(['server' => $_SERVER]);

Message Trace Level

During development, it’s often desirable to see where each log message is coming from. You can achieve this by calling the [[\Yiisoft\Log\Logger::setTraceLevel()|setTraceLevel()]] method like the following:

$logger = new \Yiisoft\Log\Logger($targets);
$logger->setTraceLevel(3);

This application configuration sets trace level to be 3 so each log message will be appended with at most 3 levels of the call stack at which the log message is recorded. You can also set a list of paths to exclude from the trace by calling the [[\Yiisoft\Log\Logger::setExcludedTracePaths()|setExcludedTracePaths()]] method.

$logger = new \Yiisoft\Log\Logger($targets);
$logger->setExcludedTracePaths(['/path/to/file', '/path/to/folder']);

Info: Getting call stack information isn’t trivial. Therefore, you should only use this feature during development or when debugging an application.

Message Flushing and Exporting

As aforementioned, log messages are maintained in an array by [[\Yiisoft\Log\Logger|logger object]]. To limit the memory consumption by this array, the logger will flush the recorded messages to the log targets each time the array accumulates a certain number of log messages. You can customize this number by calling the [[\Yiisoft\Log\Logger::setFlushInterval()]] method:

$logger = new \Yiisoft\Log\Logger($targets);
$logger->setFlushInterval(100); // default is 1000

Info: Message flushing also occurs when the application ends, which ensures log targets can receive complete log messages.

When the [[\Yiisoft\Log\Logger|logger object]] flushes log messages to log targets, they don’t get exported immediately. Instead, the message exporting only occurs when a log target accumulates a certain number of the filtered messages. You can customize this number by calling the [[\Yiisoft\Log\Target::setExportInterval()|setExportInterval()]] method of individual log targets, like the following:

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$fileTarget->setExportInterval(100); // default is 1000

Because of the flushing and exporting level setting, by default when you call any logging method, you will NOT see the log message immediately in the log targets. This could be a problem for some long-running console applications. To make each log message appear immediately in the log targets, you should set both flush interval and export interval to be 1, as shown below:

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$fileTarget->setExportInterval(1);

$logger = new \Yiisoft\Log\Logger([$fileTarget]);
$logger->setFlushInterval(1);

Note: Frequent message flushing and exporting will degrade the performance of your application.

Toggling Log Targets

You can enable or disable a log target by calling its [[\Yiisoft\Log\Target::enable()|enable()] ] and [[\Yiisoft\Log\Target::disable()|disable()]] methods. You may do so via the log target configuration or by the following PHP statement in your code:

$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log');
$logger = new \Yiisoft\Log\Logger([$fileTarget, /*Other targets*/]);

foreach ($logger->getTargets() as $target) {
    if ($target instanceof \Yiisoft\Log\Target\File\FileTarget) {
        $target->disable();
    }
}

To check whether the log target is enabled, call the isEnabled() method. You also may pass callable to [[\Yiisoft\Log\Target::setEnabled()|setEnabled()]] to define a dynamic condition for whether the log target should be enabled or not.

Creating New Targets

Creating a new log target class is simple. You mainly need to implement the [[\Yii\Log\Target::export()]] abstract method that sends all accumulated log messages to a designated medium.

The following protected methods will also be available for child targets:

For more details, you may refer to any of the log target classes included in the package.

Tip: Instead of creating your own loggers, you may try any PSR-3 compatible logger such as Monolog by using [[\Yii\Log\PsrTarget]].

/**
 * @var \Psr\Log\LoggerInterface $psrLogger
 */

$psrTarget = new \Yiisoft\Log\PsrTarget($psrLogger);
$logger = new \Yiisoft\Log\Logger([$psrTarget]);

$logger->info('Text message');