saluki_core/data_model/event/trace_stats/
mod.rs

1//! Trace stats.
2
3use stringtheory::MetaString;
4
5/// Trace statistics output from the APM Stats transform.
6///
7/// Contains pre-aggregated trace statistics grouped by client/tracer. The encoder wraps this
8/// in a `StatsPayload` protobuf and adds agent-level metadata (agentHostname, agentEnv,
9/// agentVersion, clientComputed, splitPayload) from ADP configuration.
10#[derive(Clone, Debug, PartialEq, Default)]
11pub struct TraceStats {
12    /// Multiple client payloads, one per PayloadAggregationKey (hostname/env/version/container).
13    stats: Vec<ClientStatsPayload>,
14}
15
16impl TraceStats {
17    /// Creates a new `TraceStats` with the given client stats payloads.
18    pub fn new(stats: Vec<ClientStatsPayload>) -> Self {
19        Self { stats }
20    }
21
22    /// Returns a reference to the client stats payloads.
23    pub fn stats(&self) -> &[ClientStatsPayload] {
24        &self.stats
25    }
26
27    /// Returns a mutable reference to the client stats payloads.
28    pub fn stats_mut(&mut self) -> &mut Vec<ClientStatsPayload> {
29        &mut self.stats
30    }
31}
32
33/// Tracer-level stats payload.
34///
35/// Groups stats by tracer/container identity (hostname, env, version, container_id).
36#[derive(Clone, Debug, PartialEq, Default)]
37pub struct ClientStatsPayload {
38    hostname: MetaString,
39    env: MetaString,
40    version: MetaString,
41    stats: Vec<ClientStatsBucket>,
42    lang: MetaString,
43    tracer_version: MetaString,
44    runtime_id: MetaString,
45    sequence: u64,
46    agent_aggregation: MetaString,
47    service: MetaString,
48    container_id: MetaString,
49    tags: Vec<MetaString>,
50    git_commit_sha: MetaString,
51    image_tag: MetaString,
52    process_tags_hash: u64,
53    process_tags: MetaString,
54}
55
56impl ClientStatsPayload {
57    /// Creates a new `ClientStatsPayload` with the required identity fields.
58    pub fn new(hostname: impl Into<MetaString>, env: impl Into<MetaString>, version: impl Into<MetaString>) -> Self {
59        Self {
60            hostname: hostname.into(),
61            env: env.into(),
62            version: version.into(),
63            ..Self::default()
64        }
65    }
66
67    /// Sets the stats buckets.
68    pub fn with_stats(mut self, stats: Vec<ClientStatsBucket>) -> Self {
69        self.stats = stats;
70        self
71    }
72
73    /// Sets the tracer language.
74    pub fn with_lang(mut self, lang: impl Into<MetaString>) -> Self {
75        self.lang = lang.into();
76        self
77    }
78
79    /// Sets the tracer version.
80    pub fn with_tracer_version(mut self, tracer_version: impl Into<MetaString>) -> Self {
81        self.tracer_version = tracer_version.into();
82        self
83    }
84
85    /// Sets the runtime identifier.
86    pub fn with_runtime_id(mut self, runtime_id: impl Into<MetaString>) -> Self {
87        self.runtime_id = runtime_id.into();
88        self
89    }
90
91    /// Sets the message sequence number.
92    pub fn with_sequence(mut self, sequence: u64) -> Self {
93        self.sequence = sequence;
94        self
95    }
96
97    /// Sets the agent aggregation key.
98    pub fn with_agent_aggregation(mut self, agent_aggregation: impl Into<MetaString>) -> Self {
99        self.agent_aggregation = agent_aggregation.into();
100        self
101    }
102
103    /// Sets the main service name.
104    pub fn with_service(mut self, service: impl Into<MetaString>) -> Self {
105        self.service = service.into();
106        self
107    }
108
109    /// Sets the container identifier.
110    pub fn with_container_id(mut self, container_id: impl Into<MetaString>) -> Self {
111        self.container_id = container_id.into();
112        self
113    }
114
115    /// Sets the orchestrator tags.
116    pub fn with_tags(mut self, tags: Vec<MetaString>) -> Self {
117        self.tags = tags;
118        self
119    }
120
121    /// Sets the git commit SHA.
122    pub fn with_git_commit_sha(mut self, git_commit_sha: impl Into<MetaString>) -> Self {
123        self.git_commit_sha = git_commit_sha.into();
124        self
125    }
126
127    /// Sets the container image tag.
128    pub fn with_image_tag(mut self, image_tag: impl Into<MetaString>) -> Self {
129        self.image_tag = image_tag.into();
130        self
131    }
132
133    /// Sets the process tags hash.
134    pub fn with_process_tags_hash(mut self, process_tags_hash: u64) -> Self {
135        self.process_tags_hash = process_tags_hash;
136        self
137    }
138
139    /// Sets the process tags.
140    pub fn with_process_tags(mut self, process_tags: impl Into<MetaString>) -> Self {
141        self.process_tags = process_tags.into();
142        self
143    }
144
145    /// Returns the hostname.
146    pub fn hostname(&self) -> &str {
147        &self.hostname
148    }
149
150    /// Returns the environment.
151    pub fn env(&self) -> &str {
152        &self.env
153    }
154
155    /// Returns the version.
156    pub fn version(&self) -> &str {
157        &self.version
158    }
159
160    /// Returns the stats buckets.
161    pub fn stats(&self) -> &[ClientStatsBucket] {
162        &self.stats
163    }
164
165    /// Returns the tracer language.
166    pub fn lang(&self) -> &str {
167        &self.lang
168    }
169
170    /// Returns the tracer version.
171    pub fn tracer_version(&self) -> &str {
172        &self.tracer_version
173    }
174
175    /// Returns the runtime identifier.
176    pub fn runtime_id(&self) -> &str {
177        &self.runtime_id
178    }
179
180    /// Returns the message sequence number.
181    pub fn sequence(&self) -> u64 {
182        self.sequence
183    }
184
185    /// Returns the agent aggregation key.
186    pub fn agent_aggregation(&self) -> &str {
187        &self.agent_aggregation
188    }
189
190    /// Returns the main service name.
191    pub fn service(&self) -> &str {
192        &self.service
193    }
194
195    /// Returns the container identifier.
196    pub fn container_id(&self) -> &str {
197        &self.container_id
198    }
199
200    /// Returns the orchestrator tags.
201    pub fn tags(&self) -> &[MetaString] {
202        &self.tags
203    }
204
205    /// Returns the git commit SHA.
206    pub fn git_commit_sha(&self) -> &str {
207        &self.git_commit_sha
208    }
209
210    /// Returns the container image tag.
211    pub fn image_tag(&self) -> &str {
212        &self.image_tag
213    }
214
215    /// Returns the process tags hash.
216    pub fn process_tags_hash(&self) -> u64 {
217        self.process_tags_hash
218    }
219
220    /// Returns the process tags.
221    pub fn process_tags(&self) -> &str {
222        &self.process_tags
223    }
224}
225
226/// A time bucket containing aggregated stats.
227///
228/// Stats are grouped into fixed-duration buckets (typically 10 seconds).
229#[derive(Clone, Debug, PartialEq, Default)]
230pub struct ClientStatsBucket {
231    /// Bucket start timestamp in nanoseconds since Unix epoch.
232    start: u64,
233    /// Bucket duration in nanoseconds.
234    duration: u64,
235    /// Grouped stats within this bucket.
236    stats: Vec<ClientGroupedStats>,
237    /// Time shift applied by the agent.
238    agent_time_shift: i64,
239}
240
241impl ClientStatsBucket {
242    /// Creates a new `ClientStatsBucket` with the given time range and stats.
243    pub fn new(start: u64, duration: u64, stats: Vec<ClientGroupedStats>) -> Self {
244        Self {
245            start,
246            duration,
247            stats,
248            agent_time_shift: 0,
249        }
250    }
251
252    /// Sets the agent time shift.
253    pub fn with_agent_time_shift(mut self, agent_time_shift: i64) -> Self {
254        self.agent_time_shift = agent_time_shift;
255        self
256    }
257
258    /// Returns the bucket start timestamp in nanoseconds.
259    pub fn start(&self) -> u64 {
260        self.start
261    }
262
263    /// Returns the bucket duration in nanoseconds.
264    pub fn duration(&self) -> u64 {
265        self.duration
266    }
267
268    /// Returns the grouped stats within this bucket.
269    pub fn stats(&self) -> &[ClientGroupedStats] {
270        &self.stats
271    }
272
273    /// Returns a mutable reference to the grouped stats within this bucket.
274    pub fn stats_mut(&mut self) -> &mut Vec<ClientGroupedStats> {
275        &mut self.stats
276    }
277
278    /// Returns the agent time shift.
279    pub fn agent_time_shift(&self) -> i64 {
280        self.agent_time_shift
281    }
282}
283
284/// Aggregated stats for spans grouped by aggregation key.
285///
286/// Contains both the aggregation key fields (service, name, resource, etc.) and
287/// the aggregated values (hits, errors, duration, latency distributions).
288#[derive(Clone, Debug, PartialEq, Default)]
289pub struct ClientGroupedStats {
290    // Aggregation key fields
291    service: MetaString,
292    name: MetaString,
293    resource: MetaString,
294    http_status_code: u32,
295    span_type: MetaString,
296    db_type: MetaString,
297    span_kind: MetaString,
298    peer_tags: Vec<MetaString>,
299    is_trace_root: Option<bool>,
300    grpc_status_code: MetaString,
301    http_method: MetaString,
302    http_endpoint: MetaString,
303
304    // Aggregated values
305    hits: u64,
306    errors: u64,
307    duration: u64,
308    ok_summary: Vec<u8>,
309    error_summary: Vec<u8>,
310    synthetics: bool,
311    top_level_hits: u64,
312}
313
314impl ClientGroupedStats {
315    /// Creates a new `ClientGroupedStats` with the required aggregation key fields.
316    pub fn new(service: impl Into<MetaString>, name: impl Into<MetaString>, resource: impl Into<MetaString>) -> Self {
317        Self {
318            service: service.into(),
319            name: name.into(),
320            resource: resource.into(),
321            ..Self::default()
322        }
323    }
324
325    // Builder methods for aggregation key fields
326
327    /// Sets the HTTP status code.
328    pub fn with_http_status_code(mut self, http_status_code: u32) -> Self {
329        self.http_status_code = http_status_code;
330        self
331    }
332
333    /// Sets the span type.
334    pub fn with_span_type(mut self, span_type: impl Into<MetaString>) -> Self {
335        self.span_type = span_type.into();
336        self
337    }
338
339    /// Sets the database type.
340    pub fn with_db_type(mut self, db_type: impl Into<MetaString>) -> Self {
341        self.db_type = db_type.into();
342        self
343    }
344
345    /// Sets the span kind.
346    pub fn with_span_kind(mut self, span_kind: impl Into<MetaString>) -> Self {
347        self.span_kind = span_kind.into();
348        self
349    }
350
351    /// Sets the peer tags.
352    pub fn with_peer_tags(mut self, peer_tags: Vec<MetaString>) -> Self {
353        self.peer_tags = peer_tags;
354        self
355    }
356
357    /// Sets whether this is a trace root.
358    pub fn with_is_trace_root(mut self, is_trace_root: Option<bool>) -> Self {
359        self.is_trace_root = is_trace_root;
360        self
361    }
362
363    /// Sets the gRPC status code.
364    pub fn with_grpc_status_code(mut self, grpc_status_code: impl Into<MetaString>) -> Self {
365        self.grpc_status_code = grpc_status_code.into();
366        self
367    }
368
369    /// Sets the HTTP method.
370    pub fn with_http_method(mut self, http_method: impl Into<MetaString>) -> Self {
371        self.http_method = http_method.into();
372        self
373    }
374
375    /// Sets the HTTP endpoint.
376    pub fn with_http_endpoint(mut self, http_endpoint: impl Into<MetaString>) -> Self {
377        self.http_endpoint = http_endpoint.into();
378        self
379    }
380
381    // Builder methods for aggregated values
382
383    /// Sets the hit count.
384    pub fn with_hits(mut self, hits: u64) -> Self {
385        self.hits = hits;
386        self
387    }
388
389    /// Sets the error count.
390    pub fn with_errors(mut self, errors: u64) -> Self {
391        self.errors = errors;
392        self
393    }
394
395    /// Sets the total duration in nanoseconds.
396    pub fn with_duration(mut self, duration: u64) -> Self {
397        self.duration = duration;
398        self
399    }
400
401    /// Sets the DDSketch summary for successful spans.
402    pub fn with_ok_summary(mut self, ok_summary: Vec<u8>) -> Self {
403        self.ok_summary = ok_summary;
404        self
405    }
406
407    /// Sets the DDSketch summary for error spans.
408    pub fn with_error_summary(mut self, error_summary: Vec<u8>) -> Self {
409        self.error_summary = error_summary;
410        self
411    }
412
413    /// Sets the synthetics traffic flag.
414    pub fn with_synthetics(mut self, synthetics: bool) -> Self {
415        self.synthetics = synthetics;
416        self
417    }
418
419    /// Sets the top-level hit count.
420    pub fn with_top_level_hits(mut self, top_level_hits: u64) -> Self {
421        self.top_level_hits = top_level_hits;
422        self
423    }
424
425    // Getters for aggregation key fields
426
427    /// Returns the service name.
428    pub fn service(&self) -> &str {
429        &self.service
430    }
431
432    /// Returns the operation name.
433    pub fn name(&self) -> &str {
434        &self.name
435    }
436
437    /// Returns the resource name.
438    pub fn resource(&self) -> &str {
439        &self.resource
440    }
441
442    /// Returns the HTTP status code.
443    pub fn http_status_code(&self) -> u32 {
444        self.http_status_code
445    }
446
447    /// Returns the span type.
448    pub fn span_type(&self) -> &str {
449        &self.span_type
450    }
451
452    /// Returns the database type.
453    pub fn db_type(&self) -> &str {
454        &self.db_type
455    }
456
457    /// Returns the span kind.
458    pub fn span_kind(&self) -> &str {
459        &self.span_kind
460    }
461
462    /// Returns the peer tags.
463    pub fn peer_tags(&self) -> &[MetaString] {
464        &self.peer_tags
465    }
466
467    /// Returns whether this is a trace root.
468    pub fn is_trace_root(&self) -> Option<bool> {
469        self.is_trace_root
470    }
471
472    /// Returns the gRPC status code.
473    pub fn grpc_status_code(&self) -> &str {
474        &self.grpc_status_code
475    }
476
477    /// Returns the HTTP method.
478    pub fn http_method(&self) -> &str {
479        &self.http_method
480    }
481
482    /// Returns the HTTP endpoint.
483    pub fn http_endpoint(&self) -> &str {
484        &self.http_endpoint
485    }
486
487    // Getters for aggregated values
488
489    /// Returns the hit count.
490    pub fn hits(&self) -> u64 {
491        self.hits
492    }
493
494    /// Returns the error count.
495    pub fn errors(&self) -> u64 {
496        self.errors
497    }
498
499    /// Returns the total duration in nanoseconds.
500    pub fn duration(&self) -> u64 {
501        self.duration
502    }
503
504    /// Returns the DDSketch summary for successful spans.
505    pub fn ok_summary(&self) -> &[u8] {
506        &self.ok_summary
507    }
508
509    /// Returns the DDSketch summary for error spans.
510    pub fn error_summary(&self) -> &[u8] {
511        &self.error_summary
512    }
513
514    /// Returns the synthetics traffic flag.
515    pub fn synthetics(&self) -> bool {
516        self.synthetics
517    }
518
519    /// Returns the top-level hit count.
520    pub fn top_level_hits(&self) -> u64 {
521        self.top_level_hits
522    }
523}