Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
80.77% |
21 / 26 |
|
42.86% |
3 / 7 |
CRAP | |
0.00% |
0 / 1 |
StatsUtils | |
80.77% |
21 / 26 |
|
42.86% |
3 / 7 |
20.30 | |
0.00% |
0 / 1 |
validateNewSampleRate | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
getFilteredSamples | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
4.03 | |||
validateMetricName | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
3.14 | |||
validateLabelKey | |
50.00% |
2 / 4 |
|
0.00% |
0 / 1 |
4.12 | |||
validateLabelValue | |
50.00% |
1 / 2 |
|
0.00% |
0 / 1 |
2.50 | |||
normalizeArray | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
normalizeString | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * @file |
18 | */ |
19 | |
20 | declare( strict_types=1 ); |
21 | |
22 | namespace Wikimedia\Stats; |
23 | |
24 | use InvalidArgumentException; |
25 | use Wikimedia\Stats\Exceptions\InvalidConfigurationException; |
26 | |
27 | /** |
28 | * Functionality common to all metric types. |
29 | * |
30 | * @author Cole White |
31 | * @since 1.38 |
32 | */ |
33 | class StatsUtils { |
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 | |
38 | /** |
39 | * Validates the new sample rate. Throws InvalidArgumentException if provided an invalid rate. |
40 | * |
41 | * @param float $newSampleRate |
42 | * @throws InvalidArgumentException |
43 | */ |
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 | |
50 | /** |
51 | * Returns a subset of samples based on configured sample rate. |
52 | * |
53 | * @param float $sampleRate |
54 | * @param array $samples |
55 | * @return array |
56 | */ |
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 | |
71 | /** |
72 | * Determines if provided string is a valid name. |
73 | * |
74 | * @param string $name |
75 | * @return void |
76 | * @throws InvalidArgumentException |
77 | * @throws InvalidConfigurationException |
78 | */ |
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 | |
88 | /** |
89 | * Determines if provided string is a valid label key. |
90 | * |
91 | * @param string $key |
92 | * @return void |
93 | * @throws InvalidArgumentException |
94 | * @throws InvalidConfigurationException |
95 | */ |
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 | |
111 | /** |
112 | * Normalize an array of strings. |
113 | * |
114 | * @param string[] $entities |
115 | * @return string[] |
116 | */ |
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 | |
125 | /** |
126 | * Normalize strings to a metrics-compatible format. |
127 | * |
128 | * Replace all other non-alphanumeric characters with an underscore. |
129 | * Trim leading or trailing underscores. |
130 | * |
131 | * @param string $entity |
132 | * @return string |
133 | */ |
134 | public static function normalizeString( string $entity ): string { |
135 | $entity = preg_replace( '/[^a-z\d]+/i', '_', $entity ); |
136 | return trim( $entity, "_" ); |
137 | } |
138 | } |