MediaWiki master
SamplingStatsdClient.php
Go to the documentation of this file.
1<?php
9namespace Wikimedia\Stats;
10
11use Exception;
12use InvalidArgumentException;
13use Liuggio\StatsdClient\Entity\StatsdData;
14use Liuggio\StatsdClient\Entity\StatsdDataInterface;
15use Liuggio\StatsdClient\StatsdClient;
16use LogicException;
17use Wikimedia\RequestTimeout\TimeoutException;
18
25class SamplingStatsdClient extends StatsdClient {
27 protected $samplingRates = [];
28
36 public function setSamplingRates( array $samplingRates ) {
37 $this->samplingRates = $samplingRates;
38 }
39
46 public function appendSampleRate( $data, $sampleRate = 1 ) {
48 if ( !$samplingRates && $sampleRate !== 1 ) {
49 $samplingRates = [ '*' => $sampleRate ];
50 }
51 if ( $samplingRates ) {
52 array_walk( $data, static function ( $item ) use ( $samplingRates ) {
54 foreach ( $samplingRates as $pattern => $rate ) {
55 if ( fnmatch( $pattern, $item->getKey(), FNM_NOESCAPE ) ) {
56 $item->setSampleRate( $item->getSampleRate() * $rate );
57 break;
58 }
59 }
60 } );
61 }
62
63 return $data;
64 }
65
76 public function send( $data, $sampleRate = 1 ) {
77 if ( !is_array( $data ) ) {
78 $data = [ $data ];
79 }
80 if ( !$data ) {
81 return 0;
82 }
83 foreach ( $data as $item ) {
84 if ( !( $item instanceof StatsdDataInterface ) ) {
85 throw new InvalidArgumentException(
86 'SamplingStatsdClient does not accept stringified messages' );
87 }
88 }
89
90 // add sampling
91 $data = $this->appendSampleRate( $data, $sampleRate );
92 $data = $this->sampleData( $data );
93
94 $data = array_map( 'strval', $data );
95
96 // reduce number of packets
97 if ( $this->getReducePacket() ) {
98 $data = $this->reduceCount( $data );
99 }
100
101 // failures in any of this should be silently ignored if ..
102 $written = 0;
103 try {
104 $fp = $this->getSender()->open();
105 if ( !$fp ) {
106 return 0;
107 }
108 foreach ( $data as $message ) {
109 $written += $this->getSender()->write( $fp, $message );
110 }
111 $this->getSender()->close( $fp );
112 } catch ( TimeoutException $e ) {
113 throw $e;
114 } catch ( Exception $e ) {
115 $this->throwException( $e );
116 }
117
118 return $written;
119 }
120
126 protected function sampleData( $data ) {
127 $newData = [];
128 $mt_rand_max = mt_getrandmax();
129 foreach ( $data as $item ) {
130 $samplingRate = $item->getSampleRate();
131 if ( $samplingRate <= 0.0 || $samplingRate > 1.0 ) {
132 throw new LogicException( 'Sampling rate shall be within ]0, 1]' );
133 }
134 if (
135 $samplingRate === 1 ||
136 ( mt_rand() / $mt_rand_max <= $samplingRate )
137 ) {
138 $newData[] = $item;
139 }
140 }
141 return $newData;
142 }
143
148 private function throwException( Exception $exception ) {
149 if ( !$this->getFailSilently() ) {
150 throw $exception;
151 }
152 }
153}
154
156class_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.