1- //! Batching for Sentry [structured logs](https://docs.sentry.io/product/explore/logs/) .
1+ //! Generic batching for Sentry envelope items .
22
33use std:: sync:: { Arc , Condvar , Mutex , MutexGuard } ;
44use std:: thread:: JoinHandle ;
@@ -9,37 +9,61 @@ use crate::protocol::EnvelopeItem;
99use crate :: Envelope ;
1010use sentry_types:: protocol:: v7:: Log ;
1111
12- // Flush when there's 100 logs in the buffer
13- const MAX_LOG_ITEMS : usize = 100 ;
12+ // Flush when there's 100 items in the buffer
13+ const MAX_ITEMS : usize = 100 ;
1414// Or when 5 seconds have passed from the last flush
1515const FLUSH_INTERVAL : Duration = Duration :: from_secs ( 5 ) ;
1616
17- #[ derive( Debug , Default ) ]
18- struct LogQueue {
19- logs : Vec < Log > ,
17+ #[ derive( Debug ) ]
18+ struct BatchQueue < T > {
19+ items : Vec < T > ,
2020}
2121
22- /// Accumulates logs in the queue and submits them through the transport when one of the flushing
22+ pub ( crate ) trait IntoBatchEnvelopeItem : Sized {
23+ fn into_envelope_item ( items : Vec < Self > ) -> EnvelopeItem ;
24+ }
25+
26+ impl < T > IntoBatchEnvelopeItem for T
27+ where
28+ Vec < T > : Into < EnvelopeItem > ,
29+ {
30+ fn into_envelope_item ( items : Vec < Self > ) -> EnvelopeItem {
31+ items. into ( )
32+ }
33+ }
34+
35+ pub ( crate ) trait Batch : IntoBatchEnvelopeItem {
36+ const TYPE_NAME : & str ;
37+ }
38+
39+ impl Batch for Log {
40+ const TYPE_NAME : & str = "logs" ;
41+ }
42+
43+ /// Accumulates items in the queue and submits them through the transport when one of the flushing
2344/// conditions is met.
24- pub ( crate ) struct LogsBatcher {
45+ pub ( crate ) struct Batcher < T : Batch > {
2546 transport : TransportArc ,
26- queue : Arc < Mutex < LogQueue > > ,
47+ queue : Arc < Mutex < BatchQueue < T > > > ,
2748 shutdown : Arc < ( Mutex < bool > , Condvar ) > ,
2849 worker : Option < JoinHandle < ( ) > > ,
2950}
3051
31- impl LogsBatcher {
32- /// Creates a new LogsBatcher that will submit envelopes to the given `transport`.
52+ impl < T > Batcher < T >
53+ where
54+ T : Batch + Send + ' static ,
55+ {
56+ /// Creates a new Batcher that will submit envelopes to the given `transport`.
3357 pub ( crate ) fn new ( transport : TransportArc ) -> Self {
34- let queue = Arc :: new ( Mutex :: new ( Default :: default ( ) ) ) ;
58+ let queue = Arc :: new ( Mutex :: new ( BatchQueue { items : Vec :: new ( ) } ) ) ;
3559 #[ allow( clippy:: mutex_atomic) ]
3660 let shutdown = Arc :: new ( ( Mutex :: new ( false ) , Condvar :: new ( ) ) ) ;
3761
3862 let worker_transport = transport. clone ( ) ;
3963 let worker_queue = queue. clone ( ) ;
4064 let worker_shutdown = shutdown. clone ( ) ;
4165 let worker = std:: thread:: Builder :: new ( )
42- . name ( "sentry-logs -batcher" . into ( ) )
66+ . name ( format ! ( "sentry-{} -batcher" , T :: TYPE_NAME ) )
4367 . spawn ( move || {
4468 let ( lock, cvar) = worker_shutdown. as_ref ( ) ;
4569 let mut shutdown = lock. lock ( ) . unwrap ( ) ;
@@ -57,7 +81,7 @@ impl LogsBatcher {
5781 return ;
5882 }
5983 if last_flush. elapsed ( ) >= FLUSH_INTERVAL {
60- LogsBatcher :: flush_queue_internal (
84+ Batcher :: flush_queue_internal (
6185 worker_queue. lock ( ) . unwrap ( ) ,
6286 & worker_transport,
6387 ) ;
@@ -74,48 +98,50 @@ impl LogsBatcher {
7498 worker : Some ( worker) ,
7599 }
76100 }
101+ }
77102
78- /// Enqueues a log for delayed sending.
103+ impl < T : Batch > Batcher < T > {
104+ /// Enqueues an item for delayed sending.
79105 ///
80- /// This will automatically flush the queue if it reaches a size of `BATCH_SIZE `.
81- pub ( crate ) fn enqueue ( & self , log : Log ) {
106+ /// This will automatically flush the queue if it reaches a size of `MAX_ITEMS `.
107+ pub ( crate ) fn enqueue ( & self , item : T ) {
82108 let mut queue = self . queue . lock ( ) . unwrap ( ) ;
83- queue. logs . push ( log ) ;
84- if queue. logs . len ( ) >= MAX_LOG_ITEMS {
85- LogsBatcher :: flush_queue_internal ( queue, & self . transport ) ;
109+ queue. items . push ( item ) ;
110+ if queue. items . len ( ) >= MAX_ITEMS {
111+ Batcher :: flush_queue_internal ( queue, & self . transport ) ;
86112 }
87113 }
88114
89115 /// Flushes the queue to the transport.
90116 pub ( crate ) fn flush ( & self ) {
91117 let queue = self . queue . lock ( ) . unwrap ( ) ;
92- LogsBatcher :: flush_queue_internal ( queue, & self . transport ) ;
118+ Batcher :: flush_queue_internal ( queue, & self . transport ) ;
93119 }
94120
95121 /// Flushes the queue to the transport.
96122 ///
97123 /// This is a static method as it will be called from both the background
98124 /// thread and the main thread on drop.
99- fn flush_queue_internal ( mut queue_lock : MutexGuard < LogQueue > , transport : & TransportArc ) {
100- let logs = std:: mem:: take ( & mut queue_lock. logs ) ;
125+ fn flush_queue_internal ( mut queue_lock : MutexGuard < BatchQueue < T > > , transport : & TransportArc ) {
126+ let items = std:: mem:: take ( & mut queue_lock. items ) ;
101127 drop ( queue_lock) ;
102128
103- if logs . is_empty ( ) {
129+ if items . is_empty ( ) {
104130 return ;
105131 }
106132
107- sentry_debug ! ( "[LogsBatcher ] Flushing {} logs " , logs . len( ) ) ;
133+ sentry_debug ! ( "[Batcher({}) ] Flushing {} items " , T :: TYPE_NAME , items . len( ) ) ;
108134
109135 if let Some ( ref transport) = * transport. read ( ) . unwrap ( ) {
110136 let mut envelope = Envelope :: new ( ) ;
111- let logs_item : EnvelopeItem = logs . into ( ) ;
112- envelope. add_item ( logs_item ) ;
137+ let envelope_item = T :: into_envelope_item ( items ) ;
138+ envelope. add_item ( envelope_item ) ;
113139 transport. send_envelope ( envelope) ;
114140 }
115141 }
116142}
117143
118- impl Drop for LogsBatcher {
144+ impl < T : Batch > Drop for Batcher < T > {
119145 fn drop ( & mut self ) {
120146 let ( lock, cvar) = self . shutdown . as_ref ( ) ;
121147 * lock. lock ( ) . unwrap ( ) = true ;
@@ -124,7 +150,7 @@ impl Drop for LogsBatcher {
124150 if let Some ( worker) = self . worker . take ( ) {
125151 worker. join ( ) . ok ( ) ;
126152 }
127- LogsBatcher :: flush_queue_internal ( self . queue . lock ( ) . unwrap ( ) , & self . transport ) ;
153+ Batcher :: flush_queue_internal ( self . queue . lock ( ) . unwrap ( ) , & self . transport ) ;
128154 }
129155}
130156
0 commit comments