metrics_datadog_exporter/
data.rs1use std::sync::atomic::Ordering;
4use std::sync::Arc;
5
6use chrono::Utc;
7use itertools::Itertools;
8use metrics::atomics::AtomicU64;
9use metrics::{Key, Label};
10use metrics_util::AtomicBucket;
11
12use serde::{Deserialize, Serialize};
13use serde_with::skip_serializing_none;
14
15#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
17pub enum DataDogMetricType {
18 #[serde(rename = "count")]
20 Count,
21 #[serde(rename = "gauge")]
23 Gauge,
24 #[serde(rename = "histogram")]
26 Histogram,
27}
28
29#[derive(Debug, Serialize, Deserialize, Clone, PartialOrd, PartialEq)]
30#[serde(untagged)]
31pub enum DataDogMetricValue {
33 Float(f64),
35 Unsigned(u64),
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone, PartialOrd, PartialEq)]
40pub struct DataDogMetric {
42 pub metric: String,
44 pub metric_type: DataDogMetricType,
46 pub points: Vec<DataDogMetricValue>,
48 pub timestamp: i64,
50 pub tags: Vec<String>,
52}
53
54impl DataDogMetric {
55 pub(crate) fn from_counter(
56 key: Key,
57 values: Vec<Arc<AtomicU64>>,
58 global_tags: &[Label],
59 ) -> Self {
60 let values = values
61 .into_iter()
62 .map(|value| {
63 let u = value.load(Ordering::Acquire);
64 DataDogMetricValue::Unsigned(u)
65 })
66 .collect_vec();
67 DataDogMetric::from_metric_value(DataDogMetricType::Count, key, values, global_tags)
68 }
69
70 pub(crate) fn from_gauge(key: Key, values: Vec<Arc<AtomicU64>>, global_tags: &[Label]) -> Self {
71 let values = values
72 .into_iter()
73 .map(|value| {
74 let u = f64::from_bits(value.load(Ordering::Acquire));
75 DataDogMetricValue::Float(u)
76 })
77 .collect_vec();
78 DataDogMetric::from_metric_value(DataDogMetricType::Gauge, key, values, global_tags)
79 }
80
81 pub(crate) fn from_histogram(
82 key: Key,
83 values: Vec<Arc<AtomicBucket<f64>>>,
84 global_tags: &[Label],
85 ) -> Self {
86 let values = values
87 .into_iter()
88 .flat_map(|value| value.data().into_iter().map(DataDogMetricValue::Float))
89 .collect_vec();
90 DataDogMetric::from_metric_value(DataDogMetricType::Histogram, key, values, global_tags)
91 }
92
93 fn from_metric_value(
94 metric_type: DataDogMetricType,
95 key: Key,
96 values: Vec<DataDogMetricValue>,
97 global_tags: &[Label],
98 ) -> Self {
99 DataDogMetric {
100 metric: key.name().to_string(),
101 metric_type,
102 points: values,
103 timestamp: Utc::now().timestamp(),
104 tags: global_tags
105 .iter()
106 .chain(key.labels())
107 .map(|l| format!("{}:{}", l.key(), l.value()))
108 .collect(),
109 }
110 }
111
112 pub(crate) fn to_metric_lines(&self) -> Vec<DataDogMetricLine> {
113 self.points
114 .iter()
115 .map(|v| DataDogMetricLine {
116 name: self.metric.to_string(),
117 value: v.clone(),
118 timestamp: self.timestamp,
119 tags: self.tags.clone(),
120 })
121 .collect()
122 }
123}
124
125#[derive(Debug, Serialize, Deserialize, Clone)]
127pub struct DataDogMetricLine {
128 #[serde(rename = "m")]
130 pub name: String,
131 #[serde(rename = "v")]
133 pub value: DataDogMetricValue,
134 #[serde(rename = "e")]
136 pub timestamp: i64,
137 #[serde(rename = "t")]
139 pub tags: Vec<String>,
140}
141
142#[derive(Debug, Serialize, Clone)]
144pub struct DataDogApiPost<'a> {
145 pub series: &'a [DataDogSeries],
147}
148
149#[skip_serializing_none]
151#[derive(Debug, Serialize, Deserialize, Clone)]
152pub struct DataDogSeries {
153 pub interval: Option<i64>,
155 pub metric: String,
157 pub points: Vec<(i64, DataDogMetricValue)>,
159 pub tags: Vec<String>,
161 #[serde(rename = "type")]
163 pub metric_type: DataDogMetricType,
164}
165
166impl DataDogSeries {
167 pub fn new(m: DataDogMetric) -> Vec<DataDogSeries> {
169 m.points
170 .chunks(3)
171 .map(|points| DataDogSeries {
172 interval: None,
173 metric: m.metric.to_owned(),
174 points: points.iter().map(|v| (m.timestamp, v.to_owned())).collect(),
175 tags: m.tags.to_owned(),
176 metric_type: m.metric_type.to_owned(),
177 })
178 .collect_vec()
179 }
180}