radar_trace 0.3.0 copy "radar_trace: ^0.3.0" to clipboard
radar_trace: ^0.3.0 copied to clipboard

Pure-Dart tracer framework with monotonic spans, log-linear latency histograms, Zone-based async nesting, and a lossless outlier ring.

0.3.0 #

Integration-facing additions from the first third-party integration. Additive except for one documented behaviour change: record() no longer samples (see below). Existing call sites, subclasses and JSON readers keep working.

A minor bump rather than a patch, so a ^0.2.0 dependency does not pick the behaviour change up on pub upgrade — taking it is a deliberate move to ^0.3.0.

  • Span exporters. TraceRecorder(exporters: [...]) mirrors every accepted span into host-supplied callbacks, so teeing spans into an app's own logging pipeline no longer needs a TraceRecorder subclass. Exporters see spans that pass the enabled gate and exportFilter, including ones whose key is later dropped by maxKeys. A throwing exporter is swallowed and counted in exporterErrorCount — recording never breaks.
  • exportFilter. A bool Function(Span) in front of the exporters, consulted on the export path only. This is the volume control for a chatty key: it quietens a mirror-style exporter without moving a percentile, which lowering sampleRate cannot do. A throwing filter skips the export and counts into exporterErrorCount.
  • Outcome tagging at stop time. SpanHandle.stop({attributes}) and SpanHandle.fail(error, [attributes]) merge attributes over the start-time ones, so an outcome-dependent dimension (cache hit vs miss, error class) can be recorded. Attributes are not part of the TraceKey, so aggregation is unchanged.
  • Error type on failed spans. SpanHandle.fail, Tracer.trace and Tracer.traceAsync record the error's runtime type as the error.type attribute (kErrorTypeAttribute) — the type name only, never the message.
  • Cross-isolate merge. TraceSnapshot.fromJson and TraceSnapshot.merge combine snapshots from separate isolates into one view. Histograms add bucket-wise, so merged percentiles stay as accurate as single-isolate ones. Each snapshot now carries clockOriginWallMicros, and merge rebases later-started isolates onto the earliest origin — otherwise the merged window and callsPerSecond would mix incomparable per-isolate clocks. traceClockOriginWallMicros exposes the current isolate's origin.
  • TraceSnapshot.toJson / SpanKeyStatsSnapshot.toJson now include the latency distribution (sparse — non-empty buckets only), without which a restored snapshot could not report percentiles. Outlier spans are opt-in via includeOutliers, keeping the default payload aggregate-sized. Span.toJson / Span.fromJson are public for that path; attribute values that are not JSON primitives are serialised via toString().
  • Per-trace capture. TraceRecorder(slowTraceCapacity: n) retains the slowest n complete traces as TraceTrees — root span plus its full subtree — reachable via TraceSnapshot.slowTraces, with TraceTree.describe() for an indented waterfall. Aggregates answer "how long does this usually take"; this answers "why did this one take 8 seconds". Off by default (capacity 0 is the switch). Bounded by maxSpansPerTrace (marks the tree truncated) and maxInFlightTraces (evicts the oldest buffer into TraceSnapshot.traceDropCount). A trace whose root never arrives is dropped and counted, never reported as a partial waterfall; a span that arrives once its trace has been evicted or already reported marks that tree truncated rather than rebuilding a second one that would look whole. Trees serialise via includeSlowTraces and merge slowest-first across isolates, rebased like everything else.
  • Sampling moved to the start of a span. TraceRecorder.shouldSample() is now the draw, and Tracer.trace / traceAsync / start call it before building anything — a sampled-out span costs one call and one branch instead of a Span, an attribute map and a Zone.fork. Tracer.start returns the new SpanHandle.inert() when sampled out.
    • Behaviour change: record() no longer samples. A caller handing hand-built spans to record with sampleRate < 1.0 now gets all of them; call shouldSample() first if you want the old behaviour. Sampling belongs to the start of a span — by the time one is finished the work has been paid for. Tracer still calls the public record, so TraceRecorder subclasses that override it keep seeing every span.
    • A sampled-out span forks no zone, so it is invisible to its descendants: a sampled-in child under it attaches to the nearest sampled-in ancestor, or becomes its own root when there is none, rather than pointing at a span nobody recorded. A trace holds only sampled-in spans, so below sampleRate: 1.0 a retained waterfall can be missing a middle level without being marked truncated.
  • Docs: traceAsync notes that T should be passed explicitly when wrapping an existing assignment — inference reads the assignment context, which is the promoted type when the target is type-promoted, so a nullable body can stop compiling once it is wrapped.

0.2.0 #

  • New series module: MetricSample, SeriesGap, and MetricSeries (JSON with schemaVersion: 1), plus assessSeries producing a SeriesAssessment with a SeriesVerdict (monotonicGrowth / plateau / noisy / insufficientData). Implements the field-proven growth methodology: settle-window trim, gap-aware region selection (gaps are never bridged), init-free batch2-minus-batch1 delta, Theil-Sen robust slope, degrees-of-freedom-preserving noise (first-difference sigma combined with residual sigma), Mann-Kendall certification of growth verdicts (bounds the false-growth rate under pure noise at 0.5% one-sided; measured 0.07% over 12k seeded trials), and end-shift checks so late crashes cannot read as growth and late rises cannot read as a bounded plateau. Details claim only measured facts and quantify the detection floor. Honest degradation throughout: a signal that cannot be truthfully computed reads insufficientData / null — never a plausible number.

0.1.2 #

  • Optional dedupKey on Tracer.trace / traceAsync / start — a caller-supplied signature (e.g. arguments) marking repeated invocations of the same operation. SpanKeyStatsSnapshot.duplicateCount reports how many spans repeated a previously-seen signature for a key (bounded to ~1024 signatures), distinct from any statistical "hot" heuristic. Span.dedupKey carries the joined signature.

0.1.1 #

  • Docs only (no code change): document the per-key SpanKeyStatsSnapshot metrics — callsPerSecond, avgInterCallIntervalMicros, meanMicros, maxMicros, totalMicros, firstStartMicros, lastStartMicros — in the README.

0.1.0 #

  • Initial release: Span model, LatencyHistogram, OutlierRing, TraceRecorder, TraceSnapshot, Tracer façade with Zone-based nesting.
  • Added per-key call metrics to SpanKeyStatsSnapshot: firstStartMicros, lastStartMicros, avgInterCallIntervalMicros (null when count < 2), callsPerSecond (null when count < 2 or window is zero), meanMicros, maxMicros, totalMicros — all exact (no bucket approximation).
0
likes
160
points
121
downloads

Documentation

API reference

Publisher

verified publishertp9imka.dev

Weekly Downloads

Pure-Dart tracer framework with monotonic spans, log-linear latency histograms, Zone-based async nesting, and a lossless outlier ring.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#tracing #profiling #observability #performance #dart

License

MIT (license)

Dependencies

meta

More

Packages that depend on radar_trace