@@ -6,15 +6,15 @@ use std::sync::RwLock;
66
77use glean_core:: metrics:: MetricType ;
88
9- use super :: { BooleanMetric , CommonMetricData , CounterMetric , ErrorType , StringMetric } ;
9+ use super :: { BooleanMetric , CommonMetricData , CounterMetric , ErrorType , MetricId , StringMetric } ;
1010use crate :: dispatcher;
1111use crate :: ipc:: need_ipc;
1212
1313/// Sealed traits protect against downstream implementations.
1414///
1515/// We wrap it in a private module that is inaccessible outside of this module.
1616mod private {
17- use super :: { BooleanMetric , CommonMetricData , CounterMetric , StringMetric } ;
17+ use super :: { BooleanMetric , CommonMetricData , CounterMetric , MetricId , StringMetric } ;
1818 use crate :: ipc:: need_ipc;
1919 use std:: sync:: Arc ;
2020
@@ -26,7 +26,7 @@ mod private {
2626 type Inner : glean_core:: metrics:: MetricType + Clone ;
2727
2828 /// Create a new metric object from the inner type.
29- fn from_inner ( metric : Self :: Inner ) -> Self ;
29+ fn from_inner ( id : MetricId , metric : Self :: Inner ) -> Self ;
3030
3131 /// Create a new `glean_core `metric of the inner type.
3232 fn new_inner ( meta : CommonMetricData ) -> Self :: Inner ;
@@ -38,7 +38,7 @@ mod private {
3838 impl Sealed for BooleanMetric {
3939 type Inner = glean_core:: metrics:: BooleanMetric ;
4040
41- fn from_inner ( metric : Self :: Inner ) -> Self {
41+ fn from_inner ( _id : MetricId , metric : Self :: Inner ) -> Self {
4242 assert ! (
4343 !need_ipc( ) ,
4444 "Labeled Boolean metrics are not supported in non-main processes"
@@ -57,7 +57,7 @@ mod private {
5757 impl Sealed for StringMetric {
5858 type Inner = glean_core:: metrics:: StringMetric ;
5959
60- fn from_inner ( metric : Self :: Inner ) -> Self {
60+ fn from_inner ( _id : MetricId , metric : Self :: Inner ) -> Self {
6161 assert ! (
6262 !need_ipc( ) ,
6363 "Labeled String metrics are not supported in non-main processes"
@@ -76,9 +76,12 @@ mod private {
7676 impl Sealed for CounterMetric {
7777 type Inner = glean_core:: metrics:: CounterMetric ;
7878
79- fn from_inner ( metric : Self :: Inner ) -> Self {
79+ fn from_inner ( id : MetricId , metric : Self :: Inner ) -> Self {
8080 assert ! ( !need_ipc( ) ) ;
81- CounterMetric :: Parent ( Arc :: new ( crate :: private:: counter:: CounterMetricImpl ( metric) ) )
81+ CounterMetric :: Parent {
82+ id,
83+ inner : Arc :: new ( crate :: private:: counter:: CounterMetricImpl ( metric) ) ,
84+ }
8285 }
8386
8487 fn new_inner ( meta : CommonMetricData ) -> Self :: Inner {
@@ -126,6 +129,9 @@ impl<T> AllowLabeled for T where T: private::Sealed {}
126129/// ```
127130#[ derive( Debug ) ]
128131pub struct LabeledMetric < T : AllowLabeled > {
132+ /// The metric ID of the underlying metric.
133+ id : MetricId ,
134+
129135 /// Wrapping the underlying core metric.
130136 ///
131137 /// We delegate all functionality to this and wrap it up again in our own metric type.
@@ -141,11 +147,16 @@ where
141147 /// Create a new labeled metric from the given metric instance and optional list of labels.
142148 ///
143149 /// See [`get`](#method.get) for information on how static or dynamic labels are handled.
144- pub fn new ( meta : CommonMetricData , labels : Option < Vec < String > > ) -> LabeledMetric < T > {
150+ pub fn new (
151+ id : MetricId ,
152+ meta : CommonMetricData ,
153+ labels : Option < Vec < String > > ,
154+ ) -> LabeledMetric < T > {
145155 let submetric = T :: new_inner ( meta) ;
146156 let core = glean_core:: metrics:: LabeledMetric :: new ( submetric, labels) ;
147157
148158 LabeledMetric {
159+ id,
149160 core : RwLock :: new ( core) ,
150161 }
151162 }
@@ -172,7 +183,7 @@ where
172183 . write ( )
173184 . expect ( "lock of wrapped metric was poisoned" ) ;
174185 let inner = core. get ( label) ;
175- T :: from_inner ( inner)
186+ T :: from_inner ( self . id , inner)
176187 }
177188 }
178189
@@ -209,3 +220,173 @@ where
209220 } )
210221 }
211222}
223+
224+ #[ cfg( test) ]
225+ mod test {
226+ use once_cell:: sync:: Lazy ;
227+
228+ use super :: * ;
229+ use crate :: common_test:: * ;
230+
231+ // Smoke test for what should be the generated code.
232+ static GLOBAL_METRIC : Lazy < LabeledMetric < BooleanMetric > > = Lazy :: new ( || {
233+ LabeledMetric :: new (
234+ 0 . into ( ) ,
235+ CommonMetricData {
236+ name : "global" . into ( ) ,
237+ category : "metric" . into ( ) ,
238+ send_in_pings : vec ! [ "ping" . into( ) ] ,
239+ disabled : false ,
240+ ..Default :: default ( )
241+ } ,
242+ None ,
243+ )
244+ } ) ;
245+
246+ #[ test]
247+ fn smoke_test_global_metric ( ) {
248+ let _lock = lock_test ( ) ;
249+
250+ GLOBAL_METRIC . get ( "a_value" ) . set ( true ) ;
251+ assert_eq ! (
252+ true ,
253+ GLOBAL_METRIC . get( "a_value" ) . test_get_value( "ping" ) . unwrap( )
254+ ) ;
255+ }
256+
257+ #[ test]
258+ fn sets_labeled_bool_metrics ( ) {
259+ let _lock = lock_test ( ) ;
260+ let store_names: Vec < String > = vec ! [ "store1" . into( ) ] ;
261+
262+ let metric: LabeledMetric < BooleanMetric > = LabeledMetric :: new (
263+ 0 . into ( ) ,
264+ CommonMetricData {
265+ name : "bool" . into ( ) ,
266+ category : "labeled" . into ( ) ,
267+ send_in_pings : store_names,
268+ disabled : false ,
269+ ..Default :: default ( )
270+ } ,
271+ None ,
272+ ) ;
273+
274+ metric. get ( "upload" ) . set ( true ) ;
275+
276+ assert ! ( metric. get( "upload" ) . test_get_value( "store1" ) . unwrap( ) ) ;
277+ assert_eq ! ( None , metric. get( "download" ) . test_get_value( "store1" ) ) ;
278+ }
279+
280+ #[ test]
281+ fn sets_labeled_string_metrics ( ) {
282+ let _lock = lock_test ( ) ;
283+ let store_names: Vec < String > = vec ! [ "store1" . into( ) ] ;
284+
285+ let metric: LabeledMetric < StringMetric > = LabeledMetric :: new (
286+ 0 . into ( ) ,
287+ CommonMetricData {
288+ name : "string" . into ( ) ,
289+ category : "labeled" . into ( ) ,
290+ send_in_pings : store_names,
291+ disabled : false ,
292+ ..Default :: default ( )
293+ } ,
294+ None ,
295+ ) ;
296+
297+ metric. get ( "upload" ) . set ( "Glean" ) ;
298+
299+ assert_eq ! (
300+ "Glean" ,
301+ metric. get( "upload" ) . test_get_value( "store1" ) . unwrap( )
302+ ) ;
303+ assert_eq ! ( None , metric. get( "download" ) . test_get_value( "store1" ) ) ;
304+ }
305+
306+ #[ test]
307+ fn sets_labeled_counter_metrics ( ) {
308+ let _lock = lock_test ( ) ;
309+ let store_names: Vec < String > = vec ! [ "store1" . into( ) ] ;
310+
311+ let metric: LabeledMetric < CounterMetric > = LabeledMetric :: new (
312+ 0 . into ( ) ,
313+ CommonMetricData {
314+ name : "counter" . into ( ) ,
315+ category : "labeled" . into ( ) ,
316+ send_in_pings : store_names,
317+ disabled : false ,
318+ ..Default :: default ( )
319+ } ,
320+ None ,
321+ ) ;
322+
323+ metric. get ( "upload" ) . add ( 10 ) ;
324+
325+ assert_eq ! ( 10 , metric. get( "upload" ) . test_get_value( "store1" ) . unwrap( ) ) ;
326+ assert_eq ! ( None , metric. get( "download" ) . test_get_value( "store1" ) ) ;
327+ }
328+
329+ #[ test]
330+ fn records_errors ( ) {
331+ let _lock = lock_test ( ) ;
332+ let store_names: Vec < String > = vec ! [ "store1" . into( ) ] ;
333+
334+ let metric: LabeledMetric < BooleanMetric > = LabeledMetric :: new (
335+ 0 . into ( ) ,
336+ CommonMetricData {
337+ name : "bool" . into ( ) ,
338+ category : "labeled" . into ( ) ,
339+ send_in_pings : store_names,
340+ disabled : false ,
341+ ..Default :: default ( )
342+ } ,
343+ None ,
344+ ) ;
345+
346+ metric
347+ . get ( "this_string_has_more_than_thirty_characters" )
348+ . set ( true ) ;
349+
350+ assert_eq ! (
351+ Ok ( 1 ) ,
352+ metric. test_get_num_recorded_errors( ErrorType :: InvalidLabel , None )
353+ ) ;
354+ }
355+
356+ #[ test]
357+ fn predefined_labels ( ) {
358+ let _lock = lock_test ( ) ;
359+ let store_names: Vec < String > = vec ! [ "store1" . into( ) ] ;
360+
361+ let metric: LabeledMetric < BooleanMetric > = LabeledMetric :: new (
362+ 0 . into ( ) ,
363+ CommonMetricData {
364+ name : "bool" . into ( ) ,
365+ category : "labeled" . into ( ) ,
366+ send_in_pings : store_names,
367+ disabled : false ,
368+ ..Default :: default ( )
369+ } ,
370+ Some ( vec ! [ "label1" . into( ) , "label2" . into( ) ] ) ,
371+ ) ;
372+
373+ metric. get ( "label1" ) . set ( true ) ;
374+ metric. get ( "label2" ) . set ( false ) ;
375+ metric. get ( "not_a_label" ) . set ( true ) ;
376+
377+ assert_eq ! ( true , metric. get( "label1" ) . test_get_value( "store1" ) . unwrap( ) ) ;
378+ assert_eq ! (
379+ false ,
380+ metric. get( "label2" ) . test_get_value( "store1" ) . unwrap( )
381+ ) ;
382+ // The label not in the predefined set is recorded to the `other` bucket.
383+ assert_eq ! (
384+ true ,
385+ metric. get( "__other__" ) . test_get_value( "store1" ) . unwrap( )
386+ ) ;
387+
388+ assert ! ( metric
389+ . test_get_num_recorded_errors( ErrorType :: InvalidLabel , None )
390+ . is_err( ) ) ;
391+ }
392+ }
0 commit comments