1
- use crate :: { config:: { DataType , SinkConfig , SinkContext } , event:: Event , http:: HttpClient , sinks:: { Healthcheck , UriParseError , VectorSink , datadog:: { Region , healthcheck} , util:: { Compression , Concurrency , TowerRequestConfig , batch:: { BatchConfig , BatchSettings } , retries:: RetryLogic } } } ;
2
- use chrono:: Utc ;
3
- use futures:: { stream, FutureExt , SinkExt } ;
1
+ use crate :: {
2
+ config:: { DataType , SinkConfig , SinkContext } ,
3
+ http:: HttpClient ,
4
+ sinks:: {
5
+ datadog:: { healthcheck, Region } ,
6
+ util:: {
7
+ batch:: { BatchConfig , BatchSettings } ,
8
+ retries:: RetryLogic ,
9
+ Compression , Concurrency , ServiceBuilderExt , TowerRequestConfig ,
10
+ } ,
11
+ Healthcheck , UriParseError , VectorSink ,
12
+ } ,
13
+ } ;
14
+ use futures:: FutureExt ;
4
15
use http:: { uri:: InvalidUri , Uri } ;
5
16
use serde:: { Deserialize , Serialize } ;
6
17
use snafu:: { ResultExt , Snafu } ;
7
18
use tower:: ServiceBuilder ;
8
- use std:: {
9
- future:: ready,
10
- sync:: atomic:: AtomicI64 ,
19
+ use vector_core:: config:: proxy:: ProxyConfig ;
20
+
21
+ use super :: {
22
+ service:: { DatadogMetricsRetryLogic , DatadogMetricsService } ,
23
+ sink:: DatadogMetricsSink ,
11
24
} ;
12
25
13
26
// TODO: revisit our concurrency and batching defaults
14
27
const DEFAULT_REQUEST_LIMITS : TowerRequestConfig =
15
- TowerRequestConfig :: const_new ( Concurrency :: None , Concurrency :: None ) . retry_attempts ( 5 ) ;
28
+ TowerRequestConfig :: const_new ( Concurrency :: None , Concurrency :: None ) . retry_attempts ( 5 ) ;
16
29
17
30
const DEFAULT_BATCH_SETTINGS : BatchSettings < ( ) > =
18
- BatchSettings :: const_default ( ) . events ( 20 ) . timeout ( 1 ) ;
31
+ BatchSettings :: const_default ( ) . events ( 20 ) . timeout ( 1 ) ;
19
32
20
33
const MAXIMUM_SERIES_PAYLOAD_COMPRESSED_SIZE : usize = 3_200_000 ;
21
34
const MAXIMUM_SERIES_PAYLOAD_SIZE : usize = 62_914_560 ;
@@ -27,29 +40,14 @@ enum BuildError {
27
40
}
28
41
29
42
/// Various metric type-specific API types.
30
- ///
43
+ ///
31
44
/// Each of these corresponds to a specific request path when making a request to the agent API.
32
45
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
33
- enum DatadogMetricsEndpoint {
46
+ pub enum DatadogMetricsEndpoint {
34
47
Series ,
35
48
Distribution ,
36
49
}
37
50
38
- pub struct DatadogMetricsRetryLogic ;
39
-
40
- impl RetryLogic for DatadogMetricsRetryLogic {
41
- type Error = HttpError ;
42
- type Response = DatadogMetricsResponse ;
43
-
44
- fn is_retriable_error ( & self , error : & Self :: Error ) -> bool {
45
- todo ! ( )
46
- }
47
-
48
- fn should_retry_response ( & self , response : & Self :: Response ) -> RetryAction {
49
- todo ! ( )
50
- }
51
- }
52
-
53
51
#[ derive( Deserialize , Serialize , Debug , Clone , Default ) ]
54
52
#[ serde( deny_unknown_fields) ]
55
53
pub struct DatadogMetricsConfig {
@@ -66,8 +64,8 @@ pub struct DatadogMetricsConfig {
66
64
pub batch : BatchConfig ,
67
65
#[ serde( default ) ]
68
66
pub request : TowerRequestConfig ,
69
- #[ serde( default = "Compression::gzip_default" ) ]
70
- pub compression : Compression ,
67
+ #[ serde( default = "Compression::gzip_default" ) ]
68
+ pub compression : Compression ,
71
69
}
72
70
73
71
impl_generate_config_from_default ! ( DatadogMetricsConfig ) ;
@@ -78,12 +76,12 @@ impl SinkConfig for DatadogMetricsConfig {
78
76
async fn build ( & self , cx : SinkContext ) -> crate :: Result < ( VectorSink , Healthcheck ) > {
79
77
let client = HttpClient :: new ( None , cx. proxy ( ) ) ?;
80
78
81
- let client = self . build_client ( & cx. proxy ) ?;
82
- let healthcheck = self . build_healthcheck ( client. clone ( ) ) ;
83
- let sink = self . build_sink ( client, cx) ?;
79
+ let client = self . build_client ( & cx. proxy ) ?;
80
+ let healthcheck = self . build_healthcheck ( client. clone ( ) ) ;
81
+ let sink = self . build_sink ( client, cx) ?;
84
82
85
- Ok ( ( sink, healthcheck) )
86
- }
83
+ Ok ( ( sink, healthcheck) )
84
+ }
87
85
88
86
fn input_type ( & self ) -> DataType {
89
87
DataType :: Metric
@@ -95,103 +93,98 @@ impl SinkConfig for DatadogMetricsConfig {
95
93
}
96
94
97
95
impl DatadogMetricsConfig {
98
- /// Copies this `DatadogMetricsConfig` with the API key set to the given value .
99
- pub fn with_api_key < T : Into < String > > ( api_key : T ) -> Self {
96
+ /// Creates a default [ `DatadogMetricsConfig`] with the given API key.
97
+ pub fn from_api_key < T : Into < String > > ( api_key : T ) -> Self {
100
98
Self {
101
99
api_key : api_key. into ( ) ,
102
100
..Self :: default ( )
103
101
}
104
102
}
105
103
106
- /// Gets the base URI of the Datadog agent API.
107
- ///
108
- /// Per the Datadog agent convention, we should include a unique identifier as part of the
109
- /// domain to indicate that these metrics are being submitted by Vector, including the version,
110
- /// likely useful for detecting if a specific version of the agent (Vector, in this case) is
111
- /// doing something wrong, for understanding issues from the API side.
112
- ///
113
- /// The `endpoint` configuration field will be used here if it is present.
104
+ /// Gets the base URI of the Datadog agent API.
105
+ ///
106
+ /// Per the Datadog agent convention, we should include a unique identifier as part of the
107
+ /// domain to indicate that these metrics are being submitted by Vector, including the version,
108
+ /// likely useful for detecting if a specific version of the agent (Vector, in this case) is
109
+ /// doing something wrong, for understanding issues from the API side.
110
+ ///
111
+ /// The `endpoint` configuration field will be used here if it is present.
114
112
fn get_base_agent_endpoint ( & self ) -> String {
115
113
self . endpoint . clone ( ) . unwrap_or_else ( || {
116
114
let version = str:: replace ( crate :: built_info:: PKG_VERSION , "." , "-" ) ;
117
115
format ! ( "https://{}-vector.agent.{}" , version, self . get_site( ) )
118
116
} )
119
117
}
120
118
121
- /// Generates the full URIs to use for the various type-specific metrics endpoints.
122
- fn generate_metric_endpoints ( & self ) -> crate :: Result < Vec < ( DatadogMetricsEndpoint , Uri ) > > {
123
- let base_uri = self . get_base_metric_endpoint ( ) ;
124
- let series_endpoint = build_uri ( & base_uri, "/api/v1/series" ) ?;
125
- let distribution_endpoint = build_uri ( & base_uri, "/api/v1/distribution_points" ) ?;
126
-
127
- Ok ( vec ! [
128
- ( DatadogMetricsEndpoint :: Series , series_endpoint) ,
129
- ( DatadogMetricsEndpoint :: Distribution , distribution_endpoint) ,
130
- ] )
131
- }
132
-
133
- /// Gets the base URI of the Datadog API.
134
- ///
135
- /// The `endpoint` configuration field will be used here if it is present.
119
+ /// Generates the full URIs to use for the various type-specific metrics endpoints.
120
+ fn generate_metric_endpoints ( & self ) -> crate :: Result < Vec < ( DatadogMetricsEndpoint , Uri ) > > {
121
+ let base_uri = self . get_base_agent_endpoint ( ) ;
122
+ let series_endpoint = build_uri ( & base_uri, "/api/v1/series" ) ?;
123
+ let distribution_endpoint = build_uri ( & base_uri, "/api/v1/distribution_points" ) ?;
124
+
125
+ Ok ( vec ! [
126
+ ( DatadogMetricsEndpoint :: Series , series_endpoint) ,
127
+ ( DatadogMetricsEndpoint :: Distribution , distribution_endpoint) ,
128
+ ] )
129
+ }
130
+
131
+ /// Gets the base URI of the Datadog API.
132
+ ///
133
+ /// The `endpoint` configuration field will be used here if it is present.
136
134
fn get_api_endpoint ( & self ) -> String {
137
135
self . endpoint
138
136
. clone ( )
139
137
. unwrap_or_else ( || format ! ( "https://api.{}" , self . get_site( ) ) )
140
138
}
141
139
142
- /// Gets the base domain to use for any calls to Datadog.
143
- ///
144
- /// If `site` is not specified, we fallback to `region`, and if that is not specified, we
145
- /// fallback to the Datadog US domain.
140
+ /// Gets the base domain to use for any calls to Datadog.
141
+ ///
142
+ /// If `site` is not specified, we fallback to `region`, and if that is not specified, we
143
+ /// fallback to the Datadog US domain.
146
144
fn get_site ( & self ) -> & str {
147
145
self . site . as_deref ( ) . unwrap_or_else ( || match self . region {
148
146
Some ( Region :: Eu ) => "datadoghq.eu" ,
149
147
None | Some ( Region :: Us ) => "datadoghq.com" ,
150
148
} )
151
149
}
152
150
153
- fn build_client ( & self , proxy : & ProxyConfig ) -> crate :: Result < HttpClient > {
154
- HttpClient :: new ( None , proxy)
155
- }
156
-
157
- fn build_healthcheck ( & self , client : HttpClient ) -> Healthcheck {
158
- healthcheck ( self . get_api_endpoint ( ) , self . api_key . clone ( ) , client) . boxed ( )
159
- }
160
-
161
- fn build_sink ( & self , client : HttpClient , cx : SinkContext ) -> crate :: Result < VectorSink > {
162
- let batch = DEFAULT_BATCH_SETTINGS
163
- . parse_config ( self . batch ) ?;
164
-
165
- let request_limits = self . request . unwrap_with ( & DEFAULT_REQUEST_LIMITS ) ;
166
- let metric_endpoints = self . generate_metric_endpoints ( ) ?;
167
- let service = ServiceBuilder :: new ( )
168
- . settings ( request_limits, DatadogMetricsRetryLogic )
169
- . service ( DatadogMetricsService :: new ( client) ) ;
170
-
171
- let sink = DatadogMetricsSink :: new (
172
- cx,
173
- service,
174
- metric_endpoints,
175
- compression: self . compression ,
176
- ) ;
177
-
178
- Ok ( VectorSink :: Sink ( Box :: new ( sink) ) )
179
- }
151
+ fn build_client ( & self , proxy : & ProxyConfig ) -> crate :: Result < HttpClient > {
152
+ let client = HttpClient :: new ( None , proxy) ?;
153
+ Ok ( client)
154
+ }
155
+
156
+ fn build_healthcheck ( & self , client : HttpClient ) -> Healthcheck {
157
+ healthcheck ( self . get_api_endpoint ( ) , self . api_key . clone ( ) , client) . boxed ( )
158
+ }
159
+
160
+ fn build_sink ( & self , client : HttpClient , cx : SinkContext ) -> crate :: Result < VectorSink > {
161
+ let batch = DEFAULT_BATCH_SETTINGS . parse_config ( self . batch ) ?;
162
+
163
+ let request_limits = self . request . unwrap_with ( & DEFAULT_REQUEST_LIMITS ) ;
164
+ let metric_endpoints = self . generate_metric_endpoints ( ) ?;
165
+ let service = ServiceBuilder :: new ( )
166
+ . settings ( request_limits, DatadogMetricsRetryLogic )
167
+ . service ( DatadogMetricsService :: new ( client) ) ;
168
+
169
+ let sink = DatadogMetricsSink :: new ( cx, service, metric_endpoints, self . compression ) ;
170
+
171
+ Ok ( VectorSink :: Stream ( Box :: new ( sink) ) )
172
+ }
180
173
}
181
174
182
175
fn build_uri ( host : & str , endpoint : & str ) -> crate :: Result < Uri > {
183
- format ! ( "{}{}" , host, endpoint)
176
+ let result = format ! ( "{}{}" , host, endpoint)
184
177
. parse :: < Uri > ( )
185
- . context ( UriParseError )
178
+ . context ( UriParseError ) ?;
179
+ Ok ( result)
186
180
}
187
181
188
182
#[ cfg( test) ]
189
183
mod tests {
190
184
use super :: * ;
191
- use crate :: { event:: metric:: Sample , sinks:: util:: test:: load_sink} ;
192
185
193
186
#[ test]
194
187
fn generate_config ( ) {
195
- crate :: test_util:: test_generate_config :: < DatadogConfig > ( ) ;
188
+ crate :: test_util:: test_generate_config :: < DatadogMetricsConfig > ( ) ;
196
189
}
197
190
}
0 commit comments