11use crate :: exporters:: * ;
22use 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 } ;
55use std:: collections:: HashMap ;
66use std:: thread;
77use std:: time:: { Duration , Instant } ;
88
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+ #[ derive( Debug , Clone , Serialize ) ]
60+ pub struct Serie {
61+ // The name of the host that produced the metric.
62+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
63+ host : Option < String > ,
64+ // If the type of the metric is rate or count, define the corresponding interval.
65+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
66+ interval : Option < i64 > ,
67+ // The name of the timeseries.
68+ metric : String ,
69+ // Points relating to a metric. All points must be tuples with timestamp and a scalar value (cannot be a string).
70+ // 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.
71+ points : Vec < Point > ,
72+ // A list of tags associated with the metric.
73+ tags : Vec < String > ,
74+ // The type of the metric either count, gauge, or rate.
75+ #[ serde( rename = "type" ) ]
76+ dtype : Type ,
77+ }
78+
79+ impl Serie {
80+ pub fn new ( metric : & str , dtype : Type ) -> Self {
81+ Self {
82+ host : None ,
83+ interval : None ,
84+ metric : metric. to_string ( ) ,
85+ points : Vec :: new ( ) ,
86+ tags : Vec :: new ( ) ,
87+ dtype,
88+ }
89+ }
90+ }
91+
92+ impl Serie {
93+ pub fn set_host ( mut self , host : & str ) -> Self {
94+ self . host = Some ( host. to_string ( ) ) ;
95+ self
96+ }
97+
98+ pub fn set_interval ( mut self , interval : i64 ) -> Self {
99+ self . interval = Some ( interval) ;
100+ self
101+ }
102+
103+ pub fn set_points ( mut self , points : Vec < Point > ) -> Self {
104+ self . points = points;
105+ self
106+ }
107+
108+ pub fn add_point ( mut self , point : Point ) -> Self {
109+ self . points . push ( point) ;
110+ self
111+ }
112+ }
113+
114+ impl Serie {
115+ pub fn set_tags ( mut self , tags : Vec < String > ) -> Self {
116+ self . tags = tags;
117+ self
118+ }
119+
120+ pub fn add_tag ( mut self , tag : String ) -> Self {
121+ self . tags . push ( tag) ;
122+ self
123+ }
124+ }
125+
126+ struct Client {
127+ host : String ,
128+ api_key : String ,
129+ }
130+
131+ impl Client {
132+ pub fn new ( parameters : & ArgMatches ) -> Self {
133+ Self {
134+ host : parameters. value_of ( "host" ) . unwrap ( ) . to_string ( ) ,
135+ api_key : parameters. value_of ( "api_key" ) . unwrap ( ) . to_string ( ) ,
136+ }
137+ }
138+
139+ pub fn send ( & self , series : & [ Serie ] ) {
140+ let url = format ! ( "{}/api/v1/series" , self . host) ;
141+ let request = ureq:: post ( url. as_str ( ) )
142+ . set ( "DD-API-KEY" , self . api_key . as_str ( ) )
143+ . send_json ( serde_json:: json!( { "series" : series } ) ) ;
144+ match request {
145+ Ok ( response) => {
146+ if response. status ( ) >= 400 {
147+ log:: warn!(
148+ "couldn't send metrics to datadog: status {}" ,
149+ response. status_text( )
150+ ) ;
151+ if let Ok ( body) = response. into_string ( ) {
152+ log:: warn!( "response from server: {}" , body) ;
153+ }
154+ } else {
155+ log:: info!( "metrics sent with success" ) ;
156+ }
157+ }
158+ Err ( err) => log:: warn!( "error while sending metrics: {}" , err) ,
159+ } ;
160+ }
161+ }
162+
9163fn merge < A > ( first : Vec < A > , second : Vec < A > ) -> Vec < A > {
10164 second. into_iter ( ) . fold ( first, |mut res, item| {
11165 res. push ( item) ;
@@ -79,15 +233,8 @@ impl DatadogExporter {
79233 }
80234 }
81235
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 ) {
236+ fn runner ( & mut self , parameters : & ArgMatches < ' _ > ) {
237+ let client = Client :: new ( parameters) ;
91238 if let Some ( timeout) = parameters. value_of ( "timeout" ) {
92239 let now = Instant :: now ( ) ;
93240 let timeout = timeout
@@ -110,18 +257,18 @@ impl DatadogExporter {
110257 info ! ( "Measurement step is: {}s" , step_duration) ;
111258
112259 while now. elapsed ( ) . as_secs ( ) <= timeout {
113- self . iterate ( parameters ) ;
260+ self . iterate ( & client ) ;
114261 thread:: sleep ( Duration :: new ( step_duration, step_duration_nano) ) ;
115262 }
116263 } else {
117- self . iterate ( parameters ) ;
264+ self . iterate ( & client ) ;
118265 }
119266 }
120267
121- fn iterate ( & mut self , parameters : & ArgMatches ) {
268+ fn iterate ( & mut self , client : & Client ) {
122269 self . topology . refresh ( ) ;
123- let _series = self . collect_series ( ) ;
124- let _client = Self :: build_client ( parameters ) ;
270+ let series = self . collect_series ( ) ;
271+ client . send ( & series ) ;
125272 }
126273
127274 fn create_consumption_serie ( & self ) -> Serie {
0 commit comments