TimeWarp.State.Telemetry
12.0.0-beta.5
Prefix Reserved
dotnet add package TimeWarp.State.Telemetry --version 12.0.0-beta.5
NuGet\Install-Package TimeWarp.State.Telemetry -Version 12.0.0-beta.5
<PackageReference Include="TimeWarp.State.Telemetry" Version="12.0.0-beta.5" />
<PackageVersion Include="TimeWarp.State.Telemetry" Version="12.0.0-beta.5" />
<PackageReference Include="TimeWarp.State.Telemetry" />
paket add TimeWarp.State.Telemetry --version 12.0.0-beta.5
#r "nuget: TimeWarp.State.Telemetry, 12.0.0-beta.5"
#:package TimeWarp.State.Telemetry@12.0.0-beta.5
#addin nuget:?package=TimeWarp.State.Telemetry&version=12.0.0-beta.5&prerelease
#tool nuget:?package=TimeWarp.State.Telemetry&version=12.0.0-beta.5&prerelease
TimeWarp.State.Telemetry
OpenTelemetry instrumentation for the TimeWarp.State mediator pipeline. Each dispatched action becomes a span with type names, duration, and success/failure — the observation half of Redux DevTools, on any OTel backend (Aspire dashboard, Jaeger, Seq, Application Insights).
Time-travel, commit, and import/export stay out of this package. Those need a dev-only back-channel; OTLP is one-directional.
Install
dotnet add package TimeWarp.State.Telemetry
The package weaves TelemetryBehavior<TAction, TResponse> into ClientPipeline the same way StateTransactionBehavior is woven (generated mediator, closed types visible to the trimmer). Order 350 sits inside StateTransactionBehavior (300) and outside RenderSubscriptionsPostProcessor (400): handler failures are recorded as Error before the transaction restores state and swallows the exception. Span duration is handler + render, not clone or Redux DevTools JS.
Register
builder.Services.AddGeneratedMediator<ClientPipeline>();
builder.Services.AddTimeWarpState();
builder.Services.AddTimeWarpStateTelemetry();
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.AddSource(TimeWarpStateTelemetry.ActivitySourceName);
tracing.AddAspNetCoreInstrumentation();
tracing.AddOtlpExporter(); // reads OTEL_EXPORTER_OTLP_* (Aspire sets these)
});
AddTimeWarpStateTelemetry uses TryAdd* so a host can replace options or the snapshot cache.
What a span contains
Default (no payload):
| Item | Source |
|---|---|
| Name | Nested declaring-type chain, e.g. CounterState.IncrementCountActionSet.Action |
timewarp.state.action |
Nested name relative to the enclosing state, e.g. IncrementCountActionSet.Action |
timewarp.state.state_type |
Enclosing state type name |
| Duration | Activity start/stop (handler + render) |
| Status | Ok or Error (exception recorded) |
An action that triggers HTTP is the parent of that HTTP span when the handler runs under Activity.Current.
Opt-in snapshots
Snapshots are off unless all of these are true:
- An Activity listener is attached (
ActivitySource.HasListeners()). - The span is sampled (
IsAllDataRequested). TimeWarpStateTelemetryOptions.IncludeSnapshotsis true.- Caller-supplied
JsonSerializerOptions.TypeInfoResolverreturnsJsonTypeInfofor the state type.
builder.Services.AddTimeWarpStateTelemetry(options =>
{
options.IncludeSnapshots = true;
options.JsonSerializerOptions = timeWarpStateJsonOptions; // TypeInfoResolver required
options.MaxSnapshotChars = 16_384;
});
Or set TypeInfoResolver on TimeWarpStateOptions.JsonSerializerOptions (the same options Store and persistence use). This package never calls new JsonSerializerOptions() and never JsonSerializer.Serialize(object) on an open TState.
Events (not span attributes):
- First JSON for a state type in the scope:
state.snapshotwith tagsnapshot.json - Later unequal JSON:
state.diffwith the new JSON (string compare of the full JSON, no reflection property walk) - Equal JSON: no event
MaxSnapshotCharstruncates only the event payload and sets boolean tagsnapshot.truncated
Performance
The dispatch hot path with no listener is ActivitySource.HasListeners() (false) and next(). No GetState, no JSON, no snapshot cache.
With a listener, StartActivity returns null when the sampler drops the span; that path also skips snapshots.
Security
State JSON may contain user data. Defaults emit no payload. Enable snapshots only in local/dev, pair them with sampling, and redact via JsonConverter / source-generated context (omit secrets, tokens, PII). Truncation (MaxSnapshotChars) is a size cap, not redaction.
Do not enable IncludeSnapshots in production unless the OTel backend is access-controlled and payloads are redacted.
AOT / trimming
IsAotCompatible=trueon this package.- Default spans use
typeofnames only. - Snapshots require caller
JsonTypeInfo(typically aJsonSerializerContext). - No
Type.GetType, noAssemblyQualifiedName, noGetPropertieswalk. - Time-travel /
LoadStatesFromJsonis not in this package.
Blazor Server
Works out of the box: the circuit runs .NET, so ActivitySource spans export over OTLP to the Aspire dashboard (or any backend).
Blazor WebAssembly / browser telemetry
WASM process telemetry is the JS OpenTelemetry SDK, not this ActivitySource. That is maintained SDK code, not the custom redux-dev-tools.ts / timewarp-state.ts bridge.
Aspire dashboard browser telemetry (OTLP/HTTP + CORS):
- When the AppHost launches both the app and the dashboard, CORS for the OTLP HTTP endpoint is configured automatically. See Enable browser telemetry.
- A standalone dashboard needs
DASHBOARD__OTLP__CORS__ALLOWEDORIGINSset to the WASM origin (for examplehttps://localhost:7001).
This JS is not the C# trimmer’s problem.
Redux DevTools
Use this package for the observation half (action log, timing, snapshots). Keep UseReduxDevTools only if you still need time-travel / commit / import-export in the browser extension. A dedicated control channel is a follow-on; that path is AOT-hostile.
Sample
samples/04-telemetry/ is a Blazor Server counter that exports action spans. Run it against the Aspire dashboard (see that sample’s overview).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.CodeAnalysis.CSharp (>= 4.14.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- TimeWarp.Mediator.Contracts (>= 14.0.0-beta.1)
- TimeWarp.State (>= 12.0.0-beta.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 12.0.0-beta.5 | 30 | 9/24/2026 |