@@ -129,6 +129,7 @@ impl MetricStats {
129
129
130
130
let mut tags = BTreeMap :: from ( [
131
131
( "mri" . to_owned ( ) , bucket. name . to_string ( ) ) ,
132
+ ( "mri.type" . to_owned ( ) , bucket. value . ty ( ) . to_string ( ) ) ,
132
133
( "mri.namespace" . to_owned ( ) , namespace. to_string ( ) ) ,
133
134
(
134
135
"outcome.id" . to_owned ( ) ,
@@ -160,22 +161,30 @@ impl MetricStats {
160
161
return None ;
161
162
}
162
163
163
- let name = report. metric_name . as_ref ( ) ?;
164
- let namespace = name. namespace ( ) ;
165
-
166
- if !namespace. has_metric_stats ( ) {
167
- return None ;
168
- }
169
-
170
- let tags = BTreeMap :: from ( [
171
- ( "mri" . to_owned ( ) , name. to_string ( ) ) ,
172
- ( "mri.namespace" . to_owned ( ) , namespace. to_string ( ) ) ,
164
+ let mut tags = BTreeMap :: from ( [
165
+ ( "cardinality.limit" . to_owned ( ) , limit. id . clone ( ) ) ,
166
+ (
167
+ "cardinality.scope" . to_owned ( ) ,
168
+ limit. scope . as_str ( ) . to_owned ( ) ,
169
+ ) ,
173
170
(
174
171
"cardinality.window" . to_owned ( ) ,
175
172
limit. window . window_seconds . to_string ( ) ,
176
173
) ,
177
174
] ) ;
178
175
176
+ if let Some ( ref name) = report. metric_name {
177
+ tags. insert ( "mri" . to_owned ( ) , name. to_string ( ) ) ;
178
+ tags. insert ( "mri.namespace" . to_owned ( ) , name. namespace ( ) . to_string ( ) ) ;
179
+ if let Some ( t) = name. try_type ( ) {
180
+ tags. insert ( "mri.type" . to_owned ( ) , t. to_string ( ) ) ;
181
+ }
182
+ }
183
+
184
+ if let Some ( t) = report. metric_type {
185
+ tags. insert ( "mri.type" . to_owned ( ) , t. to_string ( ) ) ;
186
+ }
187
+
179
188
Some ( Bucket {
180
189
timestamp : UnixTimestamp :: now ( ) ,
181
190
width : 0 ,
@@ -190,7 +199,9 @@ impl MetricStats {
190
199
#[ cfg( test) ]
191
200
mod tests {
192
201
use relay_base_schema:: project:: { ProjectId , ProjectKey } ;
202
+ use relay_cardinality:: { CardinalityScope , SlidingWindow } ;
193
203
use relay_dynamic_config:: GlobalConfig ;
204
+ use relay_metrics:: MetricType ;
194
205
use relay_quotas:: ReasonCode ;
195
206
use tokio:: sync:: mpsc:: UnboundedReceiver ;
196
207
@@ -265,6 +276,7 @@ mod tests {
265
276
bucket. tags,
266
277
tags!(
267
278
( "mri" , "d:custom/rt@millisecond" ) ,
279
+ ( "mri.type" , "d" ) ,
268
280
( "mri.namespace" , "custom" ) ,
269
281
( "outcome.id" , "0" ) ,
270
282
)
@@ -285,6 +297,7 @@ mod tests {
285
297
bucket. tags,
286
298
tags!(
287
299
( "mri" , "d:custom/rt@millisecond" ) ,
300
+ ( "mri.type" , "d" ) ,
288
301
( "mri.namespace" , "custom" ) ,
289
302
( "outcome.id" , "2" ) ,
290
303
( "outcome.reason" , "foobar" ) ,
@@ -294,6 +307,132 @@ mod tests {
294
307
assert ! ( receiver. blocking_recv( ) . is_none( ) ) ;
295
308
}
296
309
310
+ #[ test]
311
+ fn test_metric_stats_cardinality_name ( ) {
312
+ let ( ms, mut receiver) = create_metric_stats ( 1.0 ) ;
313
+
314
+ let scoping = scoping ( ) ;
315
+ let limit = CardinalityLimit {
316
+ id : "test" . to_owned ( ) ,
317
+ passive : false ,
318
+ report : true ,
319
+ window : SlidingWindow {
320
+ window_seconds : 246 ,
321
+ granularity_seconds : 123 ,
322
+ } ,
323
+ limit : 99 ,
324
+ scope : CardinalityScope :: Name ,
325
+ namespace : None ,
326
+ } ;
327
+ let report = CardinalityReport {
328
+ organization_id : Some ( scoping. organization_id ) ,
329
+ project_id : Some ( scoping. project_id ) ,
330
+ metric_type : None ,
331
+ metric_name : Some ( MetricName :: from ( "d:custom/rt@millisecond" ) ) ,
332
+ cardinality : 12 ,
333
+ } ;
334
+
335
+ ms. track_cardinality ( scoping, & limit, & report) ;
336
+
337
+ drop ( ms) ;
338
+
339
+ let Aggregator :: MergeBuckets ( mb) = receiver. blocking_recv ( ) . unwrap ( ) else {
340
+ panic ! ( ) ;
341
+ } ;
342
+ assert_eq ! ( mb. project_key( ) , scoping. project_key) ;
343
+
344
+ let mut buckets = mb. buckets ( ) ;
345
+ assert_eq ! ( buckets. len( ) , 1 ) ;
346
+ let bucket = buckets. pop ( ) . unwrap ( ) ;
347
+
348
+ assert_eq ! ( & * bucket. name, "g:metric_stats/cardinality@none" ) ;
349
+ assert_eq ! (
350
+ bucket. value,
351
+ BucketValue :: Gauge ( GaugeValue {
352
+ last: 12 . into( ) ,
353
+ min: 12 . into( ) ,
354
+ max: 12 . into( ) ,
355
+ sum: 12 . into( ) ,
356
+ count: 1 ,
357
+ } )
358
+ ) ;
359
+ assert_eq ! (
360
+ bucket. tags,
361
+ tags!(
362
+ ( "mri" , "d:custom/rt@millisecond" ) ,
363
+ ( "mri.type" , "d" ) ,
364
+ ( "mri.namespace" , "custom" ) ,
365
+ ( "cardinality.limit" , "test" ) ,
366
+ ( "cardinality.scope" , "name" ) ,
367
+ ( "cardinality.window" , "246" ) ,
368
+ )
369
+ ) ;
370
+
371
+ assert ! ( receiver. blocking_recv( ) . is_none( ) ) ;
372
+ }
373
+
374
+ #[ test]
375
+ fn test_metric_stats_cardinality_type ( ) {
376
+ let ( ms, mut receiver) = create_metric_stats ( 1.0 ) ;
377
+
378
+ let scoping = scoping ( ) ;
379
+ let limit = CardinalityLimit {
380
+ id : "test" . to_owned ( ) ,
381
+ passive : false ,
382
+ report : true ,
383
+ window : SlidingWindow {
384
+ window_seconds : 246 ,
385
+ granularity_seconds : 123 ,
386
+ } ,
387
+ limit : 99 ,
388
+ scope : CardinalityScope :: Type ,
389
+ namespace : None ,
390
+ } ;
391
+ let report = CardinalityReport {
392
+ organization_id : Some ( scoping. organization_id ) ,
393
+ project_id : Some ( scoping. project_id ) ,
394
+ metric_type : Some ( MetricType :: Distribution ) ,
395
+ metric_name : None ,
396
+ cardinality : 12 ,
397
+ } ;
398
+
399
+ ms. track_cardinality ( scoping, & limit, & report) ;
400
+
401
+ drop ( ms) ;
402
+
403
+ let Aggregator :: MergeBuckets ( mb) = receiver. blocking_recv ( ) . unwrap ( ) else {
404
+ panic ! ( ) ;
405
+ } ;
406
+ assert_eq ! ( mb. project_key( ) , scoping. project_key) ;
407
+
408
+ let mut buckets = mb. buckets ( ) ;
409
+ assert_eq ! ( buckets. len( ) , 1 ) ;
410
+ let bucket = buckets. pop ( ) . unwrap ( ) ;
411
+
412
+ assert_eq ! ( & * bucket. name, "g:metric_stats/cardinality@none" ) ;
413
+ assert_eq ! (
414
+ bucket. value,
415
+ BucketValue :: Gauge ( GaugeValue {
416
+ last: 12 . into( ) ,
417
+ min: 12 . into( ) ,
418
+ max: 12 . into( ) ,
419
+ sum: 12 . into( ) ,
420
+ count: 1 ,
421
+ } )
422
+ ) ;
423
+ assert_eq ! (
424
+ bucket. tags,
425
+ tags!(
426
+ ( "mri.type" , "d" ) ,
427
+ ( "cardinality.limit" , "test" ) ,
428
+ ( "cardinality.scope" , "type" ) ,
429
+ ( "cardinality.window" , "246" ) ,
430
+ )
431
+ ) ;
432
+
433
+ assert ! ( receiver. blocking_recv( ) . is_none( ) ) ;
434
+ }
435
+
297
436
#[ test]
298
437
fn test_metric_stats_rollout_rate_disabled ( ) {
299
438
let ( ms, mut receiver) = create_metric_stats ( 0.0 ) ;
0 commit comments