relay_cardinality/config.rs
1use relay_base_schema::metrics::MetricNamespace;
2use serde::{Deserialize, Serialize};
3
4use crate::SlidingWindow;
5
6/// A cardinality limit.
7#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct CardinalityLimit {
10 /// Unique identifier of the cardinality limit.
11 pub id: String,
12
13 /// Whether this is a passive limit.
14 ///
15 /// Passive limits are tracked separately to normal limits
16 /// and are not enforced, but still evaluated.
17 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
18 pub passive: bool,
19 /// If `true` additional reporting of cardinality is enabled.
20 ///
21 /// The cardinality limiter will keep track of every tracked limit
22 /// and record the current cardinality. The reported data is not per limit
23 /// but per scope. For example if [`Self::scope`] is set to [`CardinalityScope::Name`],
24 /// the current cardinality for each metric name is reported.
25 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
26 pub report: bool,
27
28 /// The sliding window to enforce the cardinality limits in.
29 pub window: SlidingWindow,
30 /// The cardinality limit.
31 pub limit: u32,
32
33 /// Scope which the limit applies to.
34 pub scope: CardinalityScope,
35 /// Metric namespace the limit applies to.
36 ///
37 /// No namespace means this specific limit is enforced across all namespaces.
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub namespace: Option<MetricNamespace>,
40}
41
42/// A scope to restrict the [`CardinalityLimit`] to.
43#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
44#[serde(rename_all = "lowercase")]
45pub enum CardinalityScope {
46 /// An organization level cardinality limit.
47 ///
48 /// The limit will be enforced across the entire org.
49 Organization,
50
51 /// A project level cardinality limit.
52 ///
53 /// The limit will be enforced for a specific project.
54 ///
55 /// Hierarchy: `Organization > Project`.
56 Project,
57
58 /// A per metric type cardinality limit.
59 ///
60 /// This scope is very similar to [`Self::Name`], it operates on a per metric
61 /// basis which includes organization and project id.
62 ///
63 /// A metric type cardinality limit is mostly useful for cardinality reports.
64 ///
65 /// Hierarchy: `Organization > Project > Type`.
66 Type,
67
68 /// A per metric name cardinality limit.
69 ///
70 /// The name scope is a sub-scope of project and organization.
71 ///
72 /// Hierarchy: `Organization > Project > Name`.
73 Name,
74
75 /// Any other scope that is not known by this Relay.
76 #[serde(other)]
77 Unknown,
78}
79
80impl CardinalityScope {
81 /// Returns the string representation of this scope.
82 pub fn as_str(self) -> &'static str {
83 match self {
84 CardinalityScope::Organization => "organization",
85 CardinalityScope::Project => "project",
86 CardinalityScope::Type => "type",
87 CardinalityScope::Name => "name",
88 CardinalityScope::Unknown => "unknown",
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_cardinality_limit_json() {
99 let limit = CardinalityLimit {
100 id: "some_id".to_string(),
101 passive: false,
102 report: false,
103 window: SlidingWindow {
104 window_seconds: 3600,
105 granularity_seconds: 200,
106 },
107 limit: 1337,
108 scope: CardinalityScope::Organization,
109 namespace: Some(MetricNamespace::Custom),
110 };
111
112 let j = serde_json::to_string(&limit).unwrap();
113 assert_eq!(serde_json::from_str::<CardinalityLimit>(&j).unwrap(), limit);
114
115 let j = r#"{
116 "id":"some_id",
117 "window":{"windowSeconds":3600,"granularitySeconds":200},
118 "limit":1337,
119 "scope":"organization",
120 "namespace":"custom"
121 }"#;
122 assert_eq!(serde_json::from_str::<CardinalityLimit>(j).unwrap(), limit);
123 }
124}