Skip to content

Tracer

Serinus uses an internal system to allow you to trace the request and response of your application. This system is called Tracer.

Create a Tracer

To start tracing a request, you need to create a class that extends the Tracer class and override the methods that you want to trace.

dart
import 'package:serinus/serinus.dart';

class ServerTimingTracer extends Tracer {
  final Map<String, int> _timings = {};

  ServerTimingTracer() : super('ServerTimingTracer');

  @override
  Future<void> onRequestReceived(TraceEvent event, Duration delta) async {
    _timings['${event.name.name}-${event.traced}'] = delta.inMilliseconds;
    return;
  }

  @override
  Future<void> onHandle(TraceEvent event, Duration delta) async {
    _timings['${event.name.name}-${event.traced}'] = delta.inMilliseconds;
    return;
  }

  @override
  Future<void> onAfterHandle(TraceEvent event, Duration delta) async {
    _timings['${event.name.name}-${event.traced}'] = delta.inMilliseconds;
    return;
  }

  @override
  Future<void> onResponse(TraceEvent event, Duration delta) async {
    _timings['${event.name.name}-${event.traced}'] = delta.inMilliseconds;
    String label = '';
    for (String event in _timings.keys) {
      label +=
          '$event;dur=${(_timings[event]?.isNegative ?? false) ? 0 : _timings[event]},';
    }

    event.context?.res.headers['Server-Timing'] = label;
  }
}

These are the methods that you can override:

MethodDescriptionCalled multiple times per lifecycle
onRequestReceivedCalled when a request is received.
onRequestCalled when a onRequest hook is executed
onParseCalled when the parse hook is executed
onMiddlewareCalled when a middleware is executed
onBeforeHandleCalled when the beforeHandle hook is executed
onHandlerCalled when the handler is executed
onAfterHandleCalled when the afterHandle hook is executed
onResponseCalled when the response is being closed
onCustomEventCalled when a custom event is being fired during the lifecycle

Using a Tracer

To use a tracer, you need to pass an instance of the tracer to the trace method of the SerinusApplication instance. You can add multiple tracers to the same application.

dart
import 'package:serinus/serinus.dart';

Future<void> main() async {
  final app = await serinus.createApplication(entrypoint: AppModule());
  app.trace(ServerTimingTracer());
  await app.serve();
}

TraceEvent

The TraceEvent class is a class that contains information about the current event that is being traced. This class is passed to the methods of the Tracer class.

The TraceEvent class has the following properties:

PropertyDescription
requestThe Request object of the current request. (Can be null)
contextThe RequestContext object of the current request. (Can be null)
nameThe name of the event.
startAtThe start DateTime of the event.
endAtThe end DateTime of the event. (Can be null)
tracedThe traced event.

The traced property follows a naming convention of:

  • r-* for route-related events (e.g. route handler, route hooks)
  • m-* for middleware-related events
  • h-* for hooks-related events (e.g. global hooks)

Create a Custom Event

You can create a custom event by wrapping the function you want to trace with the methods trace or traceAsync and passing the RequestContext and the name of the event.

dart
void myFunction() {
  // Your code here
}

trace(
    () => myFunction(), 
    context: context,
    name: 'myFunction'
)

The trace and traceAsync methods will return the result of the function that you passed to it and will also fire a custom event with the name that you passed.

Built with 💙 and Dart 🎯 | One of the 🐤 of Avesbox