Skip to main content

harness/payload/
dogstatsd.rs

1//! `DogStatsD` payload generation.
2//!
3//! Dogstatsd is three message types: metric, event, service check.
4//!
5//! # Metrics
6//!
7//! ```text
8//! <NAME>:<VALUE>|<TYPE>|@<SAMPLE_RATE>|#<TAG>,<TAG>...|c:<CONTAINER>|T<TS>|e:<EXT>|card:<CARD>
9//!
10//! Required: <NAME>:<VALUE>|<TYPE>.
11//!
12//! <NAME>        := [^:|\n]+
13//! <VALUE>       := <NUMBER>(:<NUMBER>)*        ':'-packed multi-value, non-set
14//!                | [^|\n]+                     raw string, set type
15//! <NUMBER>      := [+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)? | [+-]?(inf|infinity|nan)
16//! <TYPE>        := c|g|ms|h|s|d                count gauge timer histogram set distribution
17//! <SAMPLE_RATE> := @<NUMBER>
18//! <TAG>         := [^,|\n]+                    conventionally <KEY>:<VALUE>, the ':' is not required
19//! <CONTAINER>   := c:[^|\n]+                   e.g. ci-<id>, in-<inode>
20//! <TS>          := T\d+                        unix seconds
21//! <EXT>         := e:[^|\n]+                   e.g. it-,cn-,pu-
22//! <CARD>        := card:[^|\n]+                recognized: none|low|orchestrator|high
23//! ```
24//!
25//! # Events
26//!
27//! ```text
28//! _e{<TITLE_LEN>,<TEXT_LEN>}:<TITLE>|<TEXT>|d:<TS>|h:<HOST>|k:<AGGKEY>|p:<PRIO>|s:<SRC>|t:<ALERT>|#<TAGS>
29//!
30//! Required: _e{<TITLE_LEN>,<TEXT_LEN>}:<TITLE>|<TEXT>. c: / e: / card: are valid here too.
31//!
32//! <TITLE_LEN>,<TEXT_LEN> := \d+               byte length of TITLE / TEXT
33//! <TITLE>,<TEXT>         := [^\n]{LEN}         length-delimited, so '|' and ':' are allowed
34//! <TS>          := d:\d+                       unix seconds
35//! <HOST>        := h:[^|\n]+
36//! <AGGKEY>      := k:[^|\n]+
37//! <PRIO>        := p:[^|\n]+                   recognized: normal|low (else default)
38//! <SRC>         := s:[^|\n]+
39//! <ALERT>       := t:[^|\n]+                   recognized: error|warning|info|success (else default)
40//! <TAGS>        := #<TAG>(,<TAG>)*
41//! ```
42//!
43//! # Service checks
44//!
45//! ```text
46//! _sc|<NAME>|<STATUS>|d:<TS>|h:<HOST>|#<TAG>,<TAG>...|m:<MESSAGE>
47//!
48//! Required: _sc|<NAME>|<STATUS>. c: / e: / card: are valid here too.
49//!
50//! <NAME>        := [^|\n]+
51//! <STATUS>      := [0-3]                       OK warning critical unknown
52//! <TS>          := d:\d+                       unix seconds
53//! <HOST>        := h:[^|\n]+
54//! <TAGS>        := #<TAG>(,<TAG>)*
55//! <MESSAGE>     := m:[^|\n]+
56//! ```
57//!
58//! # Name combinatorics
59//!
60//! A clean name is `c` segments from `COMPLIANT_WORD` (10 words) joined by
61//! `NAME_SEPARATORS` (4). Distinct names at count `c`: `10^c · 4^(c-1)`. `c` is
62//! sampled by vibe: clean draws from `ELEMENT_COUNTS_CLEAN` (a small body, no
63//! boundary cases); feral draws from `ELEMENT_COUNTS_FERAL`, which adds the `0`
64//! and large boundary counts as a tail.
65//!
66//! | `c`   | P(c) clean | P(c) feral | distinct names |
67//! |-------|------------|------------|----------------|
68//! | 0     | —          | 1/12       | 1 (empty)      |
69//! | 1-3   | 6/9        | 6/12       | 10 .. ~16e3    |
70//! | 4-6   | 3/9        | 3/12       | ~640e3 .. ~1e9 |
71//! | 127   | —          | 1/12       | ~10^203        |
72//! | 255   | —          | 1/12       | ~10^408        |
73
74use rand::{Rng, RngExt};
75
76mod common;
77mod events;
78mod metrics;
79mod service_checks;
80
81pub use common::{sample_vibe, Vibe};
82
83/// The three `DogStatsD` message types.
84#[derive(Clone, Copy)]
85enum Message {
86    Metric,
87    Event,
88    ServiceCheck,
89}
90
91/// Sample a message type. The mix is heavily metric-weighted — 98% metric, 1%
92/// event, 1% service check. Metrics drive the aggregate context map and the
93/// sketch bin paths, the invariants worth exercising, so the bulk of load goes
94/// there while events and service checks still fire often enough to keep their
95/// own anchors non-vacuous.
96fn choose_message<R: Rng + ?Sized>(rng: &mut R) -> Message {
97    match rng.random_range(0..100u32) {
98        0 => Message::Event,
99        1 => Message::ServiceCheck,
100        _ => Message::Metric,
101    }
102}
103
104/// Write one `DogStatsD` message of a sampled type to `buf` at the given vibe.
105/// Returns the packed value count when a multi-value metric was emitted, else
106/// `None`.
107pub fn send<R: Rng + ?Sized>(rng: &mut R, buf: &mut Vec<u8>, vibe: Vibe) -> Option<usize> {
108    buf.clear();
109    match choose_message(rng) {
110        Message::Event => {
111            events::write(rng, buf, vibe);
112            None
113        }
114        Message::ServiceCheck => {
115            service_checks::write(rng, buf, vibe);
116            None
117        }
118        Message::Metric => metrics::write(rng, buf, vibe),
119    }
120}