Distributed tracing/Tutorial/Instrumenting your own application
Instrumenting MediaWiki code (core or extensions)
First, you'll need access to a TracerInterface object. Usually you would do this via access to a MediaWikiServices object, or you might do something in ServiceWiring.php -- if you aren't sure, ask aa MediaWiki expert.
Once you have a TracerInterface -- which might be a NoopTracer or a real Tracer, depending on if the request is being sampled for tracing -- the next thing you'll want to do is create a Span.
A Span is a span of time, with a start and an end timestamp, a name, perhaps some freeform key/value attributes, and also optionally a parent. Spans should correspond to some sort of operation you want to track: a database query, an RPC to another service, a computation that might last several milliseconds or more, etc. The name should be human-readable but concise, and not high in cardinality. Some more advice on this at the official OTel Tracing spec.
$span = $tracer->createSpan('Extension:Chart rendering');
This new span will automatically be attached to the most recently 'activated' span -- these are spans that represent synchronous, longer-running operations that are expected to produce many child spans. Examples of activated spans already in the codebase are holding PoolCounter locks, or running entry points, etc. Because entry points all create a span, you can almost always expect to have an activated parent span already available when writing MediaWiki code.
In this hypothetical case, we'll activate our new span, as it is a blocking operation that we expect to make database calls and call RPCs, and we'd like to associate those all with this span.
$span->start(); // time can be overridden, but defaults to now
$span->activate();
If you prefer, you can also use a fluent interface to set lots of data at once:
$span->setSpanKind(SpanInterface::SPAN_KIND_SERVER)
->setAttributes(['wiki' => $wiki, 'page' => $pageTitle, 'rev_id' => $revision])
->start()->activate();
Creating the span should happen right as you are about to begin the actual processing you're performing.
Since we've activated this span, any child spans created by other code will automatically be associated with it.
You can and should also append other attributes to your span as you perform processing. Another thing you can do is set the status of your span. Here's an example of annotating both in a span that encounters a critical exception that breaks the request:
catch (Exception $e) {
$span->setAttributes(['exception.message' => $e->message])
->setSpanStatus(SpanInterface::SPAN_STATUS_ERROR);
}
Errors are specially highlighted with a red warning icon in Jaeger, so they stand out, and they are also searchable.
Once your operation that you'd like to track is finished, you should both end() and deactivate() your span. MediaWiki will attempt to do this for you, but it's better to be explicit. It's usually best to do this in a finally {} block.
finally {
$span->end()->deactivate();
}