NAME
Dancer2::Plugin::OpenTelemetry - Use OpenTelemetry in your Dancer2 app
SYNOPSIS
use Dancer2;
use Dancer2::Plugin::OpenTelemetry;
# Or via config, probably in your config file
BEGIN {
set plugins => {
OpenTelemetry => {
tracer => {
# Tracer parameters, see below
},
},
};
}
# Will generate a span named
# GET /static/url
get '/static/url' => sub { 'OK' };
# Will use placeholders for reduced span cardinality
# POST /url/with/:placeholder
post '/url/with/:placeholder' => sub { 'OK' }
# Use it also with async actions!
get '/async' => sub {
delayed {
flush;
content 'Hello ';
content 'World';
done;
}
};
# Errors will be correctly captured in the span
get '/error' => sub {
die 'oops';
};
dance;
DESCRIPTION
This plugin allows a Dancer2 application to automatically generate telemetry data using the OpenTelemetry API. The plugin will add a "before" hook and "after" hook to capture telemetry data about handled requests in a OpenTelemetry::Trace::Span object. Errors will be captured via an "on_route_exception" hook, which will set the span status accordingly.
During the "before" hook, a server span will be created and injected into the current context, together with any propagation data retrieved from the incoming request headers by the currently installed propagator.
The value of the tracer
parameter set in the plugin configuration will be used to obtain a tracer via "tracer" in OpenTelemetry::Trace::TracerProvider. Setting this is optional. If no value is set, the name will be read from the "OTEL_SERVICE_NAME" environment variable. If this variable is also not set, it will default to "dancer2". The name is the only parameter that has a default: all other values will be left unspecified.
The name of the generated span will be derived from the current request method, and the "spec_route" of the request's route, as in GET /foo/:bar
, to reduce the span cardinality.
The span will be created with the following attributes, which will therefore be available for any sampling decision.
http.request.method
-
Set to the request method. It will be the same value that was concatenated to the route in the span's name.
network.protocol.version
-
Set to the version number of the request protocol.
url.path
-
Set to the path of the request URL. This will be the raw path, without using any placeholders. It will not include the query string.
url.scheme
-
Set to the scheme of the request URL.
http.route
-
Set to the "spec_route" of the request's route. This will use placeholders, and will be the same value that was concatenated to the method in the span's name.
client.address
-
Set to the request's address.
server.address
-
Set to the host portion of the
host
value in the leftmost entry in theForwarded
header, falling back to the value of theX-Forwarded-Proto
header, or to the value of theHost
header if no other is set. The host portion is the part before an optional port number.See the semantic conventions entry for this attribute for more details on this logic.
If no value could be determined, this attribute will not be present.
server.port
-
Set to the port number in the
host
value in the leftmost entry in theForwarded
header, falling back to the value of theX-Forwarded-Proto
header, or to the value of theHost
header if no other is set.See the semantic conventions entry for this attribute for more details on this logic.
The port number in these is optional. If none is set, or none could be determined, this attribute will not be present.
user_agent.original
-
Set to the value of the user agent header. If not set, this attribute will not be present.
url.query
-
Set to the query of the request URL, if present. If the URL had no query parameters, this attribute will not be present.
The attributes described below will be set in the span once the action is completed, but will not be available for the sampler.
error.type
-
If an error is encountered during the execution of the action, this attribute will be set to the package name of the error (as reported by "ref"), or the value
string
if the error is not blessed into any package.If there were no errors, this attribute will not be present.
http.response.status_code
-
Set to the status code of the response. If an error was encountered while handling the request, this will be set to
500
.
The span will be unconditionally ended after the action has completed, and the status will be set to an error status if the response result in a server error (any HTTP status greater than or equal to 500).
If an exception is raised during the execution of the action, this will be caught and the description of the error status will be based on the message in that exception (otherwise no description will be set). The description will contain the first line of the exception body, minus any trailing markers of where the error took place, with the aim to make it safe to be exposed without leaking too much internal information.
Any exceptions caught by this integration will be re-thrown to be handled downstream.
Internal redirects
Dancer2 supports the use of keywords to internally forward a request from one handler to another, or to pass from one handler to another. In this case, this plugin will only execute for the first matching route. The following handlers will continue to be executed as expected, but the plugin will ignore them.
This is done on the assumption that the requests that are of interest from a telemetry point of view are those that come from outside the application.
Users for which this is undesirable are free to create new spans for those routes that this plugin would otherwise ignore.
SEE ALSO
- Dancer2
- Dancer2::Plugin
- OpenTelemetry
- OpenTelemetry::Context
- OpenTelemetry::Constants
- OpenTelemetry::Trace::Span
- OpenTelemetry::Trace::Tracer
- OpenTelemetry::Trace::TracerProvider
Integrations with other web frameworks
- Plack::Middleware::OpenTelemetry
-
A lower-level, Plack-based implementation of the same idea behind this plugin. Because it executes outside the scope of Dancer2, it will not have access to the routes with placeholders at span-creation time, but it's worth a look.
- Mojolicious::Plugin::OpenTelemetry
-
A similar version of this plugin, but integrating with the Mojolicious web framework.
COPYRIGHT AND LICENSE
This software is copyright (c) 2023 by José Joaquín Atria.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.