@@ -377,6 +377,7 @@ class _ExplicitBucketHistogramAggregation(_Aggregation[HistogramPoint]):
377
377
def __init__ (
378
378
self ,
379
379
attributes : Attributes ,
380
+ instrument_aggregation_temporality : AggregationTemporality ,
380
381
start_time_unix_nano : int ,
381
382
boundaries : Sequence [float ] = (
382
383
0.0 ,
@@ -398,33 +399,40 @@ def __init__(
398
399
record_min_max : bool = True ,
399
400
):
400
401
super ().__init__ (attributes )
402
+
401
403
self ._boundaries = tuple (boundaries )
402
- self ._bucket_counts = self . _get_empty_bucket_counts ()
404
+ self ._record_min_max = record_min_max
403
405
self ._min = inf
404
406
self ._max = - inf
405
407
self ._sum = 0
406
- self . _record_min_max = record_min_max
408
+
407
409
self ._start_time_unix_nano = start_time_unix_nano
408
- # It is assumed that the "natural" aggregation temporality for a
409
- # Histogram instrument is DELTA, like the "natural" aggregation
410
- # temporality for a Counter is DELTA and the "natural" aggregation
411
- # temporality for an ObservableCounter is CUMULATIVE.
412
- self ._instrument_aggregation_temporality = AggregationTemporality .DELTA
410
+ self ._instrument_aggregation_temporality = (
411
+ instrument_aggregation_temporality
412
+ )
413
+
414
+ self ._current_value = None
415
+
416
+ self ._previous_collection_start_nano = self ._start_time_unix_nano
417
+ self ._previous_cumulative_value = self ._get_empty_bucket_counts ()
413
418
414
419
def _get_empty_bucket_counts (self ) -> List [int ]:
415
420
return [0 ] * (len (self ._boundaries ) + 1 )
416
421
417
422
def aggregate (self , measurement : Measurement ) -> None :
423
+ with self ._lock :
424
+ if self ._current_value is None :
425
+ self ._current_value = self ._get_empty_bucket_counts ()
418
426
419
- value = measurement .value
427
+ value = measurement .value
420
428
421
- if self ._record_min_max :
422
- self ._min = min (self ._min , value )
423
- self ._max = max (self ._max , value )
429
+ self ._sum += value
424
430
425
- self ._sum += value
431
+ if self ._record_min_max :
432
+ self ._min = min (self ._min , value )
433
+ self ._max = max (self ._max , value )
426
434
427
- self ._bucket_counts [bisect_left (self ._boundaries , value )] += 1
435
+ self ._current_value [bisect_left (self ._boundaries , value )] += 1
428
436
429
437
def collect (
430
438
self ,
@@ -434,84 +442,125 @@ def collect(
434
442
"""
435
443
Atomically return a point for the current value of the metric.
436
444
"""
437
- with self ._lock :
438
- if not any (self ._bucket_counts ):
439
- return None
440
445
441
- bucket_counts = self ._bucket_counts
442
- start_time_unix_nano = self ._start_time_unix_nano
446
+ with self ._lock :
447
+ current_value = self ._current_value
443
448
sum_ = self ._sum
444
- max_ = self ._max
445
449
min_ = self ._min
450
+ max_ = self ._max
446
451
447
- self ._bucket_counts = self ._get_empty_bucket_counts ()
448
- self ._start_time_unix_nano = collection_start_nano
452
+ self ._current_value = None
449
453
self ._sum = 0
450
454
self ._min = inf
451
455
self ._max = - inf
452
456
453
- current_point = HistogramDataPoint (
454
- attributes = self ._attributes ,
455
- start_time_unix_nano = start_time_unix_nano ,
456
- time_unix_nano = collection_start_nano ,
457
- count = sum (bucket_counts ),
458
- sum = sum_ ,
459
- bucket_counts = tuple (bucket_counts ),
460
- explicit_bounds = self ._boundaries ,
461
- min = min_ ,
462
- max = max_ ,
463
- )
457
+ if (
458
+ self ._instrument_aggregation_temporality
459
+ is AggregationTemporality .DELTA
460
+ ):
461
+ # This happens when the corresponding instrument for this
462
+ # aggregation is synchronous.
463
+ if (
464
+ collection_aggregation_temporality
465
+ is AggregationTemporality .DELTA
466
+ ):
464
467
465
- if self ._previous_point is None or (
466
- self ._instrument_aggregation_temporality
467
- is collection_aggregation_temporality
468
- ):
469
- self ._previous_point = current_point
470
- return current_point
468
+ if current_value is None :
469
+ return None
471
470
472
- max_ = current_point .max
473
- min_ = current_point .min
471
+ previous_collection_start_nano = (
472
+ self ._previous_collection_start_nano
473
+ )
474
+ self ._previous_collection_start_nano = (
475
+ collection_start_nano
476
+ )
474
477
475
- if (
476
- collection_aggregation_temporality
477
- is AggregationTemporality .CUMULATIVE
478
- ):
479
- start_time_unix_nano = self ._previous_point .start_time_unix_nano
480
- sum_ = current_point .sum + self ._previous_point .sum
481
- # Only update min/max on delta -> cumulative
482
- max_ = max (current_point .max , self ._previous_point .max )
483
- min_ = min (current_point .min , self ._previous_point .min )
484
- bucket_counts = [
485
- curr_count + prev_count
486
- for curr_count , prev_count in zip (
487
- current_point .bucket_counts ,
488
- self ._previous_point .bucket_counts ,
478
+ return HistogramDataPoint (
479
+ attributes = self ._attributes ,
480
+ start_time_unix_nano = previous_collection_start_nano ,
481
+ time_unix_nano = collection_start_nano ,
482
+ count = sum (current_value ),
483
+ sum = sum_ ,
484
+ bucket_counts = tuple (current_value ),
485
+ explicit_bounds = self ._boundaries ,
486
+ min = min_ ,
487
+ max = max_ ,
488
+ )
489
+
490
+ if current_value is None :
491
+ current_value = self ._get_empty_bucket_counts ()
492
+
493
+ self ._previous_cumulative_value = [
494
+ current_value_element + previous_cumulative_value_element
495
+ for (
496
+ current_value_element ,
497
+ previous_cumulative_value_element ,
498
+ ) in zip (current_value , self ._previous_cumulative_value )
499
+ ]
500
+
501
+ return HistogramDataPoint (
502
+ attributes = self ._attributes ,
503
+ start_time_unix_nano = self ._start_time_unix_nano ,
504
+ time_unix_nano = collection_start_nano ,
505
+ count = sum (current_value ),
506
+ sum = sum_ ,
507
+ bucket_counts = tuple (current_value ),
508
+ explicit_bounds = self ._boundaries ,
509
+ min = min_ ,
510
+ max = max_ ,
489
511
)
490
- ]
491
- else :
492
- start_time_unix_nano = self ._previous_point .time_unix_nano
493
- sum_ = current_point .sum - self ._previous_point .sum
494
- bucket_counts = [
495
- curr_count - prev_count
496
- for curr_count , prev_count in zip (
497
- current_point .bucket_counts ,
498
- self ._previous_point .bucket_counts ,
512
+
513
+ # This happens when the corresponding instrument for this
514
+ # aggregation is asynchronous.
515
+
516
+ if current_value is None :
517
+ # This happens when the corresponding instrument callback
518
+ # does not produce measurements.
519
+ return None
520
+
521
+ if (
522
+ collection_aggregation_temporality
523
+ is AggregationTemporality .DELTA
524
+ ):
525
+
526
+ result_value = [
527
+ current_value_element - previous_cumulative_value_element
528
+ for (
529
+ current_value_element ,
530
+ previous_cumulative_value_element ,
531
+ ) in zip (current_value , self ._previous_cumulative_value )
532
+ ]
533
+
534
+ self ._previous_cumulative_value = current_value
535
+
536
+ previous_collection_start_nano = (
537
+ self ._previous_collection_start_nano
499
538
)
500
- ]
539
+ self . _previous_collection_start_nano = collection_start_nano
501
540
502
- current_point = HistogramDataPoint (
503
- attributes = self ._attributes ,
504
- start_time_unix_nano = start_time_unix_nano ,
505
- time_unix_nano = current_point .time_unix_nano ,
506
- count = sum (bucket_counts ),
507
- sum = sum_ ,
508
- bucket_counts = tuple (bucket_counts ),
509
- explicit_bounds = current_point .explicit_bounds ,
510
- min = min_ ,
511
- max = max_ ,
512
- )
513
- self ._previous_point = current_point
514
- return current_point
541
+ return HistogramDataPoint (
542
+ attributes = self ._attributes ,
543
+ start_time_unix_nano = previous_collection_start_nano ,
544
+ time_unix_nano = collection_start_nano ,
545
+ count = sum (result_value ),
546
+ sum = sum_ ,
547
+ bucket_counts = tuple (result_value ),
548
+ explicit_bounds = self ._boundaries ,
549
+ min = min_ ,
550
+ max = max_ ,
551
+ )
552
+
553
+ return HistogramDataPoint (
554
+ attributes = self ._attributes ,
555
+ start_time_unix_nano = self ._start_time_unix_nano ,
556
+ time_unix_nano = collection_start_nano ,
557
+ count = sum (current_value ),
558
+ sum = sum_ ,
559
+ bucket_counts = tuple (current_value ),
560
+ explicit_bounds = self ._boundaries ,
561
+ min = min_ ,
562
+ max = max_ ,
563
+ )
515
564
516
565
517
566
# pylint: disable=protected-access
@@ -1100,7 +1149,11 @@ def _create_aggregation(
1100
1149
1101
1150
if isinstance (instrument , Histogram ):
1102
1151
return _ExplicitBucketHistogramAggregation (
1103
- attributes , start_time_unix_nano
1152
+ attributes ,
1153
+ instrument_aggregation_temporality = (
1154
+ AggregationTemporality .CUMULATIVE
1155
+ ),
1156
+ start_time_unix_nano = start_time_unix_nano ,
1104
1157
)
1105
1158
1106
1159
if isinstance (instrument , ObservableGauge ):
@@ -1179,8 +1232,18 @@ def _create_aggregation(
1179
1232
attributes : Attributes ,
1180
1233
start_time_unix_nano : int ,
1181
1234
) -> _Aggregation :
1235
+
1236
+ instrument_aggregation_temporality = AggregationTemporality .UNSPECIFIED
1237
+ if isinstance (instrument , Synchronous ):
1238
+ instrument_aggregation_temporality = AggregationTemporality .DELTA
1239
+ elif isinstance (instrument , Asynchronous ):
1240
+ instrument_aggregation_temporality = (
1241
+ AggregationTemporality .CUMULATIVE
1242
+ )
1243
+
1182
1244
return _ExplicitBucketHistogramAggregation (
1183
1245
attributes ,
1246
+ instrument_aggregation_temporality ,
1184
1247
start_time_unix_nano ,
1185
1248
self ._boundaries ,
1186
1249
self ._record_min_max ,
@@ -1200,16 +1263,18 @@ def _create_aggregation(
1200
1263
start_time_unix_nano : int ,
1201
1264
) -> _Aggregation :
1202
1265
1203
- temporality = AggregationTemporality .UNSPECIFIED
1266
+ instrument_aggregation_temporality = AggregationTemporality .UNSPECIFIED
1204
1267
if isinstance (instrument , Synchronous ):
1205
- temporality = AggregationTemporality .DELTA
1268
+ instrument_aggregation_temporality = AggregationTemporality .DELTA
1206
1269
elif isinstance (instrument , Asynchronous ):
1207
- temporality = AggregationTemporality .CUMULATIVE
1270
+ instrument_aggregation_temporality = (
1271
+ AggregationTemporality .CUMULATIVE
1272
+ )
1208
1273
1209
1274
return _SumAggregation (
1210
1275
attributes ,
1211
1276
isinstance (instrument , (Counter , ObservableCounter )),
1212
- temporality ,
1277
+ instrument_aggregation_temporality ,
1213
1278
start_time_unix_nano ,
1214
1279
)
1215
1280
0 commit comments