Skip to main content

sozu_lib/metrics/
names.rs

1//! Canonical metric-name constants.
2//!
3//! Every metric string emitted by Sōzu and consumed by the StatsD/Prometheus/
4//! TUI surface should reference a constant declared here rather than being
5//! repeated as a literal. The constants intentionally preserve the dotted
6//! string values byte-for-byte so dashboards and scrapers stay valid.
7//!
8//! Layout: one submodule per metric family (`http`, `h2`, `tcp`, `tls`, …),
9//! constants inside are `UPPER_SNAKE_CASE` derived from the dotted suffix.
10//! E.g. `h2.frames.tx.data` lives at [`h2::FRAMES_TX_DATA`].
11//!
12//! When adding a new metric:
13//! 1. Add the constant in the matching submodule (create one if needed).
14//! 2. Reference the constant from the emission site
15//!    (`incr!(names::h2::FRAMES_TX_DATA)`) instead of repeating the literal.
16//! 3. If the TUI or any scraper reads this metric, reference the same
17//!    constant on the read side too.
18
19/// Accept-queue counters and gauges, fed by the worker accept loop in
20/// `lib/src/server.rs`.
21pub mod accept_queue {
22    pub const BACKPRESSURE: &str = "accept_queue.backpressure";
23    pub const CONNECTIONS: &str = "accept_queue.connections";
24    pub const SATURATED_SECONDS: &str = "accept_queue.saturated_seconds";
25    pub const TIMEOUT: &str = "accept_queue.timeout";
26    pub const WAIT_TIME: &str = "accept_queue.wait_time";
27}
28
29/// Access-log infrastructure counters.
30pub mod access_logs {
31    pub const COUNT: &str = "access_logs.count";
32    pub const UNSENT: &str = "unsent-access-logs";
33}
34
35/// Per-backend bandwidth + connection counters emitted by both H1 and the
36/// H2 mux. Front-bytes and back-bytes are accounted separately so dashboards
37/// can compare upstream vs downstream traffic.
38pub mod backend {
39    pub const BYTES_IN: &str = "bytes_in";
40    pub const BYTES_OUT: &str = "bytes_out";
41    pub const BACK_BYTES_IN: &str = "back_bytes_in";
42    pub const BACK_BYTES_OUT: &str = "back_bytes_out";
43    pub const AVAILABLE: &str = "backend.available";
44    pub const CONNECTIONS: &str = "backend.connections";
45    pub const FLOW_CONTROL_PAUSED: &str = "backend.flow_control.paused";
46    pub const POOL_HIT: &str = "backend.pool.hit";
47    pub const POOL_MISS: &str = "backend.pool.miss";
48    pub const POOL_SIZE: &str = "backend.pool.size";
49    pub const CONNECTIONS_PER_BACKEND: &str = "connections_per_backend";
50    pub const CONNECTION_TIME: &str = "backend_connection_time";
51    pub const RESPONSE_TIME: &str = "backend_response_time";
52    pub const REQUESTS: &str = "requests";
53    pub const FAIL_OPEN: &str = "backends.fail_open";
54}
55
56/// Buffer-pool gauges and counters.
57pub mod buffer {
58    pub const CAPACITY: &str = "buffer.capacity";
59    pub const IN_USE: &str = "buffer.in_use";
60    pub const USAGE_PERCENT: &str = "buffer.usage_percent";
61}
62
63/// Client-side connection gauges, populated by the worker accept loop.
64pub mod client {
65    pub const CONNECTIONS: &str = "client.connections";
66    pub const CONNECTIONS_MAX: &str = "client.connections_max";
67}
68
69/// Per-cluster aggregate gauges.
70pub mod cluster {
71    pub const AVAILABLE_BACKENDS: &str = "cluster.available_backends";
72    pub const AVAILABLE_RECOVERED: &str = "cluster.available_recovered";
73    pub const NO_AVAILABLE_BACKENDS: &str = "cluster.no_available_backends";
74    pub const TOTAL_BACKENDS: &str = "cluster.total_backends";
75}
76
77/// Configuration-state inventory gauges, refreshed when the master
78/// fans out a state change.
79pub mod configuration {
80    pub const BACKENDS: &str = "configuration.backends";
81    pub const CLUSTERS: &str = "configuration.clusters";
82    pub const FRONTENDS: &str = "configuration.frontends";
83}
84
85/// Event-loop timing counters.
86pub mod event_loop {
87    pub const EPOLL_TIME: &str = "epoll_time";
88    pub const EVENT_LOOP_TIME: &str = "event_loop_time";
89    pub const FRONTEND_MATCHING_TIME: &str = "frontend_matching_time";
90    pub const REGEX_MATCHING_TIME: &str = "regex_matching_time";
91    pub const REQUEST_TIME: &str = "request_time";
92    pub const SERVICE_TIME: &str = "service_time";
93}
94
95/// Health-check transition counters.
96pub mod health_check {
97    pub const UP: &str = "health_check.up";
98    pub const DOWN: &str = "health_check.down";
99    pub const SUCCESS: &str = "health_check.success";
100    pub const FAILURE: &str = "health_check.failure";
101}
102
103/// H1 protocol counters.
104pub mod h1 {
105    pub const BACKEND_EOF_BEFORE_MESSAGE_COMPLETE: &str = "h1.backend_eof_before_message_complete";
106}
107
108/// H2 multiplexer counters — frame TX, flood mitigations, header policy
109/// rejections, signal-writable rearm sites, and other H2-specific buckets.
110pub mod h2 {
111    pub const CLOSE_WITH_ACTIVE_STREAMS: &str = "h2.close_with_active_streams";
112    pub const COALESCING_ACCEPTED: &str = "h2.coalescing.accepted";
113    pub const CONNECTION_ACTIVE_STREAMS: &str = "h2.connection.active_streams";
114    pub const CONNECTION_PENDING_WINDOW_UPDATES: &str = "h2.connection.pending_window_updates";
115    pub const CONNECTION_WINDOW_BYTES: &str = "h2.connection.window_bytes";
116    pub const FLOW_CONTROL_STALL: &str = "h2.flow_control_stall";
117
118    // Per-stream reap counters — `cancel_timed_out_streams` breaks reaps down by
119    // which guard tripped (M1), plus a stall-budget subset for the
120    // `WINDOW_UPDATE`-drip vector the cumulative-stall budget closes (M2).
121    // `reaped.stall_budget` is a subset of `reaped.window_stall`.
122    pub const STREAMS_REAPED_IDLE_TIMEOUT: &str = "h2.streams.reaped.idle_timeout";
123    pub const STREAMS_REAPED_WINDOW_STALL: &str = "h2.streams.reaped.window_stall";
124    pub const STREAMS_REAPED_STALL_BUDGET: &str = "h2.streams.reaped.stall_budget";
125
126    // Frame-TX counters (frame type fanout).
127    pub const FRAMES_TX_CONTINUATION: &str = "h2.frames.tx.continuation";
128    pub const FRAMES_TX_DATA: &str = "h2.frames.tx.data";
129    pub const FRAMES_TX_GOAWAY: &str = "h2.frames.tx.goaway";
130    pub const FRAMES_TX_HEADERS: &str = "h2.frames.tx.headers";
131    pub const FRAMES_TX_PING_ACK: &str = "h2.frames.tx.ping_ack";
132    pub const FRAMES_TX_RST_STREAM: &str = "h2.frames.tx.rst_stream";
133    pub const FRAMES_TX_SETTINGS: &str = "h2.frames.tx.settings";
134    pub const FRAMES_TX_WINDOW_UPDATE: &str = "h2.frames.tx.window_update";
135
136    // Header-policy rejections (the `h2.headers.rejected.*` family).
137    pub const HEADERS_NO_STREAM_ERROR: &str = "h2.headers_no_stream.error";
138    pub const HEADERS_REJECTED_BUDGET_OVERRUN: &str = "h2.headers.rejected.budget_overrun";
139    pub const HEADERS_REJECTED_TOTAL: &str = "h2.headers.rejected.total";
140
141    pub const RST_STREAM_RECEIVED_PRE_RESPONSE_START: &str =
142        "h2.rst_stream.received.pre_response_start";
143
144    // Writable-rearm signal counters — one per rearm reason.
145    pub const SIGNAL_WRITABLE_REARMED_CONTROL_QUEUE: &str =
146        "h2.signal.writable.rearmed.control_queue";
147    pub const SIGNAL_WRITABLE_REARMED_DEFAULT_ANSWER: &str =
148        "h2.signal.writable.rearmed.default_answer";
149    pub const SIGNAL_WRITABLE_REARMED_FORCEFULLY_TERMINATE_ANSWER: &str =
150        "h2.signal.writable.rearmed.forcefully_terminate_answer";
151    pub const SIGNAL_WRITABLE_REARMED_PEER_DATA: &str = "h2.signal.writable.rearmed.peer_data";
152    pub const SIGNAL_WRITABLE_REARMED_PEER_HEADERS: &str =
153        "h2.signal.writable.rearmed.peer_headers";
154    pub const SIGNAL_WRITABLE_REARMED_PRIORITY_UPDATE: &str =
155        "h2.signal.writable.rearmed.priority_update";
156
157    pub const TRAILERS_DROPPED_CONTENT_LENGTH: &str = "h2.trailers_dropped_content_length";
158    pub const TRAILER_SPOOF_VECTOR_ELIDED: &str = "h2.trailer.spoof_vector_elided";
159    pub const WINDOW_UPDATE_DROPPED: &str = "h2.window_update_dropped";
160
161    // Flood-mitigation violation counters — one per flood class the H2
162    // mux's `H2FloodDetector` recognises. Surfaced in the TUI's H2 pane
163    // so operators can spot a flood-pattern before it pages.
164    pub const FLOOD_VIOLATION_CONTINUATION: &str = "h2.flood.violation.continuation";
165    pub const FLOOD_VIOLATION_GLITCH_WINDOW: &str = "h2.flood.violation.glitch_window";
166    pub const FLOOD_VIOLATION_MADE_YOU_RESET: &str = "h2.flood.violation.made_you_reset";
167    pub const FLOOD_VIOLATION_PING: &str = "h2.flood.violation.ping";
168    pub const FLOOD_VIOLATION_PRIORITY: &str = "h2.flood.violation.priority";
169    pub const FLOOD_VIOLATION_RAPID_RESET: &str = "h2.flood.violation.rapid_reset";
170    pub const FLOOD_VIOLATION_SETTINGS: &str = "h2.flood.violation.settings";
171}
172
173/// HTTP counters (H1 + H2 share these); see `https` for the HTTPS-specific
174/// variants and `h2` for H2-frame-level counters.
175pub mod http {
176    pub const ERR_400: &str = "http.400.errors";
177    pub const ERR_404: &str = "http.404.errors";
178    pub const ACTIVE_REQUESTS: &str = "http.active_requests";
179    pub const ALPN_H2: &str = "http.alpn.h2";
180    pub const ALPN_HTTP11: &str = "http.alpn.http11";
181    pub const BACKEND_PARSE_ERRORS: &str = "http.backend_parse_errors";
182    pub const E2E_H2: &str = "http.e2e.h2";
183    pub const E2E_HTTP11: &str = "http.e2e.http11";
184    pub const EARLY_RESPONSE_CLOSE: &str = "http.early_response_close";
185    pub const FAILED_BACKEND_MATCHING: &str = "http.failed_backend_matching";
186    /// Requests rejected because a Transfer-Encoding header survived parsing without
187    /// kawa adopting chunked framing (CL.TE request-smuggling defense, CWE-444).
188    pub const FRONTEND_TE_SMUGGLING: &str = "http.frontend.transfer_encoding_smuggling";
189    pub const FRONTEND_PARSE_ERRORS: &str = "http.frontend_parse_errors";
190    pub const HSTS_FRONTEND_ADDED: &str = "http.hsts.frontend_added";
191    pub const HSTS_FRONTEND_REFRESHED: &str = "http.hsts.frontend_refreshed";
192    pub const HSTS_LISTENER_DEFAULT_PATCHED: &str = "http.hsts.listener_default_patched";
193    pub const HSTS_SUPPRESSED_PLAINTEXT: &str = "http.hsts.suppressed_plaintext";
194    pub const HSTS_UNRENDERED: &str = "http.hsts.unrendered";
195    pub const INFINITE_LOOP_ERROR: &str = "http.infinite_loop.error";
196    pub const REDIRECT_TEMPLATE_COMPILE_ERROR: &str = "http.redirect_template.compile_error";
197    pub const REQUESTS: &str = "http.requests";
198    pub const SNI_AUTHORITY_MISMATCH: &str = "http.sni_authority_mismatch";
199    pub const STATUS_1XX: &str = "http.status.1xx";
200    pub const STATUS_2XX: &str = "http.status.2xx";
201    pub const STATUS_3XX: &str = "http.status.3xx";
202    pub const STATUS_4XX: &str = "http.status.4xx";
203    pub const STATUS_5XX: &str = "http.status.5xx";
204    pub const STATUS_OTHER: &str = "http.status.other";
205    pub const TRUSTING_X_PORT: &str = "http.trusting.x_port";
206    pub const TRUSTING_X_PORT_DIFF: &str = "http.trusting.x_port.diff";
207    pub const TRUSTING_X_PROTO: &str = "http.trusting.x_proto";
208    pub const TRUSTING_X_PROTO_DIFF: &str = "http.trusting.x_proto.diff";
209    pub const UPGRADE_EXPECT_FAILED: &str = "http.upgrade.expect.failed";
210    pub const UPGRADE_MUX_FAILED: &str = "http.upgrade.mux.failed";
211    pub const UPGRADE_WS_FAILED: &str = "http.upgrade.ws.failed";
212    pub const X_REQUEST_ID_GENERATED: &str = "http.x_request_id.generated";
213    pub const X_REQUEST_ID_PROPAGATED: &str = "http.x_request_id.propagated";
214}
215
216/// Per-status-code HTTP counters. Only the codes Sōzu either generates as
217/// a default answer or that operators routinely chart get a dedicated bucket;
218/// the rest fold into the `http::STATUS_*XX` parent buckets.
219pub mod http_status {
220    pub const S200: &str = "http.status.200";
221    pub const S201: &str = "http.status.201";
222    pub const S204: &str = "http.status.204";
223    pub const S301: &str = "http.status.301";
224    pub const S302: &str = "http.status.302";
225    pub const S304: &str = "http.status.304";
226    pub const S400: &str = "http.status.400";
227    pub const S401: &str = "http.status.401";
228    pub const S403: &str = "http.status.403";
229    pub const S404: &str = "http.status.404";
230    pub const S408: &str = "http.status.408";
231    pub const S413: &str = "http.status.413";
232    pub const S429: &str = "http.status.429";
233    pub const S500: &str = "http.status.500";
234    pub const S502: &str = "http.status.502";
235    pub const S503: &str = "http.status.503";
236    pub const S504: &str = "http.status.504";
237    pub const S507: &str = "http.status.507";
238}
239
240/// HTTPS-specific counters; see `http` for the HTTP family these complement.
241pub mod https {
242    pub const ALPN_REJECTED_HTTP11_DISABLED: &str = "https.alpn.rejected.http11_disabled";
243    pub const ALPN_REJECTED_UNSUPPORTED: &str = "https.alpn.rejected.unsupported";
244    pub const UPGRADE_EXPECT_FAILED: &str = "https.upgrade.expect.failed";
245    pub const UPGRADE_HANDSHAKE_FAILED: &str = "https.upgrade.handshake.failed";
246    pub const UPGRADE_MUX_FAILED: &str = "https.upgrade.mux.failed";
247    pub const UPGRADE_WSS_FAILED: &str = "https.upgrade.wss.failed";
248}
249
250/// Per-listener counters.
251pub mod listener {
252    pub const ACCEPTED_TOTAL: &str = "listener.accepted.total";
253    pub const CONNECTION_CAPPED: &str = "listener.connection_capped";
254}
255
256/// Pipe-protocol counters.
257pub mod pipe {
258    pub const ERRORS: &str = "pipe.errors";
259}
260
261/// Protocol-type counters that increment once per session and track which
262/// protocol carried it end-to-end.
263pub mod protocol {
264    pub const HTTP: &str = "protocol.http";
265    pub const HTTPS: &str = "protocol.https";
266    pub const PROXY_EXPECT: &str = "protocol.proxy.expect";
267    pub const PROXY_RELAY: &str = "protocol.proxy.relay";
268    pub const PROXY_SEND: &str = "protocol.proxy.send";
269    pub const TCP: &str = "protocol.tcp";
270    pub const TLS_HANDSHAKE: &str = "protocol.tls.handshake";
271    pub const WS: &str = "protocol.ws";
272    pub const WSS: &str = "protocol.wss";
273}
274
275/// PROXY-protocol counters.
276pub mod proxy_protocol {
277    pub const ERRORS: &str = "proxy_protocol.errors";
278}
279
280/// `rustls`-specific counters for read/write infinite-loop guards.
281pub mod rustls {
282    pub const READ_ERROR: &str = "rustls.read.error";
283    pub const READ_INFINITE_LOOP_ERROR: &str = "rustls.read.infinite_loop.error";
284    pub const WRITE_ERROR: &str = "rustls.write.error";
285    pub const WRITE_INFINITE_LOOP_ERROR: &str = "rustls.write.infinite_loop.error";
286}
287
288/// Generic session-level counters.
289pub mod sessions {
290    pub const EVICTED: &str = "sessions.evicted";
291}
292
293/// Slab-allocator gauges.
294pub mod slab {
295    pub const CAPACITY: &str = "slab.capacity";
296    pub const ENTRIES: &str = "slab.entries";
297    pub const USAGE_PERCENT: &str = "slab.usage_percent";
298}
299
300/// Raw-socket counters.
301pub mod socket {
302    pub const READ_INFINITE_LOOP_ERROR: &str = "socket.read.infinite_loop.error";
303    pub const WRITE_INFINITE_LOOP_ERROR: &str = "socket.write.infinite_loop.error";
304}
305
306/// TCP protocol counters.
307pub mod tcp {
308    pub const INFINITE_LOOP_ERROR: &str = "tcp.infinite_loop.error";
309    pub const READ_ERROR: &str = "tcp.read.error";
310    pub const REQUESTS: &str = "tcp.requests";
311    pub const UPGRADE_EXPECT_FAILED: &str = "tcp.upgrade.expect.failed";
312    pub const UPGRADE_PIPE_FAILED: &str = "tcp.upgrade.pipe.failed";
313    pub const UPGRADE_RELAY_FAILED: &str = "tcp.upgrade.relay.failed";
314    pub const UPGRADE_SEND_FAILED: &str = "tcp.upgrade.send.failed";
315    pub const UPGRADE_SNI_PREREAD_FAILED: &str = "tcp.upgrade.sni_preread.failed";
316    pub const WRITE_ERROR: &str = "tcp.write.error";
317
318    /// SNI-preread counters (TCP passthrough routing, sozu-proxy/sozu#1279),
319    /// fed by the shell in `lib/src/protocol/tcp_preread/shell.rs` (decision
320    /// metrics) and `lib/src/tcp.rs` (the `ACTIVE` gauge + `DURATION`
321    /// timing, both owned centrally by the session lifecycle so each is
322    /// touched exactly once per session regardless of which of the three
323    /// exits -- reject / upgrade / teardown -- it takes).
324    pub mod sni_preread {
325        use crate::protocol::tcp_preread::RejectReason;
326
327        /// A cluster was chosen from the ClientHello's SNI (+ optional ALPN).
328        pub const ROUTED: &str = "tcp.sni_preread.routed";
329        /// Gauge: sessions currently prereading. Incremented once at
330        /// `SniPreread` construction, decremented exactly once on every
331        /// exit (reject / upgrade / teardown); underflow is a bug.
332        pub const ACTIVE: &str = "tcp.sni_preread.active";
333        /// `time!` of the wall-clock spent prereading, recorded on every
334        /// exit alongside the `ACTIVE` decrement.
335        pub const DURATION: &str = "tcp.sni_preread.duration";
336
337        pub const REJECTED_NOT_TLS: &str = "tcp.sni_preread.rejected.not_tls";
338        pub const REJECTED_MALFORMED_RECORD: &str = "tcp.sni_preread.rejected.malformed_record";
339        pub const REJECTED_MALFORMED_HANDSHAKE: &str =
340            "tcp.sni_preread.rejected.malformed_handshake";
341        pub const REJECTED_FRAGMENTED: &str = "tcp.sni_preread.rejected.fragmented";
342        pub const REJECTED_TOO_LARGE: &str = "tcp.sni_preread.rejected.too_large";
343        pub const REJECTED_NO_SNI: &str = "tcp.sni_preread.rejected.no_sni";
344        pub const REJECTED_ECH_OUTER_ABSENT: &str = "tcp.sni_preread.rejected.ech_outer_absent";
345        pub const REJECTED_SNI_UNMATCHED: &str = "tcp.sni_preread.rejected.sni_unmatched";
346        pub const REJECTED_ALPN_UNMATCHED: &str = "tcp.sni_preread.rejected.alpn_unmatched";
347        pub const REJECTED_PROXY_HEADER_INVALID: &str =
348            "tcp.sni_preread.rejected.proxy_header_invalid";
349        pub const REJECTED_FRONT_CLOSED: &str = "tcp.sni_preread.rejected.front_closed";
350
351        /// Total function over every `RejectReason` variant: a new variant
352        /// added to the core without a matching arm here fails to compile,
353        /// so the metric surface can never silently drop a rejection reason.
354        pub fn rejected_name(reason: RejectReason) -> &'static str {
355            match reason {
356                RejectReason::NotTls => REJECTED_NOT_TLS,
357                RejectReason::MalformedRecord => REJECTED_MALFORMED_RECORD,
358                RejectReason::MalformedHandshake => REJECTED_MALFORMED_HANDSHAKE,
359                RejectReason::Fragmented => REJECTED_FRAGMENTED,
360                RejectReason::TooLarge => REJECTED_TOO_LARGE,
361                RejectReason::NoSni => REJECTED_NO_SNI,
362                RejectReason::EchOuterAbsent => REJECTED_ECH_OUTER_ABSENT,
363                RejectReason::SniUnmatched => REJECTED_SNI_UNMATCHED,
364                RejectReason::AlpnUnmatched => REJECTED_ALPN_UNMATCHED,
365                RejectReason::ProxyHeaderInvalid => REJECTED_PROXY_HEADER_INVALID,
366                RejectReason::FrontClosed => REJECTED_FRONT_CLOSED,
367            }
368        }
369    }
370}
371
372/// UDP datapath counters/gauges, fed by the UDP I/O shell in `lib/src/udp.rs`.
373///
374/// `IN`/`OUT` follow the client perspective: `IN` = client→backend
375/// (request), `OUT` = backend→client (reply). `ACTIVE_FLOWS` is a gauge that
376/// must never underflow — it is incremented exactly once per admitted flow
377/// (`FLOWS_CREATED`) and decremented exactly once per close.
378pub mod udp {
379    /// Client→backend datagrams forwarded.
380    pub const DATAGRAMS_IN: &str = "udp.datagrams.in";
381    /// Backend→client datagrams returned.
382    pub const DATAGRAMS_OUT: &str = "udp.datagrams.out";
383    /// Payload bytes forwarded client→backend (excludes PPv2 prefix).
384    pub const BYTES_IN: &str = "udp.bytes.in";
385    /// Payload bytes returned backend→client.
386    pub const BYTES_OUT: &str = "udp.bytes.out";
387    /// Gauge: currently admitted flows. Never underflows.
388    pub const ACTIVE_FLOWS: &str = "udp.active_flows";
389    /// Flows admitted since boot.
390    pub const FLOWS_CREATED: &str = "udp.flows.created";
391    /// Flows torn down (idle / teardown / drain).
392    pub const FLOWS_EVICTED: &str = "udp.flows.evicted";
393    /// New flows shed at the `max_flows` cap or under fd pressure.
394    pub const FLOWS_SHED: &str = "udp.flows.shed";
395    /// Datagrams dropped before allocation (aggregate). Reason-specific
396    /// counters below carry the dotted `.<reason>` suffix; both are emitted
397    /// so dashboards can chart the total or break it down. The `incr!` macro
398    /// needs `&'static str`, so the by-reason names are fixed constants
399    /// rather than a runtime-formatted suffix.
400    pub const DATAGRAMS_DROPPED: &str = "udp.datagrams.dropped";
401    /// Dropped: failed validation (empty / extractor rejected).
402    pub const DROPPED_INVALID: &str = "udp.datagrams.dropped.invalid";
403    /// Dropped: exceeded `max_rx_datagram_size` (truncation surrogate).
404    pub const DROPPED_TRUNCATED: &str = "udp.datagrams.dropped.truncated";
405    /// Dropped: no cluster/backend configured for the listener.
406    pub const DROPPED_NO_BACKEND: &str = "udp.datagrams.dropped.no_backend";
407    /// Dropped: flow-table cap reached (shed).
408    pub const DROPPED_SHED: &str = "udp.datagrams.dropped.shed";
409    /// Dropped: referenced an unknown / already-closed flow.
410    pub const DROPPED_UNKNOWN_FLOW: &str = "udp.datagrams.dropped.unknown_flow";
411    /// Dropped: the bounded per-flow / client-return write queue was at
412    /// capacity (genuine egress-queue overflow under sustained `WouldBlock`).
413    pub const DROPPED_WQ_FULL: &str = "udp.datagrams.dropped.wq_full";
414    /// Dropped: a hard `send`/`send_to` error (e.g. ECONNREFUSED) on the egress
415    /// path, distinct from a queue-full overflow. The egress "no resolved flow /
416    /// socket gone" case routes to [`DROPPED_UNKNOWN_FLOW`] instead, so
417    /// `wq_full` only counts genuine bounded-queue overflow.
418    pub const DROPPED_SEND_ERROR: &str = "udp.datagrams.dropped.send_error";
419    /// Backend health transitions observed by the UDP health prober.
420    pub const BACKEND_HEALTH: &str = "udp.backend.health";
421    /// `time!` of a flow's lifetime, recorded on close.
422    pub const FLOW_DURATION: &str = "udp.flow.duration";
423}
424
425/// TLS counters (certificate inventory, handshake timing).
426pub mod tls {
427    pub const CERT_MIN_EXPIRES_AT_SECONDS: &str = "tls.cert.min_expires_at_seconds";
428    pub const DEFAULT_CERT_USED: &str = "tls.default_cert_used";
429    pub const HANDSHAKE_MS: &str = "tls.handshake_ms";
430}
431
432/// WebSocket counters.
433pub mod websocket {
434    pub const ACTIVE_REQUESTS: &str = "websocket.active_requests";
435}
436
437/// Miscellaneous counters that don't fit a richer family.
438pub mod misc {
439    pub const PANIC: &str = "panic";
440    pub const ZOMBIES: &str = "zombies";
441}