├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── config └── statsd.php ├── docs └── Getting Started.md └── src ├── Client.php ├── Exception ├── ConfigurationException.php ├── ConnectionException.php └── Exception.php ├── Laravel ├── Facade │ └── StatsdFacade.php └── Provider │ └── StatsdServiceProvider.php ├── Laravel5 ├── Facade │ └── StatsdFacade.php └── Provider │ └── StatsdServiceProvider.php └── StatsDClient.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; top-most EditorConfig file 2 | root = true 3 | 4 | # All files. 5 | [*] 6 | end_of_line = LF 7 | indent_style = space 8 | indent_size = 4 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: ~ 5 | pull_request: ~ 6 | 7 | jobs: 8 | phpcs: 9 | name: PHPCS 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - uses: shivammathur/setup-php@v2 16 | with: 17 | php-version: 7.4 18 | coverage: none 19 | tools: composer:v2, cs2pr 20 | 21 | - run: composer update --no-progress 22 | 23 | - run: vendor/bin/phpcs -q --report=checkstyle | cs2pr 24 | 25 | phpunit: 26 | name: PHPUnit on ${{ matrix.php }} 27 | runs-on: ubuntu-latest 28 | continue-on-error: ${{ !matrix.stable }} 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | php: ['7.4', '8.0', '8.1'] 33 | stable: [true] 34 | 35 | steps: 36 | - uses: actions/checkout@v2 37 | with: 38 | fetch-depth: 0 39 | 40 | - uses: shivammathur/setup-php@v2 41 | with: 42 | php-version: ${{ matrix.php }} 43 | coverage: pcov 44 | tools: composer:v2 45 | 46 | - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 47 | 48 | - run: composer update --no-progress 49 | 50 | - run: vendor/bin/phpunit --coverage-text 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) principles. 4 | 5 | ## [Unreleased][unreleased] 6 | 7 | ## [2.0.0] - 2022-01-14 8 | ### Added 9 | - Added new `StatsDClient` interface, which `Client` now implements 10 | - Added new `Exception` interface, which all exceptions now implement 11 | 12 | ### Changed 13 | - Supported PHP versions are now 7.4, 8.0, and 8.1 14 | - All properties and methods now have type hints where applicable 15 | - `gauge()` now accepts both `int` and `float` values (#56) 16 | - `ConnectionException` message is now also propagated via `trigger_error()` (#57) 17 | - The following methods return the `StatsDClient` interface instead of `Client`: 18 | - `ConfigurationException::getInstance()` 19 | - `ConnectionException::getInstance()` 20 | - The following `Client` methods now return `void` instead of returning `$this`: 21 | - `increment()` 22 | - `decrement()` 23 | - `startTiming()` 24 | - `endTiming()` 25 | - `timing()` 26 | - `timings()` 27 | - `time()` 28 | - `gauge()` 29 | - `set()` 30 | - `send()` 31 | - Renamed `Client::$instance_id` to `Client::$instanceId` 32 | 33 | ## [1.5.0] - 2018-10-09 34 | ### Added 35 | - Added tags supporting Datadog format (#52) 36 | 37 | ## [1.4.3] - 2017-07-17 38 | ### Added 39 | - Added Silex 2 support (#43) 40 | 41 | ### Changed 42 | - Dropped support for PHP <5.6 43 | - Test against PHP 7.1 44 | 45 | ## [1.4.2] - 2017-02-09 46 | ### Changed 47 | - Use `config` to allow publishing differently to views or assets within Laravel 48 | 49 | ## [1.4.1] - 2017-02-02 50 | ### Added 51 | - Added Laravel 5.4 support 52 | 53 | ## [1.4.0] - 2016-04-21 54 | ### Added 55 | - Custom timeout configurations 56 | - Exception handling is now configurable 57 | - Built-in Laravel 5 support 58 | 59 | ### Fixed 60 | - DNS lookup failures no longer raise exceptions 61 | 62 | ## [1.3.0] - 2015-06-11 63 | ### Changed 64 | - Throwing an exception is now optional during connections to server and can be silently ignored 65 | 66 | ## [1.2.0] - 2015-05-15 67 | ### Added 68 | - Configurable timeouts 69 | - SET method: Count the number of unique values passed to a key 70 | - PHP 5.6 testing on Travis 71 | - Various test patches and improvements 72 | 73 | ## [1.1.0] - 2014-02-01 74 | ### Added 75 | - PSR-4 support 76 | - New documentation 77 | 78 | ## [1.0.0] - 2013-08-27 79 | 80 | This is the first fully stable version of StatsD library. This version has the following features: 81 | 82 | - Counters 83 | - Gauges 84 | - Timers 85 | - Timing Blocks 86 | - 100% Code Coverage 87 | - Silex Service Provider 88 | 89 | [unreleased]: https://github.com/thephpleague/statsd/compare/2.0.0...master 90 | [2.0.0]: https://github.com/thephpleague/statsd/compare/1.5.0...2.0.0 91 | [1.5.0]: https://github.com/thephpleague/statsd/compare/1.4.5...1.5.0 92 | [1.4.5]: https://github.com/thephpleague/statsd/compare/1.4.4...1.4.5 93 | [1.4.4]: https://github.com/thephpleague/statsd/compare/1.4.3...1.4.4 94 | [1.4.3]: https://github.com/thephpleague/statsd/compare/1.4.2...1.4.3 95 | [1.4.2]: https://github.com/thephpleague/statsd/compare/1.4.1...1.4.2 96 | [1.4.1]: https://github.com/thephpleague/statsd/compare/1.4.0...1.4.1 97 | [1.4.0]: https://github.com/thephpleague/statsd/compare/1.3.0...1.4.0 98 | [1.3.0]: https://github.com/thephpleague/statsd/compare/1.2.0...1.3.0 99 | [1.2.0]: https://github.com/thephpleague/statsd/compare/1.1.0...1.2.0 100 | [1.1.0]: https://github.com/thephpleague/statsd/compare/v1.0...1.1.0 101 | [1.0.0]: https://github.com/thephpleague/statsd/releases/tag/v1.0 102 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/php-loep/statsd). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. 17 | 18 | - **Create topic branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ phpunit 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Marc Qualie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StatsD PHP Library 2 | 3 | [![Build Status](https://img.shields.io/github/workflow/status/thephpleague/statsd/CI.svg)](https://github.com/thephpleague/statsd/actions?query=workflow%3ACI+branch%3Amaster) 4 | [![Total Downloads](https://poser.pugx.org/league/statsd/downloads.png)](https://packagist.org/packages/league/statsd) 5 | [![Latest Stable Version](https://poser.pugx.org/league/statsd/v/stable.png)](https://packagist.org/packages/league/statsd) 6 | 7 | 8 | A library for working with StatsD in PHP. 9 | 10 | 11 | 12 | ## Install 13 | 14 | Via Composer: 15 | 16 | ```shell 17 | composer require league/statsd 18 | ``` 19 | 20 | To use the Statsd Service Provider, you must register the provider when bootstrapping your Laravel application. 21 | 22 | ## Usage 23 | 24 | 25 | ### Configuring 26 | 27 | ```php 28 | $statsd = new League\StatsD\Client(); 29 | $statsd->configure([ 30 | 'host' => '127.0.0.1', 31 | 'port' => 8125, 32 | 'namespace' => 'example' 33 | ]); 34 | ``` 35 | 36 | OR 37 | 38 | ```php 39 | $statsd1 = StatsD\Client::instance('server1')->configure([...]); 40 | $statsd2 = StatsD\Client::instance('server2')->configure([...]); 41 | ``` 42 | 43 | The StatsD client wait for `ini_get('default_socket_timeout')` seconds when opening the socket by default. To reduce 44 | this timeout, add `'timeout' => ` to your config. 45 | 46 | The StatsD client will throw a `ConnectionException` if it is unable to send data to the StatsD server. You may choose 47 | to disable these exceptions and log a PHP warning instead if you wish. To do so, include the following in your config: 48 | 49 | ``` 50 | 'throwConnectionExceptions' => false 51 | ``` 52 | 53 | If omitted, this option defaults to `true`. 54 | 55 | 56 | 57 | ### Counters 58 | 59 | ```php 60 | $statsd->increment('web.pageview'); 61 | $statsd->decrement('storage.remaining'); 62 | $statsd->increment([ 63 | 'first.metric', 64 | 'second.metric' 65 | ], 2); 66 | $statsd->increment('web.clicks', 1, 0.5); 67 | ``` 68 | 69 | 70 | ### Gauges 71 | 72 | ```php 73 | $statsd->gauge('api.logged_in_users', 123456); 74 | ``` 75 | 76 | 77 | ### Sets 78 | 79 | ```php 80 | $userID = 23; 81 | $statsd->set('api.unique_logins', $userID); 82 | ``` 83 | 84 | 85 | ### Timers 86 | 87 | ```php 88 | $statsd->timing('api.response_time', 256); 89 | ``` 90 | 91 | ```php 92 | $metrics = array('api.response_time' => 256, 'api.memory' => 4096)); 93 | $statsd->timings($metrics); 94 | ``` 95 | 96 | 97 | ## Timing Blocks 98 | 99 | ```php 100 | $statsd->time('api.dbcall', function () { 101 | // this code execution will be timed and recorded in ms 102 | }); 103 | ``` 104 | 105 | ## Tags 106 | 107 | ***Attention!** That functionality support of tags in Datadog format!* 108 | 109 | You may configure it for all the metrics sending by the client. 110 | 111 | ```php 112 | $statsd->configure([ 113 | 'tags' => ['some_general_tag' => 'value'] 114 | ]); 115 | ``` 116 | 117 | Or you may send it for a single metric. 118 | 119 | ```php 120 | $statsd->increment('web.clicks', 1, 1, ['host' => $_SERVER['HTTP_HOST']]); 121 | ``` 122 | 123 | ## Framework integration 124 | 125 | Although this library will work with any PHP framework, below are a few ways to 126 | integrate it quickly with the most popular ones via included adapters. 127 | 128 | ### Laravel 4.x 129 | 130 | Find the `providers` key in your `app/config/app.php` and register the Statsd Service Provider. 131 | 132 | ```php 133 | 'providers' => [ 134 | // ... 135 | 'League\StatsD\Laravel\Provider\StatsdServiceProvider', 136 | ] 137 | ``` 138 | 139 | Find the `aliases` key in your `app/config/app.php` and add the Statsd Facade Alias. 140 | 141 | ```php 142 | 'aliases' => [ 143 | // ... 144 | 'Statsd' => 'League\StatsD\Laravel\Facade\StatsdFacade', 145 | ] 146 | ``` 147 | ### Laravel 5.x 148 | 149 | If you are using Laravel `>=5.5`, statsd uses [package discovery](https://laravel.com/docs/5.5/packages#package-discovery) to automatically register the service provider and facade. 150 | 151 | For older versions of Laravel 5, or if you disable package discovery: 152 | 153 | Find the `providers` key in your `config/app.php` and register the Statsd Service Provider. 154 | 155 | ```php 156 | 'providers' => [ 157 | // ... 158 | League\StatsD\Laravel5\Provider\StatsdServiceProvider::class, 159 | ] 160 | ``` 161 | 162 | Find the `aliases` key in your `app/config/app.php` and add the Statsd Facade Alias. 163 | 164 | ```php 165 | 'aliases' => [ 166 | // ... 167 | 'Statsd' => League\StatsD\Laravel5\Facade\StatsdFacade::class, 168 | ] 169 | ``` 170 | 171 | ### Lumen 172 | 173 | Register the provider in your boostrap app file ```boostrap/app.php``` 174 | 175 | Add the following line in the "Register Service Providers" section at the bottom of the file. 176 | 177 | ```php 178 | $app->register(\League\StatsD\Laravel5\Provider\StatsdServiceProvider::class); 179 | ``` 180 | 181 | Copy the config file ```statsd.php``` manually from the directory ```/vendor/league/statsd/config``` to the directory ```/config ``` (you may need to create this directory). 182 | 183 | Package Configuration 184 | 185 | In your `.env` file, add the configuration: 186 | 187 | ```php 188 | STATSD_HOST=127.0.0.1 189 | STATSD_PORT=8125 190 | STATSD_NAMESPACE= 191 | ``` 192 | 193 | 194 | 195 | ## Testing 196 | 197 | phpunit 198 | 199 | 200 | 201 | ## Contributing 202 | 203 | Please see [CONTRIBUTING](https://github.com/thephpleague/statsd/blob/master/CONTRIBUTING.md) for details. 204 | 205 | 206 | 207 | ## Credits 208 | 209 | - [Marc Qualie](https://github.com/marcqualie) 210 | - [All Contributors](https://github.com/thephpleague/statsd/contributors) 211 | 212 | 213 | 214 | ## License 215 | 216 | The MIT License (MIT). Please see [License File](https://github.com/thephpleague/statsd/blob/master/LICENSE) for more information. 217 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "league/statsd", 3 | "description": "A simple library for working with StatsD in PHP.", 4 | "keywords": [ 5 | "library", 6 | "statsd", 7 | "graphite" 8 | ], 9 | "homepage": "https://github.com/thephpleague/statsd", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Marc Qualie", 14 | "email": "marc@marcqualie.com", 15 | "homepage": "http://marcqualie.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^7.4 || ^8.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "^9.5", 24 | "squizlabs/php_codesniffer": "^3.6" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "League\\StatsD\\": "src" 29 | } 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "League\\StatsD\\Test\\": "tests" 34 | } 35 | }, 36 | "extra": { 37 | "laravel": { 38 | "providers": [ 39 | "League\\StatsD\\Laravel5\\Provider\\StatsdServiceProvider" 40 | ], 41 | "aliases": { 42 | "Statsd": "League\\StatsD\\Laravel5\\Facade\\StatsdFacade" 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /config/statsd.php: -------------------------------------------------------------------------------- 1 | env('STATSD_HOST', '127.0.0.1'), 5 | 6 | 'port' => env('STATSD_PORT', 8125), 7 | 8 | 'namespace' => env('STATSD_NAMESPACE', ''), 9 | 10 | 'throwConnectionExceptions' => true 11 | ]; 12 | -------------------------------------------------------------------------------- /docs/Getting Started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | You can follow the steps below to easily integrate this library into your application. 4 | 5 | 6 | ## Install 7 | 8 | Installation is pretty straight forward due to using the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) standard. 9 | 10 | Via Composer 11 | 12 | ```json 13 | { 14 | "require": { 15 | "league/statsd": "^2.0" 16 | } 17 | } 18 | ``` 19 | 20 | 21 | ## Bootstrapping 22 | 23 | Creating a new instance within your application is very easy. 24 | 25 | ```php 26 | $statsd = new League\StatsD\Client(); 27 | $statsd->configure([ 28 | 'host' => 'localhost', 29 | 'port' => 8125, 30 | 'namespace' => 'ns1' 31 | ]); 32 | ``` 33 | 34 | **Note** The namespace is optional, but recommended. 35 | 36 | 37 | ## Metrics 38 | 39 | There are various different metrics you can use within StatsD. Here are a few below. 40 | 41 | ```php 42 | $statsd->increment('metric'); // Increment a metric by 1 43 | $statsd->decrement('metric', 3); // Decrement a metric by 3 44 | $statsd->gauge('metric', 100); // Set a gauge value to 100 45 | $statsd->timing('metric', 300); // Record a time of 300ms 46 | $statsd->time('metric', function () {}); // Record function execution time 47 | ``` 48 | -------------------------------------------------------------------------------- /src/Client.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class Client implements StatsDClient 14 | { 15 | /** Instance instances array */ 16 | protected static array $instances = []; 17 | 18 | /** Instance ID */ 19 | protected string $instanceId; 20 | 21 | /** Server Host */ 22 | protected string $host = '127.0.0.1'; 23 | 24 | /** Server Port */ 25 | protected int $port = 8125; 26 | 27 | /** Last message sent to the server */ 28 | protected string $message = ''; 29 | 30 | /** Class namespace */ 31 | protected string $namespace = ''; 32 | 33 | /** Timeout for creating the socket connection */ 34 | protected ?float $timeout = null; 35 | 36 | /** Whether an exception should be thrown on failed connections */ 37 | protected bool $throwConnectionExceptions = true; 38 | 39 | /** Record metric start time */ 40 | protected array $metricTiming; 41 | 42 | /** @var resource|false|null Socket pointer for sending metrics */ 43 | protected $socket; 44 | 45 | /** Generic tags */ 46 | protected array $tags = []; 47 | 48 | /** 49 | * Singleton Reference 50 | */ 51 | public static function instance(string $name = 'default'): StatsDClient 52 | { 53 | if (! isset(self::$instances[$name])) { 54 | self::$instances[$name] = new static($name); 55 | } 56 | 57 | return self::$instances[$name]; 58 | } 59 | 60 | /** 61 | * Create a new instance 62 | */ 63 | public function __construct(?string $instanceId = null) 64 | { 65 | $this->instanceId = $instanceId ?? uniqid(); 66 | if ($this->timeout === null) { 67 | $this->timeout = ini_get('default_socket_timeout'); 68 | } 69 | } 70 | 71 | public function __toString(): string 72 | { 73 | return 'StatsD\Client::[' . $this->instanceId . ']'; 74 | } 75 | 76 | /** 77 | * Initialize Connection Details 78 | * 79 | * @param array $options Configuration options 80 | * 81 | * @return Client This instance 82 | * @throws ConfigurationException If port is invalid 83 | */ 84 | public function configure(array $options = []): self 85 | { 86 | if (isset($options['host'])) { 87 | $this->host = $options['host']; 88 | } 89 | if (isset($options['port'])) { 90 | if (! is_numeric($options['port']) || is_float($options['port']) || $options['port'] < 0 || $options['port'] > 65535) { 91 | throw new ConfigurationException($this, 'Port is out of range'); 92 | } 93 | $this->port = $options['port']; 94 | } 95 | 96 | if (isset($options['namespace'])) { 97 | $this->namespace = $options['namespace']; 98 | } 99 | 100 | if (isset($options['timeout'])) { 101 | $this->timeout = $options['timeout']; 102 | } 103 | 104 | if (isset($options['throwConnectionExceptions'])) { 105 | $this->throwConnectionExceptions = $options['throwConnectionExceptions']; 106 | } 107 | 108 | if (isset($options['tags'])) { 109 | $this->tags = $options['tags']; 110 | } 111 | 112 | return $this; 113 | } 114 | 115 | public function getHost(): string 116 | { 117 | return $this->host; 118 | } 119 | 120 | public function getPort(): int 121 | { 122 | return $this->port; 123 | } 124 | 125 | public function getNamespace(): string 126 | { 127 | return $this->namespace; 128 | } 129 | 130 | /** 131 | * Get Last message sent to server 132 | */ 133 | public function getLastMessage(): string 134 | { 135 | return $this->message; 136 | } 137 | 138 | /** 139 | * Increment a metric 140 | * 141 | * @param string|array $metrics Metric(s) to increment 142 | * @param int $delta Value to decrement the metric by 143 | * @param float $sampleRate Sample rate of metric 144 | * @param array $tags A list of metric tags values 145 | * 146 | * @throws ConnectionException 147 | */ 148 | public function increment($metrics, int $delta = 1, float $sampleRate = 1, array $tags = []): void 149 | { 150 | $metrics = (array)$metrics; 151 | $data = []; 152 | if ($sampleRate < 1) { 153 | foreach ($metrics as $metric) { 154 | if ((mt_rand() / mt_getrandmax()) <= $sampleRate) { 155 | $data[$metric] = $delta . '|c|@' . $sampleRate; 156 | } 157 | } 158 | } else { 159 | foreach ($metrics as $metric) { 160 | $data[$metric] = $delta . '|c'; 161 | } 162 | } 163 | 164 | $this->send($data, $tags); 165 | } 166 | 167 | /** 168 | * Decrement a metric 169 | * 170 | * @param string|array $metrics Metric(s) to decrement 171 | * @param int $delta Value to increment the metric by 172 | * @param float $sampleRate Sample rate of metric 173 | * @param array $tags A list of metric tags values 174 | * 175 | * @throws ConnectionException 176 | */ 177 | public function decrement($metrics, int $delta = 1, float $sampleRate = 1, array $tags = []): void 178 | { 179 | $this->increment($metrics, 0 - $delta, $sampleRate, $tags); 180 | } 181 | 182 | /** 183 | * Start timing the given metric 184 | * 185 | * @param string $metric Metric to time 186 | */ 187 | public function startTiming(string $metric): void 188 | { 189 | $this->metricTiming[$metric] = microtime(true); 190 | } 191 | 192 | /** 193 | * End timing the given metric and record 194 | * 195 | * @param string $metric Metric to time 196 | * @param array $tags A list of metric tags values 197 | * 198 | * @throws ConnectionException 199 | */ 200 | public function endTiming(string $metric, array $tags = []): void 201 | { 202 | $timer_start = $this->metricTiming[$metric]; 203 | $timer_end = microtime(true); 204 | $time = round(($timer_end - $timer_start) * 1000, 4); 205 | $this->timing($metric, $time, $tags); 206 | } 207 | 208 | /** 209 | * Timing 210 | * 211 | * @param string $metric Metric to track 212 | * @param float $time Time in milliseconds 213 | * @param array $tags A list of metric tags values 214 | * 215 | * @throws ConnectionException 216 | */ 217 | public function timing(string $metric, float $time, array $tags = []): void 218 | { 219 | $this->send( 220 | [$metric => $time . '|ms'], 221 | $tags 222 | ); 223 | } 224 | 225 | /** 226 | * Send multiple timing metrics at once 227 | * 228 | * @param array $metrics key value map of metric name -> timing value 229 | * 230 | * @throws ConnectionException 231 | */ 232 | public function timings(array $metrics): void 233 | { 234 | // add |ms to values 235 | $data = []; 236 | foreach ($metrics as $metric => $timing) { 237 | $data[$metric] = $timing . '|ms'; 238 | } 239 | 240 | $this->send($data); 241 | } 242 | 243 | /** 244 | * Time a function 245 | * 246 | * @param string $metric Metric to time 247 | * @param callable $func Function to record 248 | * @param array $tags A list of metric tags values 249 | * 250 | * @throws ConnectionException 251 | */ 252 | public function time(string $metric, $func, array $tags = []): void 253 | { 254 | $timer_start = microtime(true); 255 | $func(); 256 | $timer_end = microtime(true); 257 | $time = round(($timer_end - $timer_start) * 1000, 4); 258 | $this->timing($metric, $time, $tags); 259 | } 260 | 261 | 262 | /** 263 | * Gauges 264 | * 265 | * @param string $metric Metric to gauge 266 | * @param int|float $value Set the value of the gauge 267 | * @param array $tags A list of metric tags values 268 | * 269 | * @throws ConnectionException 270 | */ 271 | public function gauge(string $metric, $value, array $tags = []): void 272 | { 273 | $this->send([$metric => $value . '|g'], $tags); 274 | } 275 | 276 | /** 277 | * Sets - count the number of unique values passed to a key 278 | * 279 | * @param string $metric 280 | * @param mixed $value 281 | * @param array $tags A list of metric tags values 282 | * 283 | * @throws ConnectionException 284 | */ 285 | public function set(string $metric, $value, array $tags = []): void 286 | { 287 | $this->send([$metric => $value . '|s'], $tags); 288 | } 289 | 290 | /** 291 | * @return resource 292 | * @throws ConnectionException 293 | */ 294 | protected function getSocket() 295 | { 296 | if (! $this->socket) { 297 | $this->socket = @fsockopen('udp://' . $this->host, $this->port, $errno, $errstr, $this->timeout); 298 | if (! $this->socket) { 299 | throw new ConnectionException($this, '(' . $errno . ') ' . $errstr); 300 | } 301 | } 302 | 303 | return $this->socket; 304 | } 305 | 306 | protected function serializeTags(array $tags): string 307 | { 308 | if (! is_array($tags) || count($tags) === 0) { 309 | return ''; 310 | } 311 | $data = []; 312 | foreach ($tags as $tagKey => $tagValue) { 313 | $data[] = isset($tagValue) ? $tagKey . ':' . $tagValue : $tagKey; 314 | } 315 | 316 | return '|#' . implode(',', $data); 317 | } 318 | 319 | /** 320 | * Send Data to StatsD Server 321 | * 322 | * @param array $data A list of messages to send to the server 323 | * @param array $tags A list of tags to send to the server 324 | * 325 | * @throws ConnectionException If there is a connection problem with the host 326 | */ 327 | protected function send(array $data, array $tags = []): void 328 | { 329 | $tagsData = $this->serializeTags(array_replace($this->tags, $tags)); 330 | 331 | try { 332 | $socket = $this->getSocket(); 333 | $messages = []; 334 | $prefix = $this->namespace ? $this->namespace . '.' : ''; 335 | foreach ($data as $key => $value) { 336 | $messages[] = $prefix . $key . ':' . $value . $tagsData; 337 | } 338 | $this->message = implode("\n", $messages); 339 | @fwrite($socket, $this->message); 340 | fflush($socket); 341 | } catch (ConnectionException $e) { 342 | if ($this->throwConnectionExceptions) { 343 | throw $e; 344 | } else { 345 | trigger_error( 346 | sprintf( 347 | 'StatsD server connection failed (udp://%s:%d): %s', 348 | $this->host, 349 | $this->port, 350 | $e->getMessage() 351 | ), 352 | E_USER_WARNING 353 | ); 354 | } 355 | } 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/Exception/ConfigurationException.php: -------------------------------------------------------------------------------- 1 | instance = $instance; 26 | parent::__construct($message); 27 | } 28 | 29 | /** 30 | * Get Client instance that threw the exception 31 | */ 32 | public function getInstance(): StatsDClient 33 | { 34 | return $this->instance; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Exception/ConnectionException.php: -------------------------------------------------------------------------------- 1 | instance = $instance; 26 | parent::__construct($message); 27 | } 28 | 29 | /** 30 | * Get Client instance that threw the exception 31 | */ 32 | public function getInstance(): StatsDClient 33 | { 34 | return $this->instance; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Exception/Exception.php: -------------------------------------------------------------------------------- 1 | 11 | * @package League\StatsD\Laravel\Facade 12 | */ 13 | class StatsdFacade extends Facade 14 | { 15 | /** 16 | * Get the registered name of the component. 17 | * 18 | * @return string 19 | */ 20 | protected static function getFacadeAccessor() 21 | { 22 | return 'statsd'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Laravel/Provider/StatsdServiceProvider.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class StatsdServiceProvider extends ServiceProvider 14 | { 15 | /** 16 | * Boot the service provider. 17 | * 18 | * @return void 19 | */ 20 | public function boot() 21 | { 22 | $this->package('league/statsd', 'statsd'); 23 | } 24 | 25 | /** 26 | * Register the service provider. 27 | * 28 | * @return void 29 | */ 30 | public function register() 31 | { 32 | $this->registerStatsD(); 33 | } 34 | 35 | /** 36 | * Register Statsd 37 | * 38 | * @return void 39 | */ 40 | protected function registerStatsD() 41 | { 42 | $this->app['statsd'] = $this->app->share( 43 | function ($app) { 44 | // Set Default host and port 45 | $options = []; 46 | $config = $app['config']; 47 | 48 | if (isset($config['statsd.host'])) { 49 | $options['host'] = $config['statsd.host']; 50 | } 51 | 52 | if (isset($config['statsd.port'])) { 53 | $options['port'] = $config['statsd.port']; 54 | } 55 | 56 | if (isset($config['statsd.namespace'])) { 57 | $options['namespace'] = $config['statsd.namespace']; 58 | } 59 | 60 | if (isset($config['statsd.timeout'])) { 61 | $options['timeout'] = $config['statsd.timeout']; 62 | } 63 | 64 | if (isset($config['statsd.throwConnectionExceptions'])) { 65 | $options['throwConnectionExceptions'] = (bool) $config['statsd.throwConnectionExceptions']; 66 | } 67 | 68 | // Create 69 | $statsd = new Statsd(); 70 | $statsd->configure($options); 71 | return $statsd; 72 | } 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Laravel5/Facade/StatsdFacade.php: -------------------------------------------------------------------------------- 1 | 11 | * @package League\StatsD\Laravel5\Facade 12 | */ 13 | class StatsdFacade extends Facade 14 | { 15 | /** 16 | * Get the registered name of the component. 17 | * 18 | * @return string 19 | */ 20 | protected static function getFacadeAccessor() 21 | { 22 | return 'statsd'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Laravel5/Provider/StatsdServiceProvider.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class StatsdServiceProvider extends ServiceProvider 14 | { 15 | /** 16 | * Boot the service provider. 17 | * 18 | * @return void 19 | */ 20 | public function boot() 21 | { 22 | if (false !== strpos($this->app->version(), 'Lumen')) { 23 | $this->app->configure('statsd'); 24 | } else { 25 | // Publish config files 26 | $this->publishes([ 27 | __DIR__ . '/../../../config/statsd.php' => config_path('statsd.php'), 28 | ], 'config'); 29 | } 30 | } 31 | 32 | /** 33 | * Register the service provider. 34 | * 35 | * @return void 36 | */ 37 | public function register() 38 | { 39 | $this->registerStatsD(); 40 | } 41 | 42 | /** 43 | * Register Statsd 44 | * 45 | * @return void 46 | */ 47 | protected function registerStatsD() 48 | { 49 | $this->app->singleton( 50 | 'statsd', 51 | function ($app) { 52 | // Set Default host and port 53 | $options = []; 54 | $config = $app['config']; 55 | 56 | if (isset($config['statsd.host'])) { 57 | $options['host'] = $config['statsd.host']; 58 | } 59 | 60 | if (isset($config['statsd.port'])) { 61 | $options['port'] = $config['statsd.port']; 62 | } 63 | 64 | if (isset($config['statsd.namespace'])) { 65 | $options['namespace'] = $config['statsd.namespace']; 66 | } 67 | 68 | if (isset($config['statsd.timeout'])) { 69 | $options['timeout'] = $config['statsd.timeout']; 70 | } 71 | 72 | if (isset($config['statsd.throwConnectionExceptions'])) { 73 | $options['throwConnectionExceptions'] = (bool) $config['statsd.throwConnectionExceptions']; 74 | } 75 | 76 | // Create 77 | $statsd = new Statsd(); 78 | $statsd->configure($options); 79 | return $statsd; 80 | } 81 | ); 82 | 83 | $this->app->bind('League\StatsD\Client', function ($app) { 84 | return $app['statsd']; 85 | }); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/StatsDClient.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | interface StatsDClient 13 | { 14 | /** 15 | * Increment a metric 16 | * 17 | * @param string|array $metrics Metric(s) to increment 18 | * @param int $delta Value to decrement the metric by 19 | * @param float $sampleRate Sample rate of metric 20 | * @param array $tags A list of metric tags values 21 | * 22 | * @throws ConnectionException 23 | */ 24 | public function increment($metrics, int $delta = 1, float $sampleRate = 1, array $tags = []): void; 25 | 26 | /** 27 | * Decrement a metric 28 | * 29 | * @param string|array $metrics Metric(s) to decrement 30 | * @param int $delta Value to increment the metric by 31 | * @param float $sampleRate Sample rate of metric 32 | * @param array $tags A list of metric tags values 33 | * 34 | * @throws ConnectionException 35 | */ 36 | public function decrement($metrics, int $delta = 1, float $sampleRate = 1, array $tags = []): void; 37 | 38 | /** 39 | * Start timing the given metric 40 | * 41 | * @param string $metric Metric to time 42 | */ 43 | public function startTiming(string $metric): void; 44 | 45 | /** 46 | * End timing the given metric and record 47 | * 48 | * @param string $metric Metric to time 49 | * @param array $tags A list of metric tags values 50 | * 51 | * @throws ConnectionException 52 | */ 53 | public function endTiming(string $metric, array $tags = []): void; 54 | 55 | /** 56 | * Timing 57 | * 58 | * @param string $metric Metric to track 59 | * @param float $time Time in milliseconds 60 | * @param array $tags A list of metric tags values 61 | * 62 | * @throws ConnectionException 63 | */ 64 | public function timing(string $metric, float $time, array $tags = []): void; 65 | 66 | /** 67 | * Send multiple timing metrics at once 68 | * 69 | * @param array $metrics key value map of metric name -> timing value 70 | * 71 | * @throws ConnectionException 72 | */ 73 | public function timings(array $metrics): void; 74 | 75 | /** 76 | * Time a function 77 | * 78 | * @param string $metric Metric to time 79 | * @param callable $func Function to record 80 | * @param array $tags A list of metric tags values 81 | * 82 | * @throws ConnectionException 83 | */ 84 | public function time(string $metric, $func, array $tags = []): void; 85 | 86 | /** 87 | * Gauges 88 | * 89 | * @param string $metric Metric to gauge 90 | * @param int|float $value Set the value of the gauge 91 | * @param array $tags A list of metric tags values 92 | * 93 | * @throws ConnectionException 94 | */ 95 | public function gauge(string $metric, $value, array $tags = []): void; 96 | 97 | /** 98 | * Sets - count the number of unique values passed to a key 99 | * 100 | * @param string $metric 101 | * @param mixed $value 102 | * @param array $tags A list of metric tags values 103 | * 104 | * @throws ConnectionException 105 | */ 106 | public function set(string $metric, $value, array $tags = []): void; 107 | } 108 | --------------------------------------------------------------------------------