MediaWiki master
HistogramMetric.php
Go to the documentation of this file.
1<?php
7declare( strict_types=1 );
8
10
11use InvalidArgumentException;
13
23
25 private const MAX_BUCKETS = 10;
26
27 private StatsFactory $statsFactory;
28 private string $name;
29 private array $buckets;
30 private array $labels = [];
31
32 public function __construct( StatsFactory $statsFactory, string $name, array $buckets ) {
33 $this->statsFactory = $statsFactory;
34 $this->name = $name;
35 if ( !$buckets ) {
36 throw new InvalidArgumentException( "Stats: ({$name}) Histogram buckets cannot be an empty array." );
37 }
38 $bucketCount = count( $buckets );
39 if ( $bucketCount > self::MAX_BUCKETS ) {
40 throw new InvalidArgumentException(
41 "Stats: ({$name}) Too many buckets defined. Got:{$bucketCount}, Max:" . self::MAX_BUCKETS
42 );
43 }
44 foreach ( $buckets as $bucket ) {
45 if ( !( is_float( $bucket ) || is_int( $bucket ) ) ) {
46 throw new InvalidArgumentException( "Stats: ({$name}) Histogram buckets can only be float or int." );
47 }
48 }
49 $normalizedBuckets = array_unique( $buckets );
50 sort( $normalizedBuckets, SORT_NUMERIC );
51 if ( $buckets !== $normalizedBuckets ) {
52 throw new InvalidArgumentException(
53 "Stats: ({$name}) Histogram buckets must be unique and in order of least to greatest."
54 );
55 }
56 $this->buckets = $buckets;
57 }
58
63 private function preloadBuckets( CounterMetric $metric ): void {
64 $metric->setBucket( '+Inf' );
65 $metric->incrementBy( 0 );
66 foreach ( $this->buckets as $bucket ) {
67 $metric->setBucket( $bucket );
68 $metric->incrementBy( 0 );
69 }
70 }
71
75 public function observe( float $value ): void {
76 $count = $this->statsFactory->getCounter( "{$this->name}_count" );
77 $bucket = $this->statsFactory->getCounter( "{$this->name}_bucket" );
78 $sum = $this->statsFactory->getCounter( "{$this->name}_sum" );
79
80 foreach ( $this->labels as $k => $v ) {
81 $count->setLabel( $k, $v );
82 $bucket->setLabel( $k, $v );
83 $sum->setLabel( $k, $v );
84 }
85
86 if ( $bucket->getSampleCount() === 0 ) {
87 $this->preloadBuckets( $bucket );
88 }
89
90 $bucket->setBucket( '+Inf' )->increment();
91 foreach ( $this->buckets as $le ) {
92 if ( $value <= $le ) {
93 $bucket->setBucket( $le )->increment();
94 }
95 }
96
97 $count->increment();
98 $sum->incrementBy( $value );
99 }
100
106 public function setLabel( string $key, string $value ): self {
107 // each metric will run its own validation logic
108 $this->labels[$key] = $value;
109 return $this;
110 }
111
117 public function fresh(): self {
118 $this->labels = [];
119 return $this;
120 }
121}
Counter Metric Implementation.
incrementBy(float $value)
Increments metric by provided value.
setBucket( $value)
Sets the bucket value.
Histogram Metric Implementation.
observe(float $value)
Increments bucket associated with the provided value.
setLabel(string $key, string $value)
Adds a label $key with $value.
fresh()
Returns metric with cleared labels.
__construct(StatsFactory $statsFactory, string $name, array $buckets)
This is the primary interface for validating metrics definitions, caching defined metrics,...