Symfony request logger
What is it?
Any apps we write will, quite often, have cause to make external calls to either our own, or third-party, APIs. This Symfony bundle makes it easy to track how long these requests are taking and return the result via either monolog and/or an additional JSON object that's appended to your output when Symfony's in debug mode., (*1)
It works by adding extra middleware to Guzzle so we can track when a request is made and either succeeds or fails, and then storing these logs for later output., (*2)
How to set it up
Basic setup
There are a few different options for using this request logger. The most simple is to log all requests made via Guzzle, and then recall the logs later., (*3)
To do this, add / update the following services. If you've already got a Guzzle service, then update it as required:, (*4)
services:
dittto.request_logger.alias:
alias: 'dittto.request_logger'
http_client:
class: GuzzleHttp\Client
arguments:
- handler: '@http_client.handlerstack'
connect_timeout: 5
timeout: 5
http_client.handlerstack:
class: GuzzleHttp\HandlerStack
factory: [ GuzzleHttp\HandlerStack, 'create' ]
calls:
- [ 'push', [ '@dittto.request_logger.middleware.request' ] ]
What does this do then? The first service is to define which version of the request logger we're going to use. dittto.request_logger
is the most basic form of LoggerInterface
that simply stores all requests for later., (*5)
After that, we create a Guzzle client, and then make sure our middleware has been added to it, so we can store our API request attempts., (*6)
To use this, you'd probably do something like:, (*7)
services:
test_controller:
class: AppBundle\Controller\TestController
arguments: [ '@http_client', '@dittto.request_logger.alias' ]
<?php
class TestController {
private $client;
private $logger;
public function __construct(ClientInterface $client, RetrievableLogsInterface $logger) {
$this->client = $client;
$this->logger = $logger;
}
public function index()
{
$this->client->request('GET', 'https://api-path');
var_dump($this->logger->getLogs());
}
}
With monolog
Above shows how to use it and deal with the result yourself. Realistically, you're going to want to automatically output the request logger one way or another., (*8)
We'll use monolog to output our logged messages this time. To begin with, let's create a unique monolog channel for all of these messages:, (*9)
monolog:
channels:
[ "external_request" ]
Next, create the following services. If you've already defined Guzzle then just pick and choose the settings you wish to use:, (*10)
services:
dittto.request_logger.alias:
alias: 'dittto.request_logger.passthrough'
dittto.request_logger.monolog_channel:
alias: 'monolog.logger.external_request'
http_client:
class: GuzzleHttp\Client
arguments:
- handler: '@http_client.handlerstack'
connect_timeout: 5
timeout: 5
http_client.handlerstack:
class: GuzzleHttp\HandlerStack
factory: [ GuzzleHttp\HandlerStack, 'create' ]
calls:
- [ 'push', [ '@dittto.request_logger.middleware.request' ] ]
Note that the changes this time are to the first two services. The alias now references dittto.request_logger.passthrough
which allows us to save our logged messages to both our request logger, and monolog., (*11)
The second service is an alias to the new monolog channel we created above., (*12)
Now if you run your code, both monolog will save changes and the request logger has them available via getLogs()
., (*13)
If you're just going to use monolog for recording those messages, then you can use just the guzzle middleware instead of everything else. This is done using the following services:, (*14)
services:
http_client:
class: GuzzleHttp\Client
arguments:
- handler: '@http_client.handlerstack'
connect_timeout: 5
timeout: 5
http_client.handlerstack:
class: GuzzleHttp\HandlerStack
factory: [ GuzzleHttp\HandlerStack, 'create' ]
calls:
- [ 'push', [ '@dittto.request_logger.middleware.request.monolog_only' ] ]
dittto.request_logger.middleware.request.monolog_only:
class: Closure
factory: [ '@dittto.request_logger.middleware', 'onRequest' ]
arguments: [ '@monolog.logger.external_request' ]
JSON debug object
If you're building, maintaining, and debugging a lot of JSON APIs, then you can have this plugin automatically add your request logs to your JSON output when Symfony is in debug mode., (*15)
Add the following service to your app to capture valid responses and update your JSON:, (*16)
services:
dittto.request_logger.debug_listener:
class: Dittto\RequestLoggerBundle\Listener\JSONDebugListener
arguments: [ '@dittto.request_logger', '%kernel.debug%' ]
tags:
- { name: kernel.event_listener, event: kernel.response, method: 'onKernelResponse' }