1
1
use crate :: exporters:: * ;
2
2
use crate :: sensors:: { Sensor , Topology } ;
3
- use datadog_client :: client :: { Client , Config } ;
4
- use datadog_client :: metrics :: { Point , Serie , Type } ;
3
+ use serde :: ser :: SerializeSeq ;
4
+ use serde :: { Serialize , Serializer } ;
5
5
use std:: collections:: HashMap ;
6
6
use std:: thread;
7
7
use std:: time:: { Duration , Instant } ;
8
8
9
+ #[ derive( Clone , Debug ) ]
10
+ pub enum Type {
11
+ Count ,
12
+ Gauge ,
13
+ Rate ,
14
+ }
15
+
16
+ impl Type {
17
+ pub fn as_str ( & self ) -> & str {
18
+ match self {
19
+ Self :: Count => "count" ,
20
+ Self :: Gauge => "gauge" ,
21
+ Self :: Rate => "rate" ,
22
+ }
23
+ }
24
+ }
25
+
26
+ impl Serialize for Type {
27
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
28
+ where
29
+ S : Serializer ,
30
+ {
31
+ serializer. serialize_str ( self . as_str ( ) )
32
+ }
33
+ }
34
+
35
+ #[ derive( Clone , Debug ) ]
36
+ pub struct Point {
37
+ timestamp : u64 ,
38
+ value : f64 ,
39
+ }
40
+
41
+ impl Point {
42
+ pub fn new ( timestamp : u64 , value : f64 ) -> Self {
43
+ Self { timestamp, value }
44
+ }
45
+ }
46
+
47
+ impl Serialize for Point {
48
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
49
+ where
50
+ S : Serializer ,
51
+ {
52
+ let mut seq = serializer. serialize_seq ( Some ( 2 ) ) ?;
53
+ seq. serialize_element ( & self . timestamp ) ?;
54
+ seq. serialize_element ( & self . value ) ?;
55
+ seq. end ( )
56
+ }
57
+ }
58
+
59
+ /// # Examples
60
+ ///
61
+ /// ```
62
+ /// use datadog_client::metrics::{Point, Serie, Type};
63
+ ///
64
+ /// let serie = Serie::new("cpu.usage", Type::Gauge)
65
+ /// .set_host("raspberrypi")
66
+ /// .set_interval(42)
67
+ /// .set_points(vec![])
68
+ /// .add_point(Point::new(123456, 12.34))
69
+ /// .set_tags(vec![])
70
+ /// .add_tag(String::from("whatever:tag"));
71
+ /// ```
72
+ #[ derive( Debug , Clone , Serialize ) ]
73
+ pub struct Serie {
74
+ // The name of the host that produced the metric.
75
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
76
+ host : Option < String > ,
77
+ // If the type of the metric is rate or count, define the corresponding interval.
78
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
79
+ interval : Option < i64 > ,
80
+ // The name of the timeseries.
81
+ metric : String ,
82
+ // Points relating to a metric. All points must be tuples with timestamp and a scalar value (cannot be a string).
83
+ // Timestamps should be in POSIX time in seconds, and cannot be more than ten minutes in the future or more than one hour in the past.
84
+ points : Vec < Point > ,
85
+ // A list of tags associated with the metric.
86
+ tags : Vec < String > ,
87
+ // The type of the metric either count, gauge, or rate.
88
+ #[ serde( rename = "type" ) ]
89
+ dtype : Type ,
90
+ }
91
+
92
+ impl Serie {
93
+ pub fn new ( metric : & str , dtype : Type ) -> Self {
94
+ Self {
95
+ host : None ,
96
+ interval : None ,
97
+ metric : metric. to_string ( ) ,
98
+ points : Vec :: new ( ) ,
99
+ tags : Vec :: new ( ) ,
100
+ dtype,
101
+ }
102
+ }
103
+ }
104
+
105
+ impl Serie {
106
+ pub fn set_host ( mut self , host : & str ) -> Self {
107
+ self . host = Some ( host. to_string ( ) ) ;
108
+ self
109
+ }
110
+
111
+ pub fn set_interval ( mut self , interval : i64 ) -> Self {
112
+ self . interval = Some ( interval) ;
113
+ self
114
+ }
115
+
116
+ pub fn set_points ( mut self , points : Vec < Point > ) -> Self {
117
+ self . points = points;
118
+ self
119
+ }
120
+
121
+ pub fn add_point ( mut self , point : Point ) -> Self {
122
+ self . points . push ( point) ;
123
+ self
124
+ }
125
+ }
126
+
127
+ impl Serie {
128
+ pub fn set_tags ( mut self , tags : Vec < String > ) -> Self {
129
+ self . tags = tags;
130
+ self
131
+ }
132
+
133
+ pub fn add_tag ( mut self , tag : String ) -> Self {
134
+ self . tags . push ( tag) ;
135
+ self
136
+ }
137
+ }
138
+
139
+ struct Client {
140
+ host : String ,
141
+ api_key : String ,
142
+ }
143
+
144
+ impl Client {
145
+ pub fn new ( parameters : & ArgMatches ) -> Self {
146
+ Self {
147
+ host : parameters. value_of ( "host" ) . unwrap ( ) . to_string ( ) ,
148
+ api_key : parameters. value_of ( "api_key" ) . unwrap ( ) . to_string ( ) ,
149
+ }
150
+ }
151
+
152
+ pub fn send ( & self , series : & [ Serie ] ) {
153
+ let url = format ! ( "{}/api/v1/series" , self . host) ;
154
+ let request = ureq:: post ( url. as_str ( ) )
155
+ . set ( "DD-API-KEY" , self . api_key . as_str ( ) )
156
+ . send_json ( serde_json:: json!( { "series" : series } ) ) ;
157
+ match request {
158
+ Ok ( response) => {
159
+ if response. status ( ) >= 400 {
160
+ log:: warn!(
161
+ "couldn't send metrics to datadog: status {}" ,
162
+ response. status_text( )
163
+ ) ;
164
+ if let Ok ( body) = response. into_string ( ) {
165
+ log:: warn!( "response from server: {}" , body) ;
166
+ }
167
+ } else {
168
+ log:: info!( "metrics sent with success" ) ;
169
+ }
170
+ }
171
+ Err ( err) => log:: warn!( "error while sending metrics: {}" , err) ,
172
+ } ;
173
+ }
174
+ }
175
+
9
176
fn merge < A > ( first : Vec < A > , second : Vec < A > ) -> Vec < A > {
10
177
second. into_iter ( ) . fold ( first, |mut res, item| {
11
178
res. push ( item) ;
@@ -79,15 +246,8 @@ impl DatadogExporter {
79
246
}
80
247
}
81
248
82
- fn build_client ( parameters : & ArgMatches ) -> Client {
83
- let config = Config :: new (
84
- parameters. value_of ( "host" ) . unwrap ( ) . to_string ( ) ,
85
- parameters. value_of ( "api_key" ) . unwrap ( ) . to_string ( ) ,
86
- ) ;
87
- Client :: new ( config)
88
- }
89
-
90
- fn runner ( & mut self , parameters : & ArgMatches ) {
249
+ fn runner ( & mut self , parameters : & ArgMatches < ' _ > ) {
250
+ let client = Client :: new ( parameters) ;
91
251
if let Some ( timeout) = parameters. value_of ( "timeout" ) {
92
252
let now = Instant :: now ( ) ;
93
253
let timeout = timeout
@@ -110,18 +270,18 @@ impl DatadogExporter {
110
270
info ! ( "Measurement step is: {}s" , step_duration) ;
111
271
112
272
while now. elapsed ( ) . as_secs ( ) <= timeout {
113
- self . iterate ( parameters ) ;
273
+ self . iterate ( & client ) ;
114
274
thread:: sleep ( Duration :: new ( step_duration, step_duration_nano) ) ;
115
275
}
116
276
} else {
117
- self . iterate ( parameters ) ;
277
+ self . iterate ( & client ) ;
118
278
}
119
279
}
120
280
121
- fn iterate ( & mut self , parameters : & ArgMatches ) {
281
+ fn iterate ( & mut self , client : & Client ) {
122
282
self . topology . refresh ( ) ;
123
- let _series = self . collect_series ( ) ;
124
- let _client = Self :: build_client ( parameters ) ;
283
+ let series = self . collect_series ( ) ;
284
+ client . send ( & series ) ;
125
285
}
126
286
127
287
fn create_consumption_serie ( & self ) -> Serie {
0 commit comments