A Zipkin instrumentation for Symfony applications
composer require jcchavezs/zipkin-instrumentation-symfony
This Symfony bundle provides a kernel listener that can be used to trace
HTTP requests. In order to use it, it is important that you declare
the listener by adding this to your app/config/services.yml
or any other
dependency injection declaration.
services:
tracing_kernel_listener:
class: ZipkinBundle\KernelListener
arguments:
- "@zipkin.default_http_server_tracing"
- "@zipkin.route_mapper"
- "@logger"
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 2560 }
- { name: kernel.event_listener, event: kernel.response, priority: -2560 }
- { name: kernel.event_listener, event: kernel.exception }
- { name: kernel.event_listener, event: kernel.terminate }
@zipkin.default_tracing
is a Zipkin\DefaultTracing
instance which is being
built based on the configuration (add this to app/config/config.yml
):
zipkin:
noop: false # if set to true, no request will be traced
service_name: my_service # the name of the service
sampler:
type: percentage
percentage: 0.1
Besides always
, and never
there are three other sampling strategies: by path, by route and by percentage, however it is also possible yo use your own sampler.
It is important to mention that the sampling decision is made on two situations: a) when a new trace is being started, b) when the extracted context does not include a sampling decision.
This is for those cases where you want to make a sampling decision based on the url path:
zipkin:
...
sampler:
type: path
path:
included_paths:
- "/my/resource/[0-9]"
excluded_paths:
- "/another/path/"
This sampler uses the Symfony\Component\HttpFoundation\RequestStack
meaning that it won't work in event loop enviroments. For event loop environments, use a requestSampler
in the HTTP Server Tracing.
This is for those cases where you want to make a sampling decision based on the symfony route:
zipkin:
...
sampler:
type: route
route:
included_routes:
- "my_route"
excluded_routes:
- "another_route"
This sampler uses the Symfony\Component\HttpFoundation\RequestStack
meaning that it won't work in event loop enviroments. For event loop environments, use a requestSampler
in the HTTP Server Tracing.
This one is for those cases where you want to sample only a percentage of the requests (a.k.a "Sampling rate")
zipkin:
...
sampler:
type: percentage
percentage: 0.1
You can pass a custom sampler as long as it implements the Zipkin\Sampler
interface. You just need to use the service id
declared in the service container.
zipkin:
...
sampler:
type: custom
custom: my_service_name
By default, the bundle reports to Log
reporter which wraps @logger
.
This is the most common use case, it reports to a HTTP backend of Zipkin
zipkin:
...
reporter:
type: http
http:
endpoint_url: http://zipkin:9411/api/v2/spans
timeout: ~
You can add tags to every span being created by the tracer. This functionality is useful when you need to add tags like instance name.
services:
tracing_kernel_listener:
class: ZipkinBundle\KernelListener
arguments:
- "@zipkin.default_http_server_tracing"
- "@zipkin.route_mapper"
- "@logger"
- { instance: %instance_name% }
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 2560 }
- { name: kernel.event_listener, event: kernel.response, priority: -2560 }
- { name: kernel.event_listener, event: kernel.exception }
- { name: kernel.event_listener, event: kernel.terminate }
Although this bundle provides a tracer based on the configuration parameters
under the zipkin
node, you can inject your own tracing component
to the
kernel listener as long as it implements the Zipkin\Tracing
interface:
services:
tracing_kernel_listener:
class: ZipkinBundle\KernelListener
arguments:
- "@my_own_http_server_tracing"
- "@zipkin.route_mapper"
- "@logger"
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 2560 }
- { name: kernel.event_listener, event: kernel.response, priority: -2560 }
- { name: kernel.event_listener, event: kernel.exception }
- { name: kernel.event_listener, event: kernel.terminate }
By default spans include usual HTTP information like method, path or status code but there are cases where user wants to add more information in the spans based on the request (e.g. request_id
or a query parameter). In such cases one can extend the HttpServerParser
to have access to the request and tag the span:
services:
search.http_server_tracing:
class: Zipkin\Instrumentation\Http\Server\HttpServerTracing
arguments:
- "@zipkin.default_tracing"
- "@zipkin.route_mapper"
- "@search_http_parser" # my own parser
tracing_kernel_listener:
class: ZipkinBundle\KernelListener
arguments:
- "@search.http_server_tracing"
- "@logger"
- { instance: %instance_name% }
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 2560 }
- { name: kernel.event_listener, event: kernel.response, priority: -2560 }
- { name: kernel.event_listener, event: kernel.exception }
- { name: kernel.event_listener, event: kernel.terminate }
search_http_parser:
class: My\Search\HttpServerParser
and the parser would look like:
namespace My\Search;
use Zipkin\Instrumentation\Http\Server\DefaultHttpServerParser;
use Zipkin\Instrumentation\Http\Server\Response;
use Zipkin\Instrumentation\Http\Server\Request;
use Zipkin\Propagation\TraceContext;
use Zipkin\SpanCustomizer;
final class HttpServerParser extends DefaultHttpServerParser {
public function request(Request $request, TraceContext $context, SpanCustomizer $span): void {
parent::request($request, $context, $span);
if (null !== ($searchKey = $request->getHeader('search_key'))) {
$span->tag('search_key', $searchKey);
}
}
}
This bundle includes an adapter for HTTP Client. For more details, read this doc.
All contributions and feedback are welcome.
Run the unit tests with:
composer test
On every build we run a end to end (E2E) test against a symfony application.
This test run in our CI tests but it can be also reproduced in local.