Contao uses Monolog and the Symfony Monolog Bundle. Monolog provides a standardized and simple, yet flexible and extensible solution to log messages and process them through a variety of sources.
You can use all features of Monolog and the Monolog Bundle in your Contao application.
In more complex applications, log channels are used to group related messages and optionally process them differently.
A Symfony application typically uses channels such as request
or security
to assign messages to the appropriate parts of the application.
Contao itself uses the contao
channel for all Contao-specific messages.
Contao also creates additional log channels for sending messages with a specific context. For more information, see Contao channels.
The system log in the Contao back end lists all log entries that have been specifically flagged for Contao. This flagging is done via a special context that is attached to a particular log entry:
use Contao\CoreBundle\Monolog\ContaoContext;
$logger->info(
'This message is intended for the Contao system log',
['contao' => new ContaoContext(__METHOD__, ContaoContext::GENERAL)]
);
All messages with this ContaoContext
are automatically sent to the system log
and do not appear in the regular log files of the application.
In addition to the mere tagging, the ContaoContext
also offers the possibility to add
custom meta information to a message.
In the example shown above, a reference to the triggering method __METHOD__
and the action
ContaoContext::GENERAL
are added alongside the text message.
This feature is available in Contao 4.13 and later.
To conveniently create log entries without having to manually define the appropriate context, Contao provides pre-configured logger services.
For example, to log messages with a proper ContaoContext
and the action CRON
,
you have the following options:
You can tag your service with the appropriate Monolog tag to automatically receive a logger that sends messages to a specified channel.
# config/services.yaml
services:
App\MyService:
arguments:
- '@?logger'
tags:
- { name: monolog.logger, channel: contao.cron }
If the channel of the logger starts with contao.
, messages to the channel are
automatically assigned a matching ContaoContext
.
The text after the contao.
part determines the action of the ContaoContext
.
In addition to the action, log messages in these channels are automatically supplied with a reference to the triggering method.
Example:
The channel contao.cron
configures all messages with the action ContaoContext::CRON
and a reference to the triggering method. Thus, messages within this channel will appear
in the system log with the action CRON
.
If you don’t want to tag your service or if your service has to send messages to multiple log channels you may also use Autowiring to get one or multiple matching logger service(s):
use Psr\Log\LoggerInterface;
// Parameter must match Psr\Log\LoggerInterface $<camelCased channel name> + Logger
public function __construct(
private readonly LoggerInterface $contaoCronLogger,
private readonly LoggerInterface $contaoErrorLogger,
) {
}
If you do not want to use autowiring, you can also define the appropriate logger(s) in the service configuration:
# config/services.yaml
services:
App\MyService:
arguments:
- '@monolog.logger.contao.cron'
- '@monolog.logger.contao.error'
Please note that you can only use existing log channels in this way. The following channels are provided by Contao out of the box:
contao.access
contao.configuration
contao.cron
contao.email
contao.error
contao.files
contao.forms
contao.general
You may add additional channels in your application configuration.
Thanks to Monolog, all log actions are fully customizable. Depending on your requirements, you may add your own handlers, formatters or processors.
For a start, you can take a look at Contao\CoreBundle\Monolog\ContaoTableProcessor
and Contao\CoreBundle\Monolog\ContaoTableHandler
to see how Contao prepares certain
messages for the system log (processor) and writes them to the tl_log
table (handler).
Generally, a logger should always be configured as an optional dependency. This way you can simply ignore the logger in tests.
If you still need a logger in your tests, there are two options:
Psr\Log\NullLogger
.Psr\Log\LoggerInterface
.