To send your PHP logs to Datadog, log to a file and then tail that file with your Datadog Agent. This page details setup examples for the Monolog, Zend-Log, and Symfony logging libraries.
The following configuration enables JSON formatting and writes the logs and events into the application-json.log file. In your code, add a new handler after the initialization of the Monolog instance:
<?phprequire__DIR__.'/vendor/autoload.php';// load Monolog library
useMonolog\Logger;useMonolog\Handler\StreamHandler;useMonolog\Formatter\JsonFormatter;// create a log channel
$log=newLogger('channel_name');// create a Json formatter
$formatter=newJsonFormatter();// create a handler
$stream=newStreamHandler(__DIR__.'/application-json.log',Logger::DEBUG);$stream->setFormatter($formatter);// bind
$log->pushHandler($stream);// an example
$log->info('Adding a new user',array('username'=>'Seldaek'));
The following configuration enables the JSON formatting and writes the logs and events into the application-json.log file. In your code, add a new handler after the initialization of the Zend-Log instance.
<?phpuseZend\Log\Logger;useZend\Log\Writer\Stream;useZend\Log\Formatter\JsonFormatter;// create a logger
$logger=newLogger();// create a writer
$writer=newStream('file://'.__DIR__.'/application-json.log');// create a Json formatter
$formatter=newJsonFormatter();$writer->setFormatter($formatter);// bind
$logger->addWriter($writer);Zend\Log\Logger::registerErrorHandler($logger);
To configure the formatter in your Monolog configuration, declare the formatter field as follows:
If APM is enabled for this application, the correlation between application logs and traces can be improved by following the APM PHP logging instructions to automatically add trace and span IDs in your logs.
It can be useful to add additional context to your logs and events. Monolog provides methods for setting thread-local context that is then submitted automatically with all events. For example, to log an event with contextual data:
<?php$logger->info('Adding a new user',array('username'=>'Seldaek'));
Monolog’s pre-processor has a feature that is a simple callback and enriches your events with metadata you can set (for example, the session ID, or the request id):
<?php$log->pushProcessor(function($record){// record the current user
$user=Acme::getCurrentUser();$record['context']['user']=array('name'=>$user->getName(),'username'=>$user->getUsername(),'email'=>$user->getEmail(),);// Add various tags
$record['ddtags']=array('key'=>'value');// Add various generic context
$record['extra']['key']='value';return$record;});
It can be useful to add additional context to your logs and events. Zend-Log provides methods to set thread-local context that is then submitted automatically with all events. For example, to log an event with contextual data:
<?php$logger->info('Adding a new user',array('username'=>'Seldaek'));
Follow these steps to add variable context in your logs using a session processor.
Implement your session processor:
In the following example, the processor knows the current session and enriches the content of the log record with information such as the requestId, sessionId, and so on.
<?phpnamespaceAcme\Bundle\MonologBundle\Log;useSymfony\Component\HttpFoundation\Session\Session;classSessionRequestProcessor{private$session;private$sessionId;private$requestId;private$_server;private$_get;private$_post;publicfunction__construct(Session$session){$this->session=$session;}publicfunctionprocessRecord(array$record){if(null===$this->requestId){if('cli'===php_sapi_name()){$this->sessionId=getmypid();}else{try{$this->session->start();$this->sessionId=$this->session->getId();}catch(\RuntimeException$e){$this->sessionId='????????';}}$this->requestId=substr(uniqid(),-8);$this->_server=array('http.url'=>(@$_SERVER['HTTP_HOST']).'/'.(@$_SERVER['REQUEST_URI']),'http.method'=>@$_SERVER['REQUEST_METHOD'],'http.useragent'=>@$_SERVER['HTTP_USER_AGENT'],'http.referer'=>@$_SERVER['HTTP_REFERER'],'http.x_forwarded_for'=>@$_SERVER['HTTP_X_FORWARDED_FOR']);$this->_post=$this->clean($_POST);$this->_get=$this->clean($_GET);}$record['http.request_id']=$this->requestId;$record['http.session_id']=$this->sessionId;$record['http.url']=$this->_server['http.url'];$record['http.method']=$this->_server['http.method'];$record['http.useragent']=$this->_server['http.useragent'];$record['http.referer']=$this->_server['http.referer'];$record['http.x_forwarded_for']=$this->_server['http.x_forwarded_for'];return$record;}protectedfunctionclean($array){$toReturn=array();foreach(array_keys($array)as$key){if(false!==strpos($key,'password')){// Do not add
}elseif(false!==strpos($key,'csrf_token')){// Do not add
}else{$toReturn[$key]=$array[$key];}}return$toReturn;}}
Integrate the processor with Symfony by adding the following:
To integrate Monolog with your framework, add the following:
<?php// Check if the Monolog library is well loaded
//use Monolog\Logger;
//use Monolog\Handler\StreamHandler;
//use Monolog\Formatter\JsonFormatter;
// with the monolog instance
$monolog=...///// Log shipper configuration
$formatter=newJsonFormatter();$stream=newStreamHandler(__DIR__.'/application-json.log',Logger::DEBUG);$stream->setFormatter($formatter);$monolog->pushHandler($stream);return$r;
In your configuration directory /path/to/config/directory/, add the following to the config_dev.yml and config_prod.yml. Modify the example to configure it for your development and production environments.
# app/config/config.ymlmonolog:# Uncomment this section, if you want to use a Processor# Processor :# session_processor:# class: Acme\Bundle\MonologBundle\Log\SessionRequestProcessor# arguments: [ @session ]# tags:# - { name: monolog.processor, method: processRecord }json_formatter:class:Monolog\Formatter\JsonFormatterhandlers:# Log shipper configurationto_json_files:# log to var/logs/(environment).logtype:streampath:"%kernel.logs_dir%/%kernel.environment%.log"# includes all channels (doctrine, errors, and so on)channels:~# use json formatterformatter:monolog.json_formatter# set the log level (for example: debug, error, or alert)level:debug
In your configuration directory /path/to/config/directory/, add the following to the config_dev.yml and config_prod.yml. Modify the example to configure it for your development and production environments.
monolog:handlers:# Log shipper configurationto_json_files:# log to var/logs/(environment).logtype:streampath:"%kernel.logs_dir%/%kernel.environment%.log"# use json formatterformatter:monolog.json_formatter# set the log level (for example: debug, error, or alert)level:debug
The function \DDTrace\current_context() has been introduced in version 0.61.0.
Add the following:
<?phpnamespaceApp\Providers;useIlluminate\Support\ServiceProvider;classAppServiceProviderextendsServiceProvider{/**
* Register any application services.
*
* @return void
*/publicfunctionregister(){// Get the Monolog instance
$monolog=logger()->getLogger();if(!$monologinstanceof\Monolog\Logger){return;}// Optional: Use JSON formatting
$useJson=false;foreach($monolog->getHandlers()as$handler){if(method_exists($handler,'setFormatter')){$handler->setFormatter(new\Monolog\Formatter\JsonFormatter());$useJson=true;}}// Inject the trace and span ID to connect the log entry with the APM trace
$monolog->pushProcessor(function($record)use($useJson){$context=\DDTrace\current_context();if($useJson===true){$record['extra']['dd']=['trace_id'=>$context['trace_id'],'span_id'=>$context['span_id'],];}else{$record['message'].=sprintf(' [dd.trace_id=%d dd.span_id=%d]',$context['trace_id'],$context['span_id']);}return$record;});}/**
* Bootstrap any application services.
*
* @return void
*/publicfunctionboot(){//
}}
Add the following:
<?php// file: bootstrap
$app->extend('monolog',function($monolog,$app){$monolog->pushHandler(...);// configure your logger below
return$monolog;});
Add the following:
<?php//file: bootstrap/app.php
$app->configureMonologUsing(function($monolog){$monolog->pushHandler(...);// configure your logger below
});return$app;