11use std:: collections:: btree_map:: Entry ;
22use std:: collections:: { BTreeMap , BTreeSet } ;
33use std:: fmt;
4- use std:: sync:: mpsc:: { sync_channel, Receiver , RecvTimeoutError , SyncSender } ;
5- use std:: sync:: Arc ;
4+ use std:: sync:: mpsc;
65use std:: thread:: { self , JoinHandle } ;
76use std:: time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ;
87
9- use cadence:: MetricSink ;
108use sentry_types:: protocol:: latest:: { Envelope , EnvelopeItem } ;
119
1210use crate :: client:: TransportArc ;
13- use crate :: { Client , Hub } ;
14-
15- /// A [`cadence`] compatible [`MetricSink`].
16- ///
17- /// This will ingest all the emitted metrics to Sentry as well as forward them
18- /// to the inner [`MetricSink`].
19- #[ derive( Debug ) ]
20- pub struct SentryMetricSink < S > {
21- client : Arc < Client > ,
22- sink : S ,
23- }
24-
25- impl < S > SentryMetricSink < S > {
26- /// Creates a new [`SentryMetricSink`], wrapping the given [`MetricSink`].
27- pub fn try_new ( sink : S ) -> Result < Self , S > {
28- let hub = Hub :: current ( ) ;
29- let Some ( client) = hub. client ( ) else {
30- return Err ( sink) ;
31- } ;
32-
33- Ok ( Self { client, sink } )
34- }
35- }
36-
37- impl < S > MetricSink for SentryMetricSink < S >
38- where
39- S : MetricSink ,
40- {
41- fn emit ( & self , metric : & str ) -> std:: io:: Result < usize > {
42- self . client . add_metric ( metric) ;
43- self . sink . emit ( metric)
44- }
45-
46- fn flush ( & self ) -> std:: io:: Result < ( ) > {
47- if self . client . flush ( None ) {
48- self . sink . flush ( )
49- } else {
50- Err ( std:: io:: Error :: new (
51- std:: io:: ErrorKind :: Other ,
52- "Flushing Client failed" ,
53- ) )
54- }
55- }
56- }
5711
5812#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
5913enum MetricType {
@@ -166,7 +120,7 @@ enum Task {
166120}
167121
168122pub struct MetricAggregator {
169- sender : SyncSender < Task > ,
123+ sender : mpsc :: SyncSender < Task > ,
170124 handle : Option < JoinHandle < ( ) > > ,
171125}
172126
@@ -175,7 +129,7 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(10);
175129
176130impl MetricAggregator {
177131 pub fn new ( transport : TransportArc ) -> Self {
178- let ( sender, receiver) = sync_channel ( 30 ) ;
132+ let ( sender, receiver) = mpsc :: sync_channel ( 30 ) ;
179133 let handle = thread:: Builder :: new ( )
180134 . name ( "sentry-metrics" . into ( ) )
181135 . spawn ( move || Self :: worker_thread ( receiver, transport) )
@@ -240,15 +194,15 @@ impl MetricAggregator {
240194 let _ = self . sender . send ( Task :: Flush ) ;
241195 }
242196
243- fn worker_thread ( receiver : Receiver < Task > , transport : TransportArc ) {
197+ fn worker_thread ( receiver : mpsc :: Receiver < Task > , transport : TransportArc ) {
244198 let mut buckets = AggregateMetrics :: new ( ) ;
245199 let mut last_flush = Instant :: now ( ) ;
246200
247201 loop {
248202 let timeout = FLUSH_INTERVAL . saturating_sub ( last_flush. elapsed ( ) ) ;
249203
250204 match receiver. recv_timeout ( timeout) {
251- Err ( RecvTimeoutError :: Timeout ) | Ok ( Task :: Flush ) => {
205+ Err ( _ ) | Ok ( Task :: Flush ) => {
252206 // flush
253207 Self :: flush_buckets ( std:: mem:: take ( & mut buckets) , & transport) ;
254208 last_flush = Instant :: now ( ) ;
@@ -343,46 +297,3 @@ impl Drop for MetricAggregator {
343297 }
344298 }
345299}
346-
347- #[ cfg( test) ]
348- mod tests {
349- use std:: str:: from_utf8;
350-
351- use cadence:: { Counted , Distributed } ;
352-
353- use crate :: test:: with_captured_envelopes;
354-
355- use super :: * ;
356-
357- #[ test]
358- fn test_basic_metrics ( ) {
359- let envelopes = with_captured_envelopes ( || {
360- let sink = SentryMetricSink :: try_new ( cadence:: NopMetricSink ) . unwrap ( ) ;
361-
362- let client = cadence:: StatsdClient :: from_sink ( "sentry.test" , sink) ;
363- client. count ( "some.count" , 1 ) . unwrap ( ) ;
364- client. count ( "some.count" , 10 ) . unwrap ( ) ;
365- client
366- . count_with_tags ( "count.with.tags" , 1 )
367- . with_tag ( "foo" , "bar" )
368- . send ( ) ;
369- client. distribution ( "some.distr" , 1 ) . unwrap ( ) ;
370- client. distribution ( "some.distr" , 2 ) . unwrap ( ) ;
371- client. distribution ( "some.distr" , 3 ) . unwrap ( ) ;
372- } ) ;
373- assert_eq ! ( envelopes. len( ) , 1 ) ;
374-
375- let mut items = envelopes[ 0 ] . items ( ) ;
376- let Some ( EnvelopeItem :: Metrics ( metrics) ) = items. next ( ) else {
377- panic ! ( "expected metrics" ) ;
378- } ;
379- let metrics = from_utf8 ( metrics) . unwrap ( ) ;
380-
381- println ! ( "{metrics}" ) ;
382-
383- assert ! ( metrics. contains( "sentry.test.count.with.tags:1|c|#foo:bar|T" ) ) ;
384- assert ! ( metrics. contains( "sentry.test.some.count:11|c|T" ) ) ;
385- assert ! ( metrics. contains( "sentry.test.some.distr:1:2:3|d|T" ) ) ;
386- assert_eq ! ( items. next( ) , None ) ;
387- }
388- }
0 commit comments