diff options
Diffstat (limited to 'includes/libs/SamplingStatsdClient.php')
-rw-r--r-- | includes/libs/SamplingStatsdClient.php | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/includes/libs/SamplingStatsdClient.php b/includes/libs/SamplingStatsdClient.php new file mode 100644 index 00000000..f7afdb5e --- /dev/null +++ b/includes/libs/SamplingStatsdClient.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright 2015 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +use Liuggio\StatsdClient\StatsdClient; +use Liuggio\StatsdClient\Entity\StatsdData; +use Liuggio\StatsdClient\Entity\StatsdDataInterface; + +/** + * A statsd client that applies the sampling rate to the data items before sending them. + * + * @since 1.26 + */ +class SamplingStatsdClient extends StatsdClient { + /** + * Sets sampling rate for all items in $data. + * The sample rate specified in a StatsdData entity overrides the sample rate specified here. + * + * {@inheritDoc} + */ + public function appendSampleRate( $data, $sampleRate = 1 ) { + if ( $sampleRate < 1 ) { + array_walk( $data, function( $item ) use ( $sampleRate ) { + /** @var $item StatsdData */ + if ( $item->getSampleRate() === 1 ) { + $item->setSampleRate( $sampleRate ); + } + } ); + } + + return $data; + } + + /** + * Sample the metrics according to their sample rate and send the remaining ones. + * + * {@inheritDoc} + */ + public function send( $data, $sampleRate = 1 ) { + if ( !is_array( $data ) ) { + $data = array( $data ); + } + if ( !$data ) { + return; + } + foreach ( $data as $item ) { + if ( !( $item instanceof StatsdDataInterface ) ) { + throw new InvalidArgumentException( + 'SamplingStatsdClient does not accept stringified messages' ); + } + } + + // add sampling + if ( $sampleRate < 1 ) { + $data = $this->appendSampleRate( $data, $sampleRate ); + } + $data = $this->sampleData( $data ); + + $messages = array_map( 'strval', $data ); + + // reduce number of packets + if ( $this->getReducePacket() ) { + $data = $this->reduceCount( $data ); + } + //failures in any of this should be silently ignored if .. + $written = 0; + try { + $fp = $this->getSender()->open(); + if ( !$fp ) { + return; + } + foreach ( $messages as $message ) { + $written += $this->getSender()->write( $fp, $message ); + } + $this->getSender()->close( $fp ); + } catch ( Exception $e ) { + $this->throwException( $e ); + } + + return $written; + } + + /** + * Throw away some of the data according to the sample rate. + * @param StatsdDataInterface[] $data + * @return array + * @throws LogicException + */ + protected function sampleData( $data ) { + $newData = array(); + $mt_rand_max = mt_getrandmax(); + foreach ( $data as $item ) { + $samplingRate = $item->getSampleRate(); + if ( $samplingRate <= 0.0 || $samplingRate > 1.0 ) { + throw new LogicException( 'Sampling rate shall be within ]0, 1]' ); + } + if ( + $samplingRate === 1 || + ( mt_rand() / $mt_rand_max <= $samplingRate ) + ) { + $newData[] = $item; + } + } + return $newData; + } + + /** + * {@inheritDoc} + */ + protected function throwException( Exception $exception ) { + if ( !$this->getFailSilently() ) { + throw $exception; + } + } +} |