MediaWiki master
StatsUtils.php
Go to the documentation of this file.
1<?php
20declare( strict_types=1 );
21
22namespace Wikimedia\Stats;
23
24use InvalidArgumentException;
26
34
35 public const RE_VALID_NAME_AND_LABEL_NAME = "/^[a-zA-Z_][a-zA-Z0-9_]*$/";
36 public const DEFAULT_SAMPLE_RATE = 1.0;
37
44 public static function validateNewSampleRate( float $newSampleRate ): void {
45 if ( $newSampleRate < 0.0 || $newSampleRate > 1.0 ) {
46 throw new InvalidArgumentException( "Sample rate can only be between 0.0 and 1.0. Got: " . $newSampleRate );
47 }
48 }
49
57 public static function getFilteredSamples( float $sampleRate, array $samples ): array {
58 if ( $sampleRate === 1.0 ) {
59 return $samples;
60 }
61 $output = [];
62 $randMax = mt_getrandmax();
63 foreach ( $samples as $sample ) {
64 if ( mt_rand() / $randMax < $sampleRate ) {
65 $output[] = $sample;
66 }
67 }
68 return $output;
69 }
70
79 public static function validateMetricName( string $name ) {
80 if ( $name === "" ) {
81 throw new InvalidArgumentException( "Stats: Metric name cannot be empty." );
82 }
83 if ( !preg_match( self::RE_VALID_NAME_AND_LABEL_NAME, $name ) ) {
84 throw new InvalidConfigurationException( "Invalid metric name: '" . $name . "'" );
85 }
86 }
87
96 public static function validateLabelKey( string $key ) {
97 if ( $key === "" ) {
98 throw new InvalidArgumentException( "Stats: Label key cannot be empty." );
99 }
100 if ( !preg_match( self::RE_VALID_NAME_AND_LABEL_NAME, $key ) ) {
101 throw new InvalidConfigurationException( "Invalid label key: '" . $key . "'" );
102 }
103 }
104
105 public static function validateLabelValue( string $value ) {
106 if ( $value === "" ) {
107 throw new InvalidArgumentException( "Stats: Label value cannot be empty." );
108 }
109 }
110
117 public static function normalizeArray( array $entities ): array {
118 $normalizedEntities = [];
119 foreach ( $entities as $entity ) {
120 $normalizedEntities[] = self::normalizeString( $entity );
121 }
122 return $normalizedEntities;
123 }
124
138 public static function normalizeString( string $entity ): string {
139 $entity = preg_replace( '/[^a-zA-Z0-9]+/', '_', $entity );
140 return trim( $entity, '_' );
141 }
142
147 private const E12 = [
148 1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 10.0
149 ];
150
189 public static function makeBucketsFromMean( float $mean, int $skip ): array {
190 // assert $mean > 0 and $skip > 0
191 if ( $mean <= 0 ) {
192 throw new InvalidArgumentException( 'mean must be positive' );
193 }
194 if ( $skip < 1 ) {
195 throw new InvalidArgumentException( 'skip must be at least 1' );
196 }
197 // Find the appropriate starting location in the E12 series.
198 $pos = (int)round( log10( $mean ) * 12 );
199 // Further quantize $pos according to $skip, so changes in $mean
200 // don't shift all the buckets
201 $pos -= ( $pos % $skip );
202 // Compute buckets around the quantized starting position
203 // By using the E12 series and powers of ten our cutoffs will
204 // be compact (not too many digits) and consistent.
205 return array_map( static function ( $x ) use ( $pos, $skip ) {
206 $y = $pos + ( $x * $skip );
207 $rem = $y % 12;
208 if ( $rem < 0 ) {
209 $rem += 12;
210 }
211 $decade = intdiv( $y - $rem, 12 ); // floor($y/12)
212 // Use an explicit round() here to ensure float math doesn't create
213 // extra tiny variances.
214 return round( ( 10 ** $decade ) * self::E12[$rem], 1 - $decade );
215 }, [
216 // 9 buckets, centered around the (quantized) mean
217 -4, -3, -2, -1, 0, 1, 2, 3, 4
218 ] );
219 }
220}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:82
Functionality common to all metric types.
static normalizeString(string $entity)
Normalize strings to a metrics-compatible format.
static normalizeArray(array $entities)
Normalize an array of strings.
static validateMetricName(string $name)
Determines if provided string is a valid name.
static getFilteredSamples(float $sampleRate, array $samples)
Returns a subset of samples based on configured sample rate.
static validateLabelKey(string $key)
Determines if provided string is a valid label key.
static validateLabelValue(string $value)
static makeBucketsFromMean(float $mean, int $skip)
Make a set of HistogramMetric buckets from a mean and skip value.
static validateNewSampleRate(float $newSampleRate)
Validates the new sample rate.