MediaWiki  master
MetricUtils.php
Go to the documentation of this file.
1 <?php
30 declare( strict_types=1 );
31 
32 namespace Wikimedia\Metrics;
33 
36 
37 class MetricUtils {
38 
40  private const RE_VALID_NAME_AND_LABEL_NAME = '/^[a-zA-Z_][a-zA-Z0-9_]*$/';
41 
43  protected $prefix;
44 
46  protected $extension;
47 
49  protected $format;
50 
52  protected $name;
53 
55  protected $sampleRate;
56 
58  protected $labels;
59 
61  protected $samples = [];
62 
64  protected $typeIndicator;
65 
75  public function validateConfig( $config ) {
76  $this->prefix = $config['prefix'];
77  $this->extension = $config['extension'];
78  $this->name = $config['name'];
79  $this->sampleRate = $config['sampleRate'];
80  $this->format = $config['format'];
81  if ( !preg_match( self::RE_VALID_NAME_AND_LABEL_NAME, $this->name ) ) {
82  throw new InvalidConfigurationException( "Invalid metric name: '" . $this->name . "'" );
83  }
84  $this->labels = $config['labels'];
85  foreach ( $this->labels as $label ) {
86  if ( !preg_match( self::RE_VALID_NAME_AND_LABEL_NAME, $label ) ) {
87  throw new InvalidConfigurationException( "Invalid label name: '" . $label . "'" );
88  }
89  }
90  }
91 
96  public function setTypeIndicator( string $typeIndicator ) {
97  $this->typeIndicator = $typeIndicator;
98  }
99 
104  public function addSample( Sample $sample ) {
105  $this->samples[] = $sample;
106  }
107 
111  public function render(): array {
112  $output = [];
113  switch ( $this->format ) {
114  case 'dogstatsd':
115  foreach ( $this->getFilteredSamples() as $sample ) {
116  $output[] = $this->renderDogStatsD( $sample );
117  }
118  break;
119  case 'statsd':
120  foreach ( $this->getFilteredSamples() as $sample ) {
121  $output[] = $this->renderStatsD( $sample );
122  }
123  break;
124  default: // "null"
125  break;
126  }
127  return $output;
128  }
129 
134  public function validateLabels( array $labels ): void {
135  if ( count( $this->labels ) !== count( $labels ) ) {
136  throw new InvalidLabelsException(
137  'Not enough or too many labels provided to metric instance.'
138  . 'Configured: ' . json_encode( $this->labels ) . ' Provided: ' . json_encode( $labels )
139  );
140  }
141  }
142 
147  private function getFilteredSamples() {
148  if ( $this->sampleRate === 1.0 ) {
149  return $this->samples;
150  }
151  $output = [];
152  $randMax = mt_getrandmax();
153  foreach ( $this->samples as $sample ) {
154  if ( mt_rand() / $randMax < $this->sampleRate ) {
155  $output[] = $sample;
156  }
157  }
158  return $output;
159  }
160 
166  private function renderStatsD( Sample $sample ): string {
167  $stat = implode( '.',
168  array_merge( [ $this->prefix, $this->extension, $this->name ], $sample->getLabels() )
169  );
170  $value = ':' . $sample->getValue();
171  $type = '|' . $this->typeIndicator;
172  $sampleRate = $this->sampleRate !== 1.0 ? '|@' . $this->sampleRate : '';
173 
174  return $stat . $value . $type . $sampleRate;
175  }
176 
184  private function renderDogStatsD( Sample $sample ): string {
185  $stat = implode( '.', [ $this->prefix, $this->extension, $this->name ] );
186  $sampleLabels = $sample->getLabels();
187  $labels = [];
188  foreach ( $this->labels as $i => $label ) {
189  $labels[] = $label . ':' . $sampleLabels[$i];
190  }
191  $value = ':' . $sample->getValue();
192  $type = '|' . $this->typeIndicator;
193  $sampleRate = $this->sampleRate !== 1.0 ? '|@' . $this->sampleRate : '';
194  $tags = $labels === [] ? '' : '|#' . implode( ',', $labels );
195  return $stat . $value . $type . $sampleRate . $tags;
196  }
197 
198 }
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
setTypeIndicator(string $typeIndicator)
Sets the StatsD protocol type indicator.
Definition: MetricUtils.php:96
renderStatsD(Sample $sample)
Renders metrics in StatsD format.
getFilteredSamples()
Get set of samples filtered according to configured sampleRate.
addSample(Sample $sample)
Adds a sample to cache.
renderDogStatsD(Sample $sample)
Renders metrics in DogStatsD format https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?...