Observability
| Signal | Where it comes from | Consumed by |
|---|---|---|
| Traces (spans) | Axial.Telemetry emitting on the Axial ActivitySource; Axial.Telemetry.JavaScript on Fable targets |
any ActivityListener, in practice the OpenTelemetry SDK; OpenTelemetry JS under Fable |
| Logs | the explicit ILog service, bridged to Microsoft.Extensions.Logging by Axial.Hosting |
your host's logging pipeline |
| Metrics | Axial.Telemetry: FiberMetrics and QueueMetrics on the Axial Meter |
OpenTelemetry's .AddMeter("Axial"), dotnet-counters, the Aspire dashboard |
| Fiber dumps | core Axial: FiberRegistry live-fiber snapshots, no telemetry dependency |
registry.DumpAt(Clock.live) on demand; FiberDumpTelemetry.record to put dumps on traces |
Two general-purpose channels feed those signals and are part of core Axial, not the telemetry
package: runtime annotations (Flow.annotate, ambient key–value diagnostics metadata) and fiber
observers (FiberObserver, lifecycle hooks for every forked fiber; see
Supervision and fiber observability).
How .NET tracing works: ActivitySource and ActivityListener
Axial publishes spans through .NET's System.Diagnostics tracing model:
- An
ActivitySourceis the producer. Axial owns one, named"Axial". Instrumented code callsStartActivity, and anActivityis a span: name, timing, tags, status, parent. - An
ActivityListeneris the consumer. Nothing is recorded until the application registers a listener that opts into a source by name and makes the sampling decision. With no interested listener,StartActivityreturnsnulland Axial skips all tagging work, so an untraced app pays roughly a null check per span site. Activity.Currentis an async-local holding the ambient span. New spans parent to it automatically, which is how Axial spans nest inside ASP.NET Core request spans (and under an upstreamtraceparentheader) with no wiring.
The host decides at the edge whether anything listens and where spans go; workflows do not carry a tracing dependency.
Setup and recipes
The Telemetry guide covers the runnable setup that this overview only maps:
span tag vocabulary and Activity.traceOn, OpenTelemetry wiring in ASP.NET Core and console hosts, the Aspire
dashboard walkthrough, and fiber metrics and dumps. The JavaScript guide
covers the Fable bootstrap and cross-stack traceparent propagation.
Correlation: how the signals join up
- Telemetry context → span attributes.
Context.withEndUserId,Context.withAttribute, andContext.withAttributesscope typed, searchable attributes around a workflow. Both the .NET and JavaScript adapters consume the same ambient context; no environment interfaces or runtime field discovery are involved. - Annotations → every observer.
Flow.annotate"payment.attempt" attemptIdis scoped runtime metadata, not a tracing call: any active trace (Activity.traceOn,Activity.trace, or a tracer's.Trace) tees annotations onto the active span asaxial.flow.annotation.*tags, and custom sinks (Flow.addAnnotationSink) can route the same values into log scopes or anywhere else.Flow.withTraceIdidsets the standardtrace_idannotation for a flow, andFlow.traceIdreads it back. See the runtime operations tutorial. - Fiber ids link spans. Workflow spans and fiber spans both carry
axial.flow.fiber.id(and fiber spansaxial.flow.fiber.parent_id), so fiber-lifecycle spans correlate with the workflows that forked them even when they are not parent/child in the trace tree.
Logs
Unlike tracing, logging uses an explicit ILog environment service so applications can substitute the logger.
- Workflows log through
Log.info/Log.error/Log.errorExn/... againstIHasLog. Axial.HostingbridgesILogtoMicrosoft.Extensions.Logging, exceptions included, so entries flow into the host's providers.FiberLogging.observeloggeris the logging counterpart ofFiberTelemetry.observe: fiber defects are logged as errors, unobserved defects as critical entries. Compose both from one edge install.
OpenTelemetry can also export MEL logs (builder.Logging.AddOpenTelemetry(...)), which pairs naturally with
the bridge: ILog → MEL → OTLP.
Metrics
FiberMetrics.observe (in Axial.Telemetry) records fiber starts, live counts, settlement, duration, and unobserved
defects onto the Axial Meter. Subscribe with .AddMeter("Axial"): a climbing fibers.live with flat
fibers.settled is a fiber leak, and a nonzero unobserved_defects rate is crashing background work nobody joins.
The instrument-by-instrument table is in the FiberMetrics reference.
Fiber dumps
A FiberRegistry (core Axial) tracks every live fiber below one edge install and answers "what is my runtime doing
right now?" with registry.DumpAt(clock) (a rendered tree) or registry.Snapshot() (structured values). The method
inventory — Settled, Stats, UnobservedDefects, StartedCount, Interrupt, InterruptByName, and the capacity
bound — is in the FiberRegistry reference. FiberDumpTelemetry.record attaches a
dump to the current trace.
Packaging and platform notes
Why is Axial.Telemetry a separate package? It is the only piece with a dependency beyond core
(System.Diagnostics.DiagnosticSource) and the only piece that is meaningless off .NET. Keeping it out of
Axial keeps the core dependency-free and Fable-compilable; keeping it out of Axial.Hosting
keeps tracing available to console scripts and workers that never touch the generic host. The seams follow
the signals: core owns the neutral channels (annotations, FiberObserver), Telemetry turns them into spans,
Hosting turns them into MEL logs.
Fable / JavaScript. System.Diagnostics.Activity does not exist in JavaScript, so
Axial.Telemetry (and Axial.Hosting) are .NET-only. The JavaScript counterpart is
Axial.Telemetry.JavaScript, which emits through OpenTelemetry JS instead, in Node and the browser
alike, with the same span semantics and axial.flow.* tag vocabulary. It never imports the npm module
itself: the application registers the OpenTelemetry JS SDK (exporter and context manager) and hands the
@opentelemetry/api object to Otel.installNamed once at the edge, the same host/library split as registering an
application ActivitySource on .NET. See the JavaScript guide for the
bootstrap and cross-stack propagation notes.
Where to go deeper
- Telemetry: span tag vocabulary,
Activity.traceWith, span-per-fiber details, metrics, dumps, and the Aspire walkthrough. - Supervision and fiber observability:
FiberObserver,Flow.supervise, unobserved-defect semantics. - Hosting: DI integration and the
ILog/MEL bridge. - Runtime operations tutorial: annotations, timeout, retry, cancellation in practice.

