36 double? Minimum,
double? Maximum,
double? Last)
41 public double? WindowDelta {
get; init; }
43 public double? LastObservedSeconds {
get; init; }
45 public double? Mean => Count == 0 ? null : Sum / Count;
50 public static TelemetrySummary Combine(IEnumerable<TelemetrySummary> summaries)
52 ArgumentNullException.ThrowIfNull(summaries);
55 double? min =
null, max =
null, last =
null;
56 double? observed =
null, delta =
null;
59 foreach (var value
in summaries)
61 if (kind is not
null && kind != value.Kind)
throw new ArgumentException(
"Cannot combine different metric kinds.", nameof(summaries));
63 if (value.Availability > availability) availability = value.Availability;
64 if (value.Count == 0)
continue;
67 min = min is
null ? value.Minimum : Math.Min(min.Value, value.Minimum!.Value);
68 max = max is
null ? value.Maximum : Math.Max(max.Value, value.Maximum!.Value);
70 observed = value.LastObservedSeconds;
71 if (value.WindowDelta is { } change) delta = (delta ?? 0) + change;
73 return new(availability, count, sum, min, max, last)
76 LastObservedSeconds = observed,
93 internal const long MaxRetainedMetricSummaries = 1_048_576;
96 internal const long MaxPublishedMetricSummariesPerSecond = 262_144;
99 public TimeSpan Interval {
get; init; } = TimeSpan.FromMilliseconds(250);
101 public int HistoryCapacity {
get; init; } = 120;
103 public int SourceCapacity {
get; init; } = 16;
105 public int MetricCapacity {
get; init; } = 128;
108 internal void Validate()
110 if (Interval < TimeSpan.FromMilliseconds(10) || Interval > TimeSpan.FromMinutes(1))
111 throw new ArgumentOutOfRangeException(nameof(Interval));
112 if (HistoryCapacity is < 1 or > 1024)
throw new ArgumentOutOfRangeException(nameof(HistoryCapacity));
113 if (SourceCapacity is < 1 or > 64)
throw new ArgumentOutOfRangeException(nameof(SourceCapacity));
114 if (MetricCapacity is < 8 or > 512)
throw new ArgumentOutOfRangeException(nameof(MetricCapacity));
116 long retainedMetricSummaries =
117 (long)HistoryCapacity * SourceCapacity * MetricCapacity;
118 if (retainedMetricSummaries > MaxRetainedMetricSummaries)
120 throw new ArgumentException(
121 $
"HistoryCapacity * SourceCapacity * MetricCapacity must not exceed {MaxRetainedMetricSummaries:N0} retained metric summaries.");
124 double publishedMetricSummariesPerSecond =
125 (double)SourceCapacity * MetricCapacity / Interval.TotalSeconds;
126 if (publishedMetricSummariesPerSecond > MaxPublishedMetricSummariesPerSecond)
128 throw new ArgumentException(
129 $
"SourceCapacity * MetricCapacity / Interval.TotalSeconds must not exceed {MaxPublishedMetricSummariesPerSecond:N0} configured metric summaries per second.");
140public sealed record
TelemetrySnapshot(
long Generation,
double StartedSeconds,
double EndedSeconds,
141 IReadOnlyList<TelemetrySourceSnapshot> Sources,
bool Truncated)
144 public double ElapsedSeconds => EndedSeconds - StartedSeconds;
153 IReadOnlyDictionary<string, TelemetrySummary> Metrics);
record TelemetrySummary(TelemetryAvailability Availability, long Count, double Sum, double? Minimum, double? Maximum, double? Last)
Detached statistics for observations in one window; durations use milliseconds.
record TelemetrySourceSnapshot(long Id, string Name, string Backend, IReadOnlyDictionary< string, TelemetrySummary > Metrics)
Detached source identity, backend label, and measurements. No runtime objects are retained.
TelemetryAvailability
Whether an observation is meaningful for its source and window.
@ NotYetSampled
The measurement is supported but has no samples in this window.
@ NotApplicable
The measurement does not apply to this rendering path.
@ Available
At least one observation is present.
@ Unsupported
The source does not implement this measurement.
TelemetryMetricKind
How observations should be interpreted when combining windows.
@ Gauge
Observed state; use Last for current state, not the sum across windows.
@ Sample
Independent work samples; count divided by elapsed seconds gives cadence.
@ LifetimeCounter
Renderer-owned cumulative value; WindowDelta is relative to the previous observation.
record TelemetryOptions
Validated shared settings; configure only when collection is inactive.
record TelemetrySnapshot(long Generation, double StartedSeconds, double EndedSeconds, IReadOnlyList< TelemetrySourceSnapshot > Sources, bool Truncated)
Detached completed window. Sources can be observed asynchronously within its interval.