Distributed Tracing (Activity API)
A centralized
System.Diagnostics.ActivitySourceand OTel-semantic attribute constants for correlating Typhon with an application's own OTLP trace.
Status: ๐ง Partial ยท Visibility: Public ยท Level: ๐ต Core ยท Category: Observability
๐ฏ What it solves
Diagnosing a slow or failed operation across a whole application usually means correlating "what the app asked for"
with "what happened downstream" โ an HTTP handler, a gRPC call, a database operation, all as one connected trace
instead of separate, timestamp-correlated logs. TyphonActivitySource gives host applications a ready-made,
OTel-semantic ActivitySource to fold their own Typhon-adjacent instrumentation into, using the same attribute
naming (typhon.transaction.tsn, typhon.entity.id, ...) the engine's other observability surfaces use, exportable
to any OTLP backend (Jaeger, Grafana Tempo, etc.) alongside the rest of the application's trace.
โ๏ธ How it works (in brief)
TyphonActivitySource.Instance is a single System.Diagnostics.ActivitySource (name Typhon.Engine); TyphonSpanAttributes
supplies matching OTel-semantic attribute-name constants (transaction, entity, index, page-cache, ECS). Spans started on it
nest automatically under whatever Activity.Current the host already has open โ no explicit context plumbing โ and export
through the standard OpenTelemetry SDK. The engine itself does not yet call this source internally: Transaction, Entity,
B+Tree, and page-cache operations are instrumented instead through the engine's own Typed-Event Profiler
(TyphonEvent) โ a separate, higher-throughput, non-OTel pipeline consumed by the Typhon Workbench rather than an OTLP
backend. The Profiler does capture Activity.Current's trace context when a host span is open, so its records nest under
an application's OTel trace for correlation, but no engine operation materializes as an Activity on this ActivitySource
today; it exists for hosts that want to add their own manually-instrumented spans using the same naming convention.
๐ป Usage
// Program.cs / host startup โ register Typhon's source with the OTel SDK
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService("MyApp"))
.WithTracing(tracing => tracing
.AddSource(TyphonActivitySource.Name) // "Typhon.Engine"
.AddOtlpExporter(o => o.Endpoint = new Uri("http://localhost:4317")));
// Manual instrumentation of your own code, nesting under the same source and attribute convention
using var activity = TyphonActivitySource.Instance.StartActivity("MyApp.CustomStep");
activity?.SetTag(TyphonSpanAttributes.EntityId, entityId);
| Attribute group | Constants | Typical use |
|---|---|---|
| Transaction | TransactionTsn, TransactionStatus, TransactionComponentCount, TransactionConflictDetected |
Tagging a host-defined span around a UoW |
| Entity | EntityId, ComponentType, ComponentRevision, ReadFound |
Tagging a host-defined span around an ECS operation |
| Index | IndexName, IndexOperation, IndexNodeSplit, IndexNodeMerge |
Tagging a host-defined span around an index operation |
| Page cache | PageId, PageSource, CacheHit |
Tagging a host-defined span around a storage operation |
โ ๏ธ Guarantees & limits
- No engine-internal spans yet โ
TyphonActivitySourceis real, callable API, but nothing inTyphon.EnginecallsStartActivityon it today; Transaction/Entity/B+Tree/page-cache visibility comes from the Typed-Event Profiler instead, which is not exported via OTLP. Treat this feature as attribute-naming + correlation infrastructure for your own spans, not as auto-instrumentation. StartActivityreturnsnullwith no listener registered โ always use?.(activity?.SetTag(...)); this is standardActivityAPI behavior, not Typhon-specific.- ~150โ250 ns per span when enabled โ
Activityallocation cost if you do start spans on this source; too heavy for per-row hot loops, where the Profiler's ~25โ50 ns/event typed records are the right tool instead. - WAL and Checkpoint spans are not yet designed as
Activityspans โtyphon.wal.flushandtyphon.checkpointexist only as Profiler event kinds, not on this OTel-facing surface. - Standard
Activity.Current/AsyncLocal<Activity>semantics apply โ spans started on a worker thread inherit whatever activity was current on the thread that scheduled the work; this is .NET runtime behavior, not configurable.
๐ Related
- Sibling: Telemetry Configuration & Gating โ gates whether this
ActivitySource's spans (and the Profiler) are active - Sibling: Profiler โ the typed-event pipeline that actually instruments engine internals today; this
ActivitySourcedoesn't yet