@@ -5,7 +5,9 @@ use std::{collections::HashMap, fmt};
5
5
use chrono:: Utc ;
6
6
use futures:: { Stream , StreamExt } ;
7
7
use metrics:: { register_histogram, Histogram } ;
8
+ use tracing:: Span ;
8
9
use vector_buffers:: topology:: channel:: { self , LimitedReceiver , LimitedSender } ;
10
+ use vector_common:: internal_event:: { ComponentEventsDropped , UNINTENTIONAL } ;
9
11
#[ cfg( test) ]
10
12
use vector_core:: event:: { into_event_stream, EventStatus } ;
11
13
use vector_core:: {
@@ -206,6 +208,9 @@ impl SourceSender {
206
208
recv
207
209
}
208
210
211
+ /// Send an event to the default output.
212
+ ///
213
+ /// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
209
214
pub async fn send_event ( & mut self , event : impl Into < EventArray > ) -> Result < ( ) , ClosedError > {
210
215
self . inner
211
216
. as_mut ( )
@@ -214,6 +219,9 @@ impl SourceSender {
214
219
. await
215
220
}
216
221
222
+ /// Send a stream of events to the default output.
223
+ ///
224
+ /// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
217
225
pub async fn send_event_stream < S , E > ( & mut self , events : S ) -> Result < ( ) , ClosedError >
218
226
where
219
227
S : Stream < Item = E > + Unpin ,
@@ -226,10 +234,14 @@ impl SourceSender {
226
234
. await
227
235
}
228
236
237
+ /// Send a batch of events to the default output.
238
+ ///
239
+ /// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
229
240
pub async fn send_batch < I , E > ( & mut self , events : I ) -> Result < ( ) , ClosedError >
230
241
where
231
242
E : Into < Event > + ByteSizeOf ,
232
243
I : IntoIterator < Item = E > ,
244
+ <I as IntoIterator >:: IntoIter : ExactSizeIterator ,
233
245
{
234
246
self . inner
235
247
. as_mut ( )
@@ -238,10 +250,14 @@ impl SourceSender {
238
250
. await
239
251
}
240
252
253
+ /// Send a batch of events event to a named output.
254
+ ///
255
+ /// This internally handles emitting [EventsSent] and [ComponentEventsDropped] events.
241
256
pub async fn send_batch_named < I , E > ( & mut self , name : & str , events : I ) -> Result < ( ) , ClosedError >
242
257
where
243
258
E : Into < Event > + ByteSizeOf ,
244
259
I : IntoIterator < Item = E > ,
260
+ <I as IntoIterator >:: IntoIter : ExactSizeIterator ,
245
261
{
246
262
self . named_inners
247
263
. get_mut ( name)
@@ -251,6 +267,47 @@ impl SourceSender {
251
267
}
252
268
}
253
269
270
+ /// UnsentEvents tracks the number of events yet to be sent in the buffer. This is used to
271
+ /// increment the appropriate counters when a future is not polled to completion. Particularly,
272
+ /// this is known to happen in a Warp server when a client sends a new HTTP request on a TCP
273
+ /// connection that already has a pending request.
274
+ ///
275
+ /// If its internal count is greater than 0 when dropped, the appropriate [ComponentEventsDropped]
276
+ /// event is emitted.
277
+ struct UnsentEventCount {
278
+ count : usize ,
279
+ span : Span ,
280
+ }
281
+
282
+ impl UnsentEventCount {
283
+ fn new ( count : usize ) -> Self {
284
+ Self {
285
+ count,
286
+ span : Span :: current ( ) ,
287
+ }
288
+ }
289
+
290
+ fn decr ( & mut self , count : usize ) {
291
+ self . count = self . count . saturating_sub ( count) ;
292
+ }
293
+
294
+ fn discard ( & mut self ) {
295
+ self . count = 0 ;
296
+ }
297
+ }
298
+
299
+ impl Drop for UnsentEventCount {
300
+ fn drop ( & mut self ) {
301
+ if self . count > 0 {
302
+ let _enter = self . span . enter ( ) ;
303
+ emit ! ( ComponentEventsDropped :: <UNINTENTIONAL > {
304
+ count: self . count,
305
+ reason: "Source send cancelled."
306
+ } ) ;
307
+ }
308
+ }
309
+ }
310
+
254
311
#[ derive( Clone ) ]
255
312
struct Inner {
256
313
inner : LimitedSender < EventArray > ,
@@ -322,7 +379,15 @@ impl Inner {
322
379
}
323
380
324
381
async fn send_event ( & mut self , event : impl Into < EventArray > ) -> Result < ( ) , ClosedError > {
325
- self . send ( event. into ( ) ) . await
382
+ let event: EventArray = event. into ( ) ;
383
+ // It's possible that the caller stops polling this future while it is blocked waiting
384
+ // on `self.send()`. When that happens, we use `UnsentEventCount` to correctly emit
385
+ // `ComponentEventsDropped` events.
386
+ let count = event. len ( ) ;
387
+ let mut unsent_event_count = UnsentEventCount :: new ( count) ;
388
+ let res = self . send ( event) . await ;
389
+ unsent_event_count. discard ( ) ;
390
+ res
326
391
}
327
392
328
393
async fn send_event_stream < S , E > ( & mut self , events : S ) -> Result < ( ) , ClosedError >
@@ -341,10 +406,22 @@ impl Inner {
341
406
where
342
407
E : Into < Event > + ByteSizeOf ,
343
408
I : IntoIterator < Item = E > ,
409
+ <I as IntoIterator >:: IntoIter : ExactSizeIterator ,
344
410
{
411
+ // It's possible that the caller stops polling this future while it is blocked waiting
412
+ // on `self.send()`. When that happens, we use `UnsentEventCount` to correctly emit
413
+ // `ComponentEventsDropped` events.
345
414
let events = events. into_iter ( ) . map ( Into :: into) ;
415
+ let mut unsent_event_count = UnsentEventCount :: new ( events. len ( ) ) ;
346
416
for events in array:: events_into_arrays ( events, Some ( CHUNK_SIZE ) ) {
347
- self . send ( events) . await ?;
417
+ let count = events. len ( ) ;
418
+ self . send ( events) . await . map_err ( |err| {
419
+ // The unsent event count is discarded here because the caller emits the
420
+ // `StreamClosedError`.
421
+ unsent_event_count. discard ( ) ;
422
+ err
423
+ } ) ?;
424
+ unsent_event_count. decr ( count) ;
348
425
}
349
426
Ok ( ( ) )
350
427
}
@@ -394,6 +471,7 @@ fn get_timestamp_millis(value: &Value) -> Option<i64> {
394
471
mod tests {
395
472
use chrono:: { DateTime , Duration } ;
396
473
use rand:: { thread_rng, Rng } ;
474
+ use tokio:: time:: timeout;
397
475
use vector_core:: event:: { LogEvent , Metric , MetricKind , MetricValue , TraceEvent } ;
398
476
use vrl:: event_path;
399
477
@@ -483,4 +561,83 @@ mod tests {
483
561
_ => panic ! ( "source_lag_time_seconds has invalid type" ) ,
484
562
}
485
563
}
564
+
565
+ #[ tokio:: test]
566
+ async fn emits_component_discarded_events_total_for_send_event ( ) {
567
+ metrics:: init_test ( ) ;
568
+ let ( mut sender, _recv) = SourceSender :: new_test_sender_with_buffer ( 1 ) ;
569
+
570
+ let event = Event :: Metric ( Metric :: new (
571
+ "name" ,
572
+ MetricKind :: Absolute ,
573
+ MetricValue :: Gauge { value : 123.4 } ,
574
+ ) ) ;
575
+
576
+ // First send will succeed.
577
+ sender
578
+ . send_event ( event. clone ( ) )
579
+ . await
580
+ . expect ( "First send should not fail" ) ;
581
+
582
+ // Second send will timeout, so the future will not be polled to completion.
583
+ let res = timeout (
584
+ std:: time:: Duration :: from_millis ( 100 ) ,
585
+ sender. send_event ( event. clone ( ) ) ,
586
+ )
587
+ . await ;
588
+ assert ! ( res. is_err( ) , "Send should have timed out." ) ;
589
+
590
+ let component_discarded_events_total = Controller :: get ( )
591
+ . expect ( "There must be a controller" )
592
+ . capture_metrics ( )
593
+ . into_iter ( )
594
+ . filter ( |metric| metric. name ( ) == "component_discarded_events_total" )
595
+ . collect :: < Vec < _ > > ( ) ;
596
+ assert_eq ! ( component_discarded_events_total. len( ) , 1 ) ;
597
+
598
+ let component_discarded_events_total = & component_discarded_events_total[ 0 ] ;
599
+ let MetricValue :: Counter { value } = component_discarded_events_total. value ( ) else {
600
+ panic ! ( "component_discarded_events_total has invalid type" )
601
+ } ;
602
+ assert_eq ! ( * value, 1.0 ) ;
603
+ }
604
+
605
+ #[ tokio:: test]
606
+ async fn emits_component_discarded_events_total_for_send_batch ( ) {
607
+ metrics:: init_test ( ) ;
608
+ let ( mut sender, _recv) = SourceSender :: new_test_sender_with_buffer ( 1 ) ;
609
+
610
+ let expected_drop = 100 ;
611
+ let events: Vec < Event > = ( 0 ..( CHUNK_SIZE + expected_drop) )
612
+ . map ( |_| {
613
+ Event :: Metric ( Metric :: new (
614
+ "name" ,
615
+ MetricKind :: Absolute ,
616
+ MetricValue :: Gauge { value : 123.4 } ,
617
+ ) )
618
+ } )
619
+ . collect ( ) ;
620
+
621
+ // `CHUNK_SIZE` events will be sent into buffer but then the future will not be polled to completion.
622
+ let res = timeout (
623
+ std:: time:: Duration :: from_millis ( 100 ) ,
624
+ sender. send_batch ( events) ,
625
+ )
626
+ . await ;
627
+ assert ! ( res. is_err( ) , "Send should have timed out." ) ;
628
+
629
+ let component_discarded_events_total = Controller :: get ( )
630
+ . expect ( "There must be a controller" )
631
+ . capture_metrics ( )
632
+ . into_iter ( )
633
+ . filter ( |metric| metric. name ( ) == "component_discarded_events_total" )
634
+ . collect :: < Vec < _ > > ( ) ;
635
+ assert_eq ! ( component_discarded_events_total. len( ) , 1 ) ;
636
+
637
+ let component_discarded_events_total = & component_discarded_events_total[ 0 ] ;
638
+ let MetricValue :: Counter { value } = component_discarded_events_total. value ( ) else {
639
+ panic ! ( "component_discarded_events_total has invalid type" )
640
+ } ;
641
+ assert_eq ! ( * value, expected_drop as f64 ) ;
642
+ }
486
643
}
0 commit comments