Skip to main content

OpenTelemetry

Every ProtoTrace operation is also a .NET Activity on the ActivitySource named ProtoTest. ProtoTest.OpenTelemetry is a one-line bridge that subscribes an OpenTelemetry tracer to it, so test runs can land in the same backend as your application's telemetry.

dotnet add package ProtoTest.OpenTelemetry
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

The package targets .NET 8, 9 and 10 (the project template defaults to net10.0; pass -f net8.0 or net9.0 for an older runtime). It is a bridge, not an exporter: install the exporter you want separately.

using OpenTelemetry;
using OpenTelemetry.Trace;
using ProtoTest.OpenTelemetry;

public sealed class OpenTelemetryHook : IProtoRunHook
{
private TracerProvider? _provider;

public Task BeforeRunAsync(CancellationToken cancellationToken = default)
{
_provider = Sdk.CreateTracerProviderBuilder()
.AddProtoTestInstrumentation()
.AddOtlpExporter()
.Build();
return Task.CompletedTask;
}

public Task AfterRunAsync(CancellationToken cancellationToken = default)
{
_provider?.Dispose(); // flushes pending spans
return Task.CompletedTask;
}
}
builder.AddRunHook<OpenTelemetryHook>();

The package adds exactly one method — AddProtoTestInstrumentation(), which is AddSource("ProtoTest"). Exporters, sampling and resource attributes are ordinary OpenTelemetry configuration.

What's exported

ProtoTraceOpenTelemetry
an operationan Internal span
an eventan event on the span of its parent operation
a failed operationstatus Error, plus an exception event with type, message and stack trace
a succeeded operationstatus Ok

Spans nest the same way the ProtoTrace tree does: a test's test.setup, test.execution and test.teardown spans contain everything that happened in those phases, and an operation started in your test body is a child of test.execution — so one test is one connected trace in your backend.

Spans and events carry these tags:

Tag
prototest.test.idthe test id
prototest.entry.idthe ProtoTrace entry id
prototest.entry.kinde.g. web.click
prototest.sourcethe integration that wrote it
prototest.phasesetup, execution, teardown, rollback or run
prototest.outcomesucceeded, failed, partial, cancelled, skipped or unknown
prototest.logical_parent_idthe ProtoTrace parent entry id (spans only)
prototest.entity.kind, prototest.entity.idthe client, context, server or capability an entry belongs to, when it has one
prototest.entry.counthow many identical error-free events collapsed into one entry

The operation's own trace attributes — http.method, web.locator, your custom ones — are exported as tags too, except values longer than 2,048 characters and the large structured ones (shape snapshots, serialised context state, observation data). Those stay in the .prototrace file only, so spans remain lightweight.

Correlating with your application

Because operations are real Activity instances, HttpClient's standard W3C trace-context propagation applies to requests sent while one is current. If your application is instrumented with OpenTelemetry too, that is what lets its server spans line up under the test step that caused them — this end-to-end path isn't covered by the repository's tests yet, so treat it as expected rather than guaranteed.

Limits

  • No exporter included. The package only subscribes the ProtoTest source; install the exporter you want, as above.
  • Large values stay out of spans. Values longer than 2,048 characters and the structured keys context.value, observation.data, observation.metadata, shape.expected, shape.actual, shape.matches and shape.mismatches exist only in .prototrace. The same cap applies to spans captured from your application.
  • The .prototrace archive is unaffected. Tracing stays on by default and remains the complete record; OpenTelemetry is a second consumer of the same operations.
  • Propagation into the application is expected, not proven. The end-to-end W3C path is not covered by the repository's tests.