Skip to content


In your code you may wish to record events for debuggers or system admins.

CiviCRM has a logging interface that implements psr3.

By default, these will log to files in the ConfigAndLog directory. However, sites can implement alternative logging using listeners (see further down).

Best practice when logging in your code looks like this

  \Civi::log('smarty')->debug('smarty escaping original {original}, escaped {escaped} type {type} charset {charset}', [
    'original' => $string,
    'escaped' => $value,
    'type' => $esc_type,
    'charset' => $char_set,

Note that

1) The priority in this example is debug priority level. There are 8 levels in the psr3 specification and the calls to them just use the error level as the method (e.g Civi::log()->error()). Here is a useful explainer on the levels

2) Use words, not abbreviations for variable names and use underscores (not camel case). Even if the variable is something weird & wonderful like $cType the string should be {contact_type}

3)The optional channel is defined. If you just use \Civi::log() it will use the default channel. The impact of specifying the channel is that a) extensions (such as monolog) can implement per-channel logging configuration and b) absent any non core handling each channel is logged to a separate file. It is recommended that in your own code you use one or more channels to segment the logging output. Channels do not need to be pre-defined

4) The use of parameterisation - you should put each variable in curly braces ({}) and then put the expanded version in an array. (Also note that a psr3) requirement is that the key name is exception if it holds an exception).

5) Core does not use separate channels extensively - this is historical & perhaps on the basis of not wanting to change the behaviour pro-actively in case changes site-specific concerns of some sort.

6) There are other logging methods used in core like CRM_Core_Error::debug_log_message and CRM_Core_Error::debug_var. These are old methods and should be swapped out over time.

Customising logging output

It is possible to change how logging output is handled with listeners.

For example the monolog extension allows different logging channels to be logged in different ways and to use features such as browser logging and command line verbosity.

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

function monolog_civicrm_container(ContainerBuilder $container) {
  $container->setDefinition('psr_log_manager', new Definition('\Civi\MonoLog\MonologManager', []))->setPublic(TRUE);