Flexible logging with TYPO3

tl;dr TYPO3 offers a simple API to create a flexible logging setup. Developers may write a log file with just two lines of code, and configure custom logging endpoints for individual classes.

Sometimes it is necessary to write logs in an extension. For example if a script imports data periodically, the developer may want to log all status messages of the import action, like “Import successfull”.

The obvious solution is to write a custom logging method, which appends such status messages to a defined file. The pitfall of this solution is, that this logging method is fixed, and tied to one extension only. Other extensions may use different files and different formats.

Another, often used solution was the \TYPO3\CMS\Core\Utility\GeneralUtility::devLog method, provided by the TYPO3 core. This method did not log anything, but offered a hook for extensions, to pass log messages to handlers of the these extensions. The very popular extension »devlog« has a handler which saves all messages to a database table and offers a backend module to list and filter these entries. This is usefull in development, but should never be used in production as this may blow up the database very fast.

Since version 6.0 TYPO3 offers a simple logging API, which has the huge advantage that the logging endpoints may be set independently of the extension which called the logger.

To use the logger in a class, two lines of code are sufficient:

$logger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Core\Log\LogManager')->getLogger(__CLASS__);
$logger->info('Everything is fine.');

The logger offers several severity levels. The info method is a shorthand which passes the level \TYPO3\CMS\Core\Log\LogLevel::INFO to the main log method. It is also possible to pass data bound to an array, for both the main- and the shorthand method:

$logger->log(
  \TYPO3\CMS\Core\Log\LogLevel::ERROR,
  'Everything is burning!',
  ['foo' => 'hello world']
);
// …or shorthand
$logger->error(
  'Everything is burning!',
  ['foo' => 'hello world']
);

By default TYPO3 will write the log to a log file. The filename schema is typo3temp/logs/typo3_<hash>.log and it's content may look like this:

Fri, 08 Mar 2013 09:45:00 +0100 [INFO] request="5139a50bee3a1" component="SomeController": Everything is fine.
Fri, 08 Mar 2013 09:45:00 +0100 [ERROR] request="5139a50bee3a1" component="SomeController": Everything is burning! - {"foo":"bar"}

The way to write log messages is configured in $GLOBALS['TYPO3_CONF_VARS']['LOG']['writerConfiguration']. This array may be modified in the AdditionalConfiguration.php file or in the ext_localconf.php file of your extension.

TYPO3 offers several log writers like a database logger or a file logger out of the box. It is possible to configure different loggers for each severity level, or concat loggers for the same severity level. It is even possible to set up custom logging for single classes.

In the following example code the system is writing all »error« log messages to a file and to the PHP error log using error_log(). If the installation has the application context »Development«, then all »info« messages are written to a file as well.

$GLOBALS['TYPO3_CONF_VARS']['LOG']['writerConfiguration'] = [
  \TYPO3\CMS\Core\Log\LogLevel::ERROR => [
    \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
      'logFile' => 'typo3temp/logs/typo3_error.log'
    ],
    \TYPO3\CMS\Core\Log\Writer\PhpErrorLogWriter::class => []
  ],
];

if(\TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext()->isDevelopment()) {
  $GLOBALS['TYPO3_CONF_VARS']['LOG']['writerConfiguration'][\TYPO3\CMS\Core\Log\LogLevel::INFO] = [
    \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
      'logFile' => 'typo3temp/logs/typo3_info.log'
    ]
  ];
}

The next example log configuration will write all error log calls coming from classes with a namespace beginning with T3docs\Examples\Controller to a dedicated log file:

$GLOBALS['TYPO3_CONF_VARS']['LOG']['T3docs']['Examples']['Controller']['writerConfiguration'] = [
  \TYPO3\CMS\Core\Log\LogLevel::ERROR => [
    \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
      'logFile' => 'typo3temp/logs/docs_examples_error.log'
    ]
  ]
];

As you can see, you may freely loosen or restrict the namespace to use for your writer configuration.

It is possible to modify all log messages as well, for example to add additional information like a backtrace or server environment variables to every log call.

The logging API also allows writing custom log writers. If some fancy writers are desired, then it is advantageous to take a look at EXT:logging. This extension adds the »Monolog« package to TYPO3, which allows actions like logging warning messages in a file, send errors of class X to a Slack channel and errors of class Y to an E-Mail recipient.

Update: Daniel Siepmann wrote a configuration snippet to pass all devLog calls to the logging API and write them into a file. This replaces the devlog extension and has the advantage that the configuration may be limited to testsystem using a condition.

Update: Since version 9 TYPO3 offers a trait to automatically instantiate the logger in classes.

use Psr\Log\LoggerAwareTrait;

class Example implements \Psr\Log\LoggerAwareInterface
{
  use LoggerAwareTrait; // use the trait to instantiate the logger

  protected function myFunction() {
    $this->logger->info('hello world'); // log right away
  }
}

Update: A best practice for composer based installations is to make use of the temporary file storage outside the document root:

'logFile' => \TYPO3\CMS\Core\Core\Environment::getVarPath() . '/log/typo3_error.log'

⌛ Warning! This post is old. The information may be outdated.

No comments on this notepad. If you would like to add something, then dont hesitate to contact me via E-Mail or Twitter.