@@ -7,6 +7,8 @@ use vector_lib::{
7
7
event:: LogEvent ,
8
8
} ;
9
9
10
+ use crate :: event:: { Event , Metric , MetricKind , MetricValue } ;
11
+
10
12
use super :: config:: { DataTypeConfig , ListOption , Method , RedisSinkConfig } ;
11
13
use crate :: {
12
14
sinks:: prelude:: * ,
@@ -290,3 +292,98 @@ async fn redis_sink_channel_data_volume_tags() {
290
292
}
291
293
}
292
294
}
295
+
296
+ #[ tokio:: test]
297
+ async fn redis_sink_metrics ( ) {
298
+ trace_init ( ) ;
299
+
300
+ let key = Template :: try_from ( format ! ( "test-metrics-{}" , random_string( 10 ) ) )
301
+ . expect ( "should not fail to create key template" ) ;
302
+ debug ! ( "Test key name: {}." , key) ;
303
+ let num_events = 1000 ;
304
+ debug ! ( "Test events num: {}." , num_events) ;
305
+
306
+ let cnf = RedisSinkConfig {
307
+ endpoint : redis_server ( ) ,
308
+ key : key. clone ( ) ,
309
+ encoding : JsonSerializerConfig :: default ( ) . into ( ) ,
310
+ data_type : DataTypeConfig :: List ,
311
+ list_option : Some ( ListOption {
312
+ method : Method :: RPush ,
313
+ } ) ,
314
+ batch : BatchConfig :: default ( ) ,
315
+ request : TowerRequestConfig {
316
+ rate_limit_num : u64:: MAX ,
317
+ ..Default :: default ( )
318
+ } ,
319
+ acknowledgements : Default :: default ( ) ,
320
+ } ;
321
+
322
+ // Create a mix of counter and gauge metrics
323
+ let mut events: Vec < Event > = Vec :: new ( ) ;
324
+ for i in 0 ..num_events {
325
+ let metric = if i % 2 == 0 {
326
+ // Counter metrics
327
+ Metric :: new (
328
+ format ! ( "counter_{}" , i) ,
329
+ MetricKind :: Absolute ,
330
+ MetricValue :: Counter { value : i as f64 } ,
331
+ )
332
+ } else {
333
+ // Gauge metrics
334
+ Metric :: new (
335
+ format ! ( "gauge_{}" , i) ,
336
+ MetricKind :: Absolute ,
337
+ MetricValue :: Gauge { value : i as f64 } ,
338
+ )
339
+ } ;
340
+ events. push ( metric. into ( ) ) ;
341
+ }
342
+ let input = stream:: iter ( events. clone ( ) . into_iter ( ) . map ( Into :: into) ) ;
343
+
344
+ // Publish events
345
+ let cnf2 = cnf. clone ( ) ;
346
+ assert_sink_compliance ( & SINK_TAGS , async move {
347
+ let cx = SinkContext :: default ( ) ;
348
+ let ( sink, _healthcheck) = cnf2. build ( cx) . await . unwrap ( ) ;
349
+ sink. run ( input) . await
350
+ } )
351
+ . await
352
+ . expect ( "Running sink failed" ) ;
353
+
354
+ // Verify metrics were stored correctly
355
+ let mut conn = cnf. build_client ( ) . await . unwrap ( ) ;
356
+
357
+ let key_exists: bool = conn. exists ( key. to_string ( ) ) . await . unwrap ( ) ;
358
+ debug ! ( "Test key: {} exists: {}." , key, key_exists) ;
359
+ assert ! ( key_exists) ;
360
+
361
+ let llen: usize = conn. llen ( key. clone ( ) . to_string ( ) ) . await . unwrap ( ) ;
362
+ debug ! ( "Test key: {} len: {}." , key, llen) ;
363
+ assert_eq ! ( llen, num_events) ;
364
+
365
+ // Verify the content of each metric
366
+ for i in 0 ..num_events {
367
+ let original_event = events. get ( i) . unwrap ( ) . as_metric ( ) ;
368
+ let payload: ( String , String ) = conn. blpop ( key. clone ( ) . to_string ( ) , 2000.0 ) . await . unwrap ( ) ;
369
+ let val = payload. 1 ;
370
+
371
+ // Parse the JSON and verify key metric properties
372
+ let json: serde_json:: Value = serde_json:: from_str ( & val) . unwrap ( ) ;
373
+
374
+ if i % 2 == 0 {
375
+ // Counter metrics
376
+ assert_eq ! ( json[ "name" ] , format!( "counter_{}" , i) ) ;
377
+ assert_eq ! ( json[ "kind" ] , "absolute" ) ;
378
+ assert_eq ! ( json[ "counter" ] [ "value" ] , i as f64 ) ;
379
+ } else {
380
+ // Gauge metrics
381
+ assert_eq ! ( json[ "name" ] , format!( "gauge_{}" , i) ) ;
382
+ assert_eq ! ( json[ "kind" ] , "absolute" ) ;
383
+ assert_eq ! ( json[ "gauge" ] [ "value" ] , i as f64 ) ;
384
+ }
385
+
386
+ // Verify that the name matches what we expect
387
+ assert_eq ! ( json[ "name" ] . as_str( ) . unwrap( ) , original_event. name( ) ) ;
388
+ }
389
+ }
0 commit comments