MediaWiki master
SamplingStatsdClient.php
Go to the documentation of this file.
1<?php
23namespace Wikimedia\Stats;
24
25use Exception;
26use InvalidArgumentException;
27use Liuggio\StatsdClient\Entity\StatsdData;
28use Liuggio\StatsdClient\Entity\StatsdDataInterface;
29use Liuggio\StatsdClient\StatsdClient;
30use LogicException;
31use Wikimedia\RequestTimeout\TimeoutException;
32
39class SamplingStatsdClient extends StatsdClient {
41 protected $samplingRates = [];
42
50 public function setSamplingRates( array $samplingRates ) {
51 $this->samplingRates = $samplingRates;
52 }
53
60 public function appendSampleRate( $data, $sampleRate = 1 ) {
62 if ( !$samplingRates && $sampleRate !== 1 ) {
63 $samplingRates = [ '*' => $sampleRate ];
64 }
65 if ( $samplingRates ) {
66 array_walk( $data, static function ( $item ) use ( $samplingRates ) {
68 foreach ( $samplingRates as $pattern => $rate ) {
69 if ( fnmatch( $pattern, $item->getKey(), FNM_NOESCAPE ) ) {
70 $item->setSampleRate( $item->getSampleRate() * $rate );
71 break;
72 }
73 }
74 } );
75 }
76
77 return $data;
78 }
79
90 public function send( $data, $sampleRate = 1 ) {
91 if ( !is_array( $data ) ) {
92 $data = [ $data ];
93 }
94 if ( !$data ) {
95 return 0;
96 }
97 foreach ( $data as $item ) {
98 if ( !( $item instanceof StatsdDataInterface ) ) {
99 throw new InvalidArgumentException(
100 'SamplingStatsdClient does not accept stringified messages' );
101 }
102 }
103
104 // add sampling
105 $data = $this->appendSampleRate( $data, $sampleRate );
106 $data = $this->sampleData( $data );
107
108 $data = array_map( 'strval', $data );
109
110 // reduce number of packets
111 if ( $this->getReducePacket() ) {
112 $data = $this->reduceCount( $data );
113 }
114
115 // failures in any of this should be silently ignored if ..
116 $written = 0;
117 try {
118 $fp = $this->getSender()->open();
119 if ( !$fp ) {
120 return 0;
121 }
122 foreach ( $data as $message ) {
123 $written += $this->getSender()->write( $fp, $message );
124 }
125 $this->getSender()->close( $fp );
126 } catch ( TimeoutException $e ) {
127 throw $e;
128 } catch ( Exception $e ) {
129 $this->throwException( $e );
130 }
131
132 return $written;
133 }
134
140 protected function sampleData( $data ) {
141 $newData = [];
142 $mt_rand_max = mt_getrandmax();
143 foreach ( $data as $item ) {
144 $samplingRate = $item->getSampleRate();
145 if ( $samplingRate <= 0.0 || $samplingRate > 1.0 ) {
146 throw new LogicException( 'Sampling rate shall be within ]0, 1]' );
147 }
148 if (
149 $samplingRate === 1 ||
150 ( mt_rand() / $mt_rand_max <= $samplingRate )
151 ) {
152 $newData[] = $item;
153 }
154 }
155 return $newData;
156 }
157
162 private function throwException( Exception $exception ) {
163 if ( !$this->getFailSilently() ) {
164 throw $exception;
165 }
166 }
167}
168
170class_alias( SamplingStatsdClient::class, 'SamplingStatsdClient' );
A statsd client that applies the sampling rate to the data items before sending them.
appendSampleRate( $data, $sampleRate=1)
Sets sampling rate for all items in $data.
sampleData( $data)
Throw away some of the data according to the sample rate.
send( $data, $sampleRate=1)
Send the metrics over UDP Sample the metrics according to their sample rate and send the remaining on...
setSamplingRates(array $samplingRates)
Sampling rates as an associative array of patterns and rates.