├── .gitignore
├── .scrutinizer.yml
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml.dist
├── scripts
├── influxdb_conf.toml
└── nginx_proxy.conf
├── src
├── Adapter
│ ├── Http
│ │ ├── Options.php
│ │ ├── Reader.php
│ │ └── Writer.php
│ ├── QueryableInterface.php
│ ├── Udp
│ │ ├── Options.php
│ │ └── Writer.php
│ ├── WritableInterface.php
│ └── WriterTrait.php
├── Client.php
├── Manager.php
├── Query
│ ├── CreateDatabase.php
│ ├── DeleteDatabase.php
│ └── GetDatabases.php
└── Type
│ ├── BoolType.php
│ ├── FloatType.php
│ ├── IntType.php
│ └── StringType.php
└── tests
├── integration
├── Adapter
│ ├── Http
│ │ ├── ReaderTest.php
│ │ └── WriterTest.php
│ └── Udp
│ │ └── WriterTest.php
├── ClientTest.php
├── Framework
│ └── TestCase.php
└── ManagerTest.php
└── unit
├── Adapter
├── Http
│ ├── ReaderTest.php
│ └── WriterTest.php
├── Udp
│ └── WriterTest.php
└── WriterTraitTest.php
├── ClientTest.php
├── ManagerTest.php
├── Query
├── CreateDatabaseTest.php
├── DeleteDatabaseTest.php
└── GetDatabasesTest.php
└── Type
├── BoolTypeTest.php
├── FloatTypeTest.php
├── IntTypeTest.php
└── StringTypeTest.php
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | tags
3 | composer.lock
4 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | tools:
2 | external_code_coverage:
3 | timeout: 900
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.6
5 | - 7.0
6 | - 7.1
7 |
8 | env:
9 | - GUZZLE_VERSION="~5" INFLUXDB_DEB="influxdb_1.2.4_amd64.deb"
10 | - GUZZLE_VERSION="~6" INFLUXDB_DEB="influxdb_1.2.4_amd64.deb"
11 |
12 | before_install:
13 | - sudo apt-get update
14 | - sudo apt-get install libcurl4-openssl-dev libjson0-dev
15 | - wget https://dl.influxdata.com/influxdb/releases/${INFLUXDB_DEB}
16 | - sudo useradd influxdb
17 | - sudo dpkg -i ${INFLUXDB_DEB}
18 | - sudo cp ./scripts/influxdb_conf.toml /etc/influxdb/influxdb.conf
19 | - travis_retry sudo service influxdb restart
20 | - sudo service influxdb status
21 | - sudo apt-get update
22 | - sudo apt-get install -y nginx
23 | - sudo cp scripts/nginx_proxy.conf /etc/nginx/conf.d/proxy.conf
24 | - travis_retry sudo service nginx restart
25 |
26 | before_script:
27 | - composer selfupdate
28 | - composer install --prefer-source --no-interaction
29 | - composer require guzzlehttp/guzzle:${GUZZLE_VERSION} --prefer-source --no-interaction --update-with-dependencies
30 |
31 | script:
32 | - vendor/bin/phpunit --coverage-clover=clover.xml
33 |
34 | after_script:
35 | - wget https://scrutinizer-ci.com/ocular.phar
36 | - php ocular.phar code-coverage:upload --format=php-clover clover.xml
37 |
38 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to InfluxDB PHP SDK
2 |
3 | ## Pull requests are always welcome
4 |
5 | Not sure if that typo is worth a pull request? Found a bug and know how to fix
6 | it? Do it! We will appreciate it. Any significant improvement should be
7 | documented as a GitHub issue before anybody starts working on it.
8 |
9 | We are always thrilled to receive pull requests. We do our best to process them
10 | quickly. If your pull request is not accepted on the first try, don't get
11 | discouraged!
12 |
13 | Just branch on master and prepare your PR.
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Corley S.r.l.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # InfluxDB PHP SDK
2 |
3 | [](https://travis-ci.org/corley/influxdb-php-sdk)
4 | [](https://scrutinizer-ci.com/g/corley/influxdb-php-sdk/?branch=master)
5 | [](https://scrutinizer-ci.com/g/corley/influxdb-php-sdk/?branch=master)
6 | [](https://packagist.org/packages/corley/influxdb-sdk)
7 | [](https://packagist.org/packages/corley/influxdb-sdk)
8 |
9 | Send metrics to InfluxDB and query for any data.
10 |
11 | This project support InfluxDB API `>= 0.9` - **For InfluxDB v0.8 checkout branch 0.3 (no longer supported)**
12 |
13 | Supported adapters:
14 |
15 | * UDP/IP
16 | * HTTP (via GuzzleHTTP versions: ~5, ~6) - **For Guzzle 4 support checkout branch 0.9 (no longer supported)**
17 |
18 | ## Install it
19 |
20 | Just use composer
21 |
22 | ```sh
23 | $ composer require corley/influxdb-sdk:~1
24 | ```
25 |
26 | Or add to your `composer.json` file
27 |
28 | ```json
29 | {
30 | "require": {
31 | "corley/influxdb-sdk": "~1"
32 | }
33 | }
34 | ```
35 |
36 | ## Use it
37 |
38 | Add new points:
39 |
40 | ```php
41 | $client->mark("app-search", [
42 | "key" => "this is my search"
43 | ]);
44 | ```
45 |
46 | Or use InfluxDB direct messages
47 |
48 | ```php
49 | $client->mark([
50 | "tags" => [
51 | "dc" => "eu-west-1",
52 | ],
53 | "points" => [
54 | [
55 | "measurement" => "instance",
56 | "fields" => [
57 | "cpu" => 18.12,
58 | "free" => 712423,
59 | ],
60 | ],
61 | ]
62 | ]);
63 | ```
64 |
65 | Retrieve existing points:
66 |
67 | ```php
68 | $results = $client->query('select * from "app-search"');
69 | ```
70 |
71 | ## InfluxDB client adapters
72 |
73 | Actually we supports two network adapters
74 |
75 | * UDP/IP - in order to send data via UDP/IP (datagram)
76 | * HTTP - in order to send/retrieve using HTTP messages (connection oriented)
77 |
78 | ### Using UDP/IP Adapter
79 |
80 | In order to use the UDP/IP adapter your must have PHP compiled with the `sockets` extension.
81 |
82 | **Usage**
83 |
84 | ```php
85 | $reader = ...
86 |
87 | $options = new Udp\Options();
88 | $writer = new Udp\Writer($options);
89 |
90 | $client = new Client($reader, $writer);
91 | ```
92 |
93 | _UDP/IP option set have only `host` and `port` properties you configure
94 | database and retention policies directly in your InfluxDB configuration_
95 |
96 | ### Using HTTP Adapters
97 |
98 | Actually Guzzle is used as HTTP client library
99 |
100 | ```php
101 | mark(...); // Use UDP/IP support
123 | $client->query("SELECT * FROM my_serie"); // Use HTTP support
124 | ```
125 |
126 | Or use only the HTTP
127 |
128 | ```php
129 | $reader = new Http\Reader($http, $options);
130 | $writer = new Http\Writer($http, $options);
131 | $client = new Client($reader, $writer);
132 |
133 | $client->mark(...); // Use HTTP support
134 | $client->query("SELECT * FROM my_serie"); // Use HTTP support
135 | ```
136 |
137 | ### Query InfluxDB
138 |
139 | You can query the time series database using the query method.
140 |
141 | ```php
142 | $client->query('select * from "mine"');
143 | ```
144 |
145 | The adapter returns the json decoded body of the InfluxDB response, something
146 | like:
147 |
148 | ```
149 | array(1) {
150 | 'results' =>
151 | array(1) {
152 | [0] =>
153 | array(1) {
154 | 'series' =>
155 | array(1) {
156 | ...
157 | }
158 | }
159 | }
160 | }
161 | ```
162 |
163 | If you prefere a more simple response than the original one, you can use
164 | [`corley/influxdb-http-handlers`](https://github.com/corley/influxdb-http-handlers)
165 | that convert, the original InfluxDB response, in a more simple response, something like:
166 |
167 | ```php
168 | array(1) {
169 | 'serie_name' => array(2) {
170 | [0] => array(4) {
171 | 'time' => string(30) "2015-09-09T20:42:07.927267636Z"
172 | 'value1' => int(1)
173 | 'value2' => int(2)
174 | 'valueS' => string(6) "string"
175 | }
176 | [1] => array(4) {
177 | 'time' => string(30) "2015-09-09T20:42:51.332853369Z"
178 | 'value1' => int(2)
179 | 'value2' => int(4)
180 | 'valueS' => string(11) "another-one"
181 | }
182 | }
183 | }
184 | ```
185 |
186 | ## Global tags and retention policy
187 |
188 | You can set a set of default tags, that the SDK will add to your metrics:
189 |
190 | ```php
191 | $options = new Http\Options();
192 | $options->setTags([
193 | "env" => "prod",
194 | "region" => "eu-west-1",
195 | ]);
196 | ```
197 |
198 | The SDK mark all point adding those tags.
199 |
200 | You can set a default retentionPolicy using
201 |
202 | ```
203 | $options->setRetentionPolicy("myPolicy");
204 | ```
205 |
206 | In that way the SDK use that policy instead of `default` policy.
207 |
208 | ## Proxies and InfluxDB
209 |
210 | If you proxy your InfluxDB typically you have a prefix in your endpoints.
211 |
212 | ```php
213 | $option->setHost("proxy.influxdb.tld");
214 | $option->setPort(80);
215 | $option->setPrefix("/influxdb"); // your prefix is: /influxdb
216 |
217 | // final url will be: http://proxy.influxdb.tld:80/influxdb/write
218 |
219 | $client->mark("serie", ["data" => "my-data"]);
220 | ```
221 |
222 | ## Data type management
223 |
224 | From InfluxDB version `>=0.9.3` integer types are marked with a trailing `i`.
225 | This library supports data types, in particular PHP types are mapped to influxdb
226 | in this way by defaults:
227 |
228 | And the resulting mapping will be:
229 |
230 | | PHP | InfluxDB |
231 | |---------|----------|
232 | | int | int64 |
233 | | double | float64 |
234 | | boolean | boolean |
235 | | string | string |
236 |
237 | ```php
238 | $client->mark("serie", [
239 | "value" => 12, // Marked as int64
240 | "elem" => 12.4, // Marked as float64
241 | ]);
242 | ```
243 |
244 | ### Force data type
245 |
246 | If you want to ensure that a type is effectively parsed correctly you can force it directly during the send operation
247 |
248 | ```php
249 | $client->mark("serie", [
250 | "value" => new IntType(12), // Marked as int64
251 | "elem" => new FloatType(12.4), // Marked as float64
252 | "status" => new BoolType(true), // Marked as boolean
253 | "line" => new StringType("12w"), // Marked as string
254 | ]);
255 | ```
256 |
257 | ### Query Builder
258 |
259 | Interested in a Query Builder?
260 |
261 | https://github.com/corley/dbal-influxdb
262 |
263 | Thanks to Doctrine DBAL (Abstract Layer) you can use the query builder
264 |
265 | ```php
266 | $qb = $conn->createQueryBuilder();
267 |
268 | $qb->select("*")
269 | ->from("cpu_load_short")
270 | ->where("time = ?")
271 | ->setParameter(0, 1434055562000000000);
272 |
273 | $data = $qb->execute();
274 | foreach ($data->fetchAll() as $element) {
275 | // Use your element
276 | }
277 | ```
278 |
279 | ```php
280 | $config = new \Doctrine\DBAL\Configuration();
281 | //..
282 | $connectionParams = array(
283 | 'dbname' => 'mydb',
284 | 'user' => 'root',
285 | 'password' => 'root',
286 | 'host' => 'localhost',
287 | 'port' => 8086,
288 | "driverClass" => "Corley\\DBAL\\Driver\\InfluxDB",
289 | );
290 | $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
291 | ```
292 |
293 | ## Database operations and custom queries
294 |
295 | The class `InfluxDB\Client` does not support any database operation by itself.
296 | That means that you don't have any helper function for create new databases, or
297 | list actual databases and so on.
298 | Thanks to `InfluxDB\Manager` you can use a preset of queries and create your own
299 | personal queries that will run against the Influxdb instance.
300 |
301 | ### Create the manager
302 |
303 | The `Manager` instance is very simple, you have to create it with a client
304 | instance.
305 |
306 | ```php
307 | $manager = new Manager($client); // InfluxDB\Client instance
308 | ```
309 |
310 | ### Attach new queries
311 |
312 | The manager allows to attach new queries via an helper method `addQuery`.
313 |
314 | ```php
315 | $manager->addQuery("getExceptionsInMinutes", function($minutes) {
316 | return "SELECT * FROM app_exceptions WHERE time > now() - {$minutes}m";
317 | });
318 |
319 | $manager->getExceptionsInMinutes(10); // The callable name
320 | ```
321 |
322 | As you can see you have to label your anonymous function and reuse it via the
323 | manager.
324 |
325 | In order to collect and reuse custom queries you can define query objects:
326 |
327 | ```php
328 | class GetExceptionsInMinutes
329 | {
330 | public function __invoke($minutes)
331 | {
332 | return "SELECT * FROM app_exceptions WHERE time > now() - {$minutes}m";
333 | }
334 |
335 | public function __toString()
336 | {
337 | return "getExceptionsInMinutes";
338 | }
339 | }
340 |
341 | $manager->addQuery(new GetExceptionsInMinutes());
342 |
343 | $manager->getExceptionsInMinutes(10); //Use the query
344 | ```
345 |
346 | As you can see valid query command should be `callable` via the `__invoke`
347 | method and should be also serializable as strings via `__toString` method
348 |
349 | ### Existing queries
350 |
351 | This project comes out with a preset of valid queries:
352 |
353 | * Create new database `InfluxDB\Query\CreateDatabase`
354 | * Drop existing databases `InfluxDB\Query\DeleteDatabase`
355 | * List existing databases `InfluxDB\Query\GetDatabases`
356 |
357 | ```php
358 | $manager->addQuery(new CreateDatabase());
359 | $manager->addQuery(new DeleteDatabase());
360 | $manager->addQuery(new GetDatabases());
361 | ```
362 |
363 | ## FAQ
364 |
365 | ### Add sockets support to your PHP
366 |
367 | To verify if you have the `sockets` extension just issue a:
368 |
369 | ```bash
370 | php -m | grep sockets
371 | ```
372 |
373 | If you don't have the `sockets` extension, you can proceed in two ways:
374 |
375 | - Recompile your PHP whith the `--enable-sockets` flag
376 | - Or just compile the `sockets` extension extracting it from the PHP source.
377 |
378 | 1. Download the source relative to the PHP version that you on from [here](https://github.com/php/php-src/releases)
379 | 2. Enter in the `ext/sockets` directory
380 | 3. Issue a `phpize && ./configure && make -j && sudo make install`
381 | 4. Add `extension=sockets.so` to your php.ini
382 |
383 | ### Guzzle 4 support
384 |
385 | We drop the Guzzle 4 support, but we tested it as working HTTP adapter in up
386 | to PHP 7.0 and is stable with this project with version 0.9.3.
387 |
388 | If you need Guzzle 4 as HTTP adapter require for 0.9.3 version
389 |
390 | ```sh
391 | compose require corley/influxdb-sdk:0.9.*
392 | ```
393 |
394 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "corley/influxdb-sdk",
3 | "license": "MIT",
4 | "description": "Send your app metrics to InfluxDB",
5 | "require": {
6 | "php": ">=5.5",
7 | "guzzlehttp/guzzle": "~4|~5|~6"
8 | },
9 | "require-dev": {
10 | "phpunit/phpunit": "4.*",
11 | "ext-sockets": "*"
12 | },
13 | "homepage": "http://www.corley.it/",
14 | "keywords": ["influxdb", "udp", "sdk"],
15 | "authors": [
16 | {
17 | "name": "Gianluca Arbezzano",
18 | "email": "gianluca.arbezzano@corley.it"
19 | },
20 | {
21 | "name": "Walter Dal Mut",
22 | "email": "walter.dalmut@corley.it"
23 | },
24 | {
25 | "name": "Gabriele Mittica",
26 | "email": "gabriele.mittica@corley.it"
27 | }
28 | ],
29 | "autoload": {
30 | "psr-4": {
31 | "InfluxDB\\": ["./src/"],
32 | "Corley\\": ["./benchmarks/"]
33 | }
34 | },
35 | "autoload-dev": {
36 | "psr-4": {
37 | "InfluxDB\\": ["./tests/unit"],
38 | "InfluxDB\\Integration\\": ["./tests/integration"]
39 | }
40 | },
41 | "suggest": {
42 | "corley/dbal-influxdb": "This library help you to build query",
43 | "fabpot/pimple": "Allows to prepare the client dependencies in order to require an initialized instance",
44 | "zendframework/zend-servicemanager": "Use a service locator in order to prepare a valid instance",
45 | "symfony/dependency-injection": "Prepare a valid instance via the symfony DiC"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | tests/integration
12 |
13 |
14 | tests/unit
15 |
16 |
17 |
18 |
19 | src
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/scripts/influxdb_conf.toml:
--------------------------------------------------------------------------------
1 | ### Welcome to the InfluxDB configuration file.
2 |
3 | # The values in this file override the default values used by the system if
4 | # a config option is not specified. The commented out lines are the the configuration
5 | # field and the default value used. Uncommentting a line and changing the value
6 | # will change the value used at runtime when the process is restarted.
7 |
8 | # Once every 24 hours InfluxDB will report usage data to usage.influxdata.com
9 | # The data includes a random ID, os, arch, version, the number of series and other
10 | # usage data. No data from user databases is ever transmitted.
11 | # Change this option to true to disable reporting.
12 | # reporting-disabled = false
13 |
14 | # we'll try to get the hostname automatically, but if it the os returns something
15 | # that isn't resolvable by other servers in the cluster, use this option to
16 | # manually set the hostname
17 | # hostname = "localhost"
18 |
19 | ###
20 | ### [meta]
21 | ###
22 | ### Controls the parameters for the Raft consensus group that stores metadata
23 | ### about the InfluxDB cluster.
24 | ###
25 |
26 | [meta]
27 | # Where the metadata/raft database is stored
28 | dir = "/var/lib/influxdb/meta"
29 |
30 | # Automatically create a default retention policy when creating a database.
31 | # retention-autocreate = true
32 |
33 | # If log messages are printed for the meta service
34 | # logging-enabled = true
35 |
36 | ###
37 | ### [data]
38 | ###
39 | ### Controls where the actual shard data for InfluxDB lives and how it is
40 | ### flushed from the WAL. "dir" may need to be changed to a suitable place
41 | ### for your system, but the WAL settings are an advanced configuration. The
42 | ### defaults should work for most systems.
43 | ###
44 |
45 | [data]
46 | # The directory where the TSM storage engine stores TSM files.
47 | dir = "/var/lib/influxdb/data"
48 |
49 | # The directory where the TSM storage engine stores WAL files.
50 | wal-dir = "/var/lib/influxdb/wal"
51 |
52 | # Trace logging provides more verbose output around the tsm engine. Turning
53 | # this on can provide more useful output for debugging tsm engine issues.
54 | # trace-logging-enabled = false
55 |
56 | # Whether queries should be logged before execution. Very useful for troubleshooting, but will
57 | # log any sensitive data contained within a query.
58 | # query-log-enabled = true
59 |
60 | # Settings for the TSM engine
61 |
62 | # CacheMaxMemorySize is the maximum size a shard's cache can
63 | # reach before it starts rejecting writes.
64 | # cache-max-memory-size = 1048576000
65 |
66 | # CacheSnapshotMemorySize is the size at which the engine will
67 | # snapshot the cache and write it to a TSM file, freeing up memory
68 | # cache-snapshot-memory-size = 26214400
69 |
70 | # CacheSnapshotWriteColdDuration is the length of time at
71 | # which the engine will snapshot the cache and write it to
72 | # a new TSM file if the shard hasn't received writes or deletes
73 | # cache-snapshot-write-cold-duration = "10m"
74 |
75 | # CompactFullWriteColdDuration is the duration at which the engine
76 | # will compact all TSM files in a shard if it hasn't received a
77 | # write or delete
78 | # compact-full-write-cold-duration = "4h"
79 |
80 | # The maximum series allowed per database before writes are dropped. This limit can prevent
81 | # high cardinality issues at the database level. This limit can be disabled by setting it to
82 | # 0.
83 | # max-series-per-database = 1000000
84 |
85 | # The maximum number of tag values per tag that are allowed before writes are dropped. This limit
86 | # can prevent high cardinality tag values from being written to a measurement. This limit can be
87 | # disabled by setting it to 0.
88 | # max-values-per-tag = 100000
89 |
90 | ###
91 | ### [coordinator]
92 | ###
93 | ### Controls the clustering service configuration.
94 | ###
95 |
96 | [coordinator]
97 | # The default time a write request will wait until a "timeout" error is returned to the caller.
98 | # write-timeout = "10s"
99 |
100 | # The maximum number of concurrent queries allowed to be executing at one time. If a query is
101 | # executed and exceeds this limit, an error is returned to the caller. This limit can be disabled
102 | # by setting it to 0.
103 | # max-concurrent-queries = 0
104 |
105 | # The maximum time a query will is allowed to execute before being killed by the system. This limit
106 | # can help prevent run away queries. Setting the value to 0 disables the limit.
107 | # query-timeout = "0s"
108 |
109 | # The the time threshold when a query will be logged as a slow query. This limit can be set to help
110 | # discover slow or resource intensive queries. Setting the value to 0 disables the slow query logging.
111 | # log-queries-after = "0s"
112 |
113 | # The maximum number of points a SELECT can process. A value of 0 will make the maximum
114 | # point count unlimited.
115 | # max-select-point = 0
116 |
117 | # The maximum number of series a SELECT can run. A value of 0 will make the maximum series
118 | # count unlimited.
119 |
120 | # The maximum number of series a SELECT can run. A value of zero will make the maximum series
121 | # count unlimited.
122 | # max-select-series = 0
123 |
124 | # The maxium number of group by time bucket a SELECt can create. A value of zero will max the maximum
125 | # number of buckets unlimited.
126 | # max-select-buckets = 0
127 |
128 | ###
129 | ### [retention]
130 | ###
131 | ### Controls the enforcement of retention policies for evicting old data.
132 | ###
133 |
134 | [retention]
135 | # Determines whether retention policy enforcment enabled.
136 | # enabled = true
137 |
138 | # The interval of time when retention policy enforcement checks run.
139 | # check-interval = "30m"
140 |
141 | ###
142 | ### [shard-precreation]
143 | ###
144 | ### Controls the precreation of shards, so they are available before data arrives.
145 | ### Only shards that, after creation, will have both a start- and end-time in the
146 | ### future, will ever be created. Shards are never precreated that would be wholly
147 | ### or partially in the past.
148 |
149 | [shard-precreation]
150 | # Determines whether shard pre-creation service is enabled.
151 | # enabled = true
152 |
153 | # The interval of time when the check to pre-create new shards runs.
154 | # check-interval = "10m"
155 |
156 | # The default period ahead of the endtime of a shard group that its successor
157 | # group is created.
158 | # advance-period = "30m"
159 |
160 | ###
161 | ### Controls the system self-monitoring, statistics and diagnostics.
162 | ###
163 | ### The internal database for monitoring data is created automatically if
164 | ### if it does not already exist. The target retention within this database
165 | ### is called 'monitor' and is also created with a retention period of 7 days
166 | ### and a replication factor of 1, if it does not exist. In all cases the
167 | ### this retention policy is configured as the default for the database.
168 |
169 | [monitor]
170 | # Whether to record statistics internally.
171 | # store-enabled = true
172 |
173 | # The destination database for recorded statistics
174 | # store-database = "_internal"
175 |
176 | # The interval at which to record statistics
177 | # store-interval = "10s"
178 |
179 | ###
180 | ### [admin]
181 | ###
182 | ### Controls the availability of the built-in, web-based admin interface. If HTTPS is
183 | ### enabled for the admin interface, HTTPS must also be enabled on the [http] service.
184 | ###
185 | ### NOTE: This interface is deprecated as of 1.1.0 and will be removed in a future release.
186 |
187 | [admin]
188 | # Determines whether the admin service is enabled.
189 | # enabled = false
190 |
191 | # The default bind address used by the admin service.
192 | # bind-address = ":8083"
193 |
194 | # Whether the admin service should use HTTPS.
195 | # https-enabled = false
196 |
197 | # The SSL certificate used when HTTPS is enabled.
198 | # https-certificate = "/etc/ssl/influxdb.pem"
199 |
200 | ###
201 | ### [http]
202 | ###
203 | ### Controls how the HTTP endpoints are configured. These are the primary
204 | ### mechanism for getting data into and out of InfluxDB.
205 | ###
206 |
207 | [http]
208 | # Determines whether HTTP endpoint is enabled.
209 | enabled = true
210 |
211 | # The bind address used by the HTTP service.
212 | bind-address = ":8086"
213 |
214 | # Determines whether HTTP authentication is enabled.
215 | # auth-enabled = false
216 |
217 | # The default realm sent back when issuing a basic auth challenge.
218 | # realm = "InfluxDB"
219 |
220 | # Determines whether HTTP request logging is enable.d
221 | # log-enabled = true
222 |
223 | # Determines whether detailed write logging is enabled.
224 | # write-tracing = false
225 |
226 | # Determines whether the pprof endpoint is enabled. This endpoint is used for
227 | # troubleshooting and monitoring.
228 | # pprof-enabled = true
229 |
230 | # Determines whether HTTPS is enabled.
231 | # https-enabled = false
232 |
233 | # The SSL certificate to use when HTTPS is enabled.
234 | # https-certificate = "/etc/ssl/influxdb.pem"
235 |
236 | # Use a separate private key location.
237 | # https-private-key = ""
238 |
239 | # The JWT auth shared secret to validate requests using JSON web tokens.
240 | # shared-secret = ""
241 |
242 | # The default chunk size for result sets that should be chunked.
243 | # max-row-limit = 0
244 |
245 | # The maximum number of HTTP connections that may be open at once. New connections that
246 | # would exceed this limit are dropped. Setting this value to 0 disables the limit.
247 | # max-connection-limit = 0
248 |
249 | # Enable http service over unix domain socket
250 | # unix-socket-enabled = false
251 |
252 | # The path of the unix domain socket.
253 | # bind-socket = "/var/run/influxdb.sock"
254 |
255 | ###
256 | ### [subscriber]
257 | ###
258 | ### Controls the subscriptions, which can be used to fork a copy of all data
259 | ### received by the InfluxDB host.
260 | ###
261 |
262 | [subscriber]
263 | # Determines whether the subscriber service is enabled.
264 | # enabled = true
265 |
266 | # The default timeout for HTTP writes to subscribers.
267 | # http-timeout = "30s"
268 |
269 | # Allows insecure HTTPS connections to subscribers. This is useful when testing with self-
270 | # signed certificates.
271 | # insecure-skip-verify = false
272 |
273 | # The path to the PEM encoded CA certs file. If the empty string, the default system certs will be used
274 | # ca-certs = ""
275 |
276 | # The number of writer goroutines processing the write channel.
277 | # write-concurrency = 40
278 |
279 | # The number of in-flight writes buffered in the write channel.
280 | # write-buffer-size = 1000
281 |
282 |
283 | ###
284 | ### [[graphite]]
285 | ###
286 | ### Controls one or many listeners for Graphite data.
287 | ###
288 |
289 | [[graphite]]
290 | # Determines whether the graphite endpoint is enabled.
291 | # enabled = false
292 | # database = "graphite"
293 | # retention-policy = ""
294 | # bind-address = ":2003"
295 | # protocol = "tcp"
296 | # consistency-level = "one"
297 |
298 | # These next lines control how batching works. You should have this enabled
299 | # otherwise you could get dropped metrics or poor performance. Batching
300 | # will buffer points in memory if you have many coming in.
301 |
302 | # Flush if this many points get buffered
303 | # batch-size = 5000
304 |
305 | # number of batches that may be pending in memory
306 | # batch-pending = 10
307 |
308 | # Flush at least this often even if we haven't hit buffer limit
309 | # batch-timeout = "1s"
310 |
311 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max.
312 | # udp-read-buffer = 0
313 |
314 | ### This string joins multiple matching 'measurement' values providing more control over the final measurement name.
315 | # separator = "."
316 |
317 | ### Default tags that will be added to all metrics. These can be overridden at the template level
318 | ### or by tags extracted from metric
319 | # tags = ["region=us-east", "zone=1c"]
320 |
321 | ### Each template line requires a template pattern. It can have an optional
322 | ### filter before the template and separated by spaces. It can also have optional extra
323 | ### tags following the template. Multiple tags should be separated by commas and no spaces
324 | ### similar to the line protocol format. There can be only one default template.
325 | # templates = [
326 | # "*.app env.service.resource.measurement",
327 | # # Default template
328 | # "server.*",
329 | # ]
330 |
331 | ###
332 | ### [collectd]
333 | ###
334 | ### Controls one or many listeners for collectd data.
335 | ###
336 |
337 | [[collectd]]
338 | # enabled = false
339 | # bind-address = ":25826"
340 | # database = "collectd"
341 | # retention-policy = ""
342 | #
343 | # The collectd service supports either scanning a directory for multiple types
344 | # db files, or specifying a single db file.
345 | # typesdb = "/usr/local/share/collectd"
346 | #
347 | # security-level = "none"
348 | # auth-file = "/etc/collectd/auth_file"
349 |
350 | # These next lines control how batching works. You should have this enabled
351 | # otherwise you could get dropped metrics or poor performance. Batching
352 | # will buffer points in memory if you have many coming in.
353 |
354 | # Flush if this many points get buffered
355 | # batch-size = 5000
356 |
357 | # Number of batches that may be pending in memory
358 | # batch-pending = 10
359 |
360 | # Flush at least this often even if we haven't hit buffer limit
361 | # batch-timeout = "10s"
362 |
363 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max.
364 | # read-buffer = 0
365 |
366 | ###
367 | ### [opentsdb]
368 | ###
369 | ### Controls one or many listeners for OpenTSDB data.
370 | ###
371 |
372 | [[opentsdb]]
373 | # enabled = false
374 | # bind-address = ":4242"
375 | # database = "opentsdb"
376 | # retention-policy = ""
377 | # consistency-level = "one"
378 | # tls-enabled = false
379 | # certificate= "/etc/ssl/influxdb.pem"
380 |
381 | # Log an error for every malformed point.
382 | # log-point-errors = true
383 |
384 | # These next lines control how batching works. You should have this enabled
385 | # otherwise you could get dropped metrics or poor performance. Only points
386 | # metrics received over the telnet protocol undergo batching.
387 |
388 | # Flush if this many points get buffered
389 | # batch-size = 1000
390 |
391 | # Number of batches that may be pending in memory
392 | # batch-pending = 5
393 |
394 | # Flush at least this often even if we haven't hit buffer limit
395 | # batch-timeout = "1s"
396 |
397 | ###
398 | ### [[udp]]
399 | ###
400 | ### Controls the listeners for InfluxDB line protocol data via UDP.
401 | ###
402 |
403 | [[udp]]
404 | enabled = true
405 | bind-address = ":4444"
406 | database = "udp.test"
407 | # retention-policy = ""
408 |
409 | # These next lines control how batching works. You should have this enabled
410 | # otherwise you could get dropped metrics or poor performance. Batching
411 | # will buffer points in memory if you have many coming in.
412 |
413 | # Flush if this many points get buffered
414 | # batch-size = 5000
415 |
416 | # Number of batches that may be pending in memory
417 | # batch-pending = 10
418 |
419 | # Will flush at least this often even if we haven't hit buffer limit
420 | # batch-timeout = "1s"
421 |
422 | # UDP Read buffer size, 0 means OS default. UDP listener will fail if set above OS max.
423 | # read-buffer = 0
424 |
425 | ###
426 | ### [continuous_queries]
427 | ###
428 | ### Controls how continuous queries are run within InfluxDB.
429 | ###
430 |
431 | [continuous_queries]
432 | # Determiens whether the continuous query service is enabled.
433 | # enabled = true
434 |
435 | # Controls whether queries are logged when executed by the CQ service.
436 | # log-enabled = true
437 |
438 | # interval for how often continuous queries will be checked if they need to run
439 | # run-interval = "1s"
440 |
441 |
--------------------------------------------------------------------------------
/scripts/nginx_proxy.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 9000 default_server;
3 | listen [::]:9000 default_server ipv6only=on;
4 |
5 | root /usr/share/nginx/html;
6 | index index.html index.htm;
7 |
8 | server_name localhost;
9 |
10 | location / {
11 | try_files $uri $uri/ =404;
12 | }
13 |
14 | location /influxdb {
15 | proxy_set_header X-Real-IP $remote_addr;
16 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
17 | proxy_set_header Host $http_host;
18 | proxy_set_header X-NginX-Proxy true;
19 |
20 | rewrite ^/influxdb/?(.*) /$1 break;
21 |
22 | proxy_pass http://localhost:8086;
23 | proxy_redirect off;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Adapter/Http/Options.php:
--------------------------------------------------------------------------------
1 | setHost("localhost");
19 | $this->setPort(8086);
20 | $this->setUsername("root");
21 | $this->setPassword("root");
22 | $this->setProtocol("http");
23 | $this->setPrefix("");
24 |
25 | $this->setRetentionPolicy("default");
26 | $this->setTags([]);
27 | }
28 |
29 | public function getPrefix()
30 | {
31 | return $this->prefix;
32 | }
33 |
34 | public function setPrefix($prefix)
35 | {
36 | $this->prefix = $prefix;
37 | return $this;
38 | }
39 |
40 | public function getTags()
41 | {
42 | return $this->tags;
43 | }
44 |
45 | public function setTags($tags)
46 | {
47 | $this->tags = $tags;
48 | return $this;
49 | }
50 |
51 | public function getRetentionPolicy()
52 | {
53 | return $this->retentionPolicy;
54 | }
55 |
56 | public function setRetentionPolicy($retentionPolicy)
57 | {
58 | $this->retentionPolicy = $retentionPolicy;
59 | return $this;
60 | }
61 |
62 | public function getProtocol()
63 | {
64 | return $this->protocol;
65 | }
66 |
67 | public function setProtocol($protocol)
68 | {
69 | $this->protocol = $protocol;
70 | return $this;
71 | }
72 |
73 | public function getHost()
74 | {
75 | return $this->host;
76 | }
77 |
78 | public function setHost($host)
79 | {
80 | $this->host = $host;
81 | return $this;
82 | }
83 |
84 | public function getPort()
85 | {
86 | return $this->port;
87 | }
88 |
89 | public function setPort($port)
90 | {
91 | $this->port = $port;
92 | return $this;
93 | }
94 |
95 | public function getUsername()
96 | {
97 | return $this->username;
98 | }
99 |
100 | public function setUsername($username)
101 | {
102 | $this->username = $username;
103 | return $this;
104 | }
105 |
106 | public function getPassword()
107 | {
108 | return $this->password;
109 | }
110 |
111 | public function setPassword($password)
112 | {
113 | $this->password = $password;
114 | return $this;
115 | }
116 |
117 | public function getDatabase()
118 | {
119 | return $this->database;
120 | }
121 |
122 | public function setDatabase($database)
123 | {
124 | $this->database = $database;
125 | return $this;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/Adapter/Http/Reader.php:
--------------------------------------------------------------------------------
1 | httpClient = $httpClient;
16 | $this->options = $options;
17 | }
18 |
19 | public function getOptions()
20 | {
21 | return $this->options;
22 | }
23 |
24 | public function query($query)
25 | {
26 | $options = [
27 | "auth" => [$this->getOptions()->getUsername(), $this->getOptions()->getPassword()],
28 | 'query' => [
29 | "q" => $query,
30 | "db" => $this->getOptions()->getDatabase(),
31 | ]
32 | ];
33 |
34 | return $this->get($options);
35 | }
36 |
37 | private function get(array $httpMessage)
38 | {
39 | $endpoint = $this->getHttpQueryEndpoint();
40 | return json_decode($this->httpClient->get($endpoint, $httpMessage)->getBody(), true);
41 | }
42 |
43 | protected function getHttpQueryEndpoint()
44 | {
45 | return $this->getHttpEndpoint("query");
46 | }
47 |
48 | private function getHttpEndpoint($operation)
49 | {
50 | $url = sprintf(
51 | "%s://%s:%d%s/%s",
52 | $this->getOptions()->getProtocol(),
53 | $this->getOptions()->getHost(),
54 | $this->getOptions()->getPort(),
55 | $this->getOptions()->getPrefix(),
56 | $operation
57 | );
58 |
59 | return $url;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Adapter/Http/Writer.php:
--------------------------------------------------------------------------------
1 | httpClient = $httpClient;
19 | $this->options = $options;
20 | }
21 |
22 | public function getOptions()
23 | {
24 | return $this->options;
25 | }
26 |
27 | public function send(array $message)
28 | {
29 | $httpMessage = [
30 | "auth" => [$this->getOptions()->getUsername(), $this->getOptions()->getPassword()],
31 | 'query' => [
32 | "db" => $this->getOptions()->getDatabase(),
33 | "retentionPolicy" => $this->getOptions()->getRetentionPolicy(),
34 | ],
35 | "body" => $this->messageToLineProtocol($message, $this->getOptions()->getTags())
36 | ];
37 |
38 | $endpoint = $this->getHttpSeriesEndpoint();
39 | return $this->httpClient->post($endpoint, $httpMessage);
40 | }
41 |
42 | protected function getHttpSeriesEndpoint()
43 | {
44 | return $this->getHttpEndpoint("write");
45 | }
46 |
47 | private function getHttpEndpoint($operation)
48 | {
49 | $url = sprintf(
50 | "%s://%s:%d%s/%s",
51 | $this->getOptions()->getProtocol(),
52 | $this->getOptions()->getHost(),
53 | $this->getOptions()->getPort(),
54 | $this->getOptions()->getPrefix(),
55 | $operation
56 | );
57 |
58 | return $url;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Adapter/QueryableInterface.php:
--------------------------------------------------------------------------------
1 | setHost("localhost");
13 | $this->setTags([]);
14 | $this->setPort(4444);
15 | }
16 |
17 | public function getPort()
18 | {
19 | return $this->port;
20 | }
21 |
22 | public function setPort($port)
23 | {
24 | $this->port = $port;
25 | return $this;
26 | }
27 |
28 | public function getTags()
29 | {
30 | return $this->tags;
31 | }
32 |
33 | public function setTags($tags)
34 | {
35 | $this->tags = $tags;
36 | return $this;
37 | }
38 |
39 | public function getHost()
40 | {
41 | return $this->host;
42 | }
43 |
44 | public function setHost($host)
45 | {
46 | $this->host = $host;
47 | return $this;
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/src/Adapter/Udp/Writer.php:
--------------------------------------------------------------------------------
1 | options = $options;
17 | }
18 |
19 | public function getOptions()
20 | {
21 | return $this->options;
22 | }
23 | public function send(array $message)
24 | {
25 | $message = $this->messageToLineProtocol($message, $this->getOptions()->getTags());
26 |
27 | $this->write($message);
28 | }
29 |
30 | public function write($message)
31 | {
32 | // Create a handler in order to handle the 'Host is down' message
33 | set_error_handler(function() {
34 | // Suppress the error, this is the UDP adapter and if we can't send
35 | // it then we shouldn't inturrupt their application.
36 | });
37 |
38 | $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
39 | socket_sendto($socket, $message, strlen($message), 0, $this->getOptions()->getHost(), $this->getOptions()->getPort());
40 | socket_close($socket);
41 |
42 | // Remove our error handler.
43 | restore_error_handler();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Adapter/WritableInterface.php:
--------------------------------------------------------------------------------
1 | prepareMessageSection($message);
15 | $message["tags"] = array_replace_recursive($tags, $message["tags"]);
16 |
17 | $lines = [];
18 | foreach ($message["points"] as $point) {
19 | $point = $this->prepareMessageSection($point, $message["time"]);
20 | $tags = array_replace_recursive($message["tags"], $point["tags"]);
21 |
22 | $tagLine = $this->tagsToString($tags);
23 |
24 | $lines[] = sprintf(
25 | "%s%s %s %d", $point["measurement"], $tagLine, $this->pointsToString($point["fields"]), $point["time"]
26 | );
27 | }
28 |
29 | return implode("\n", $lines);
30 | }
31 |
32 | private function prepareMessageSection(array $message, $unixepoch = false)
33 | {
34 | if (!array_key_exists("tags", $message)) {
35 | $message["tags"] = [];
36 | }
37 |
38 | if (!$unixepoch) {
39 | $unixepoch = (int)(microtime(true) * 1e9);
40 | }
41 |
42 | if (array_key_exists("time", $message)) {
43 | $dt = new DateTime($message["time"]);
44 | $unixepoch = (int)($dt->format("U") * 1e9);
45 | }
46 | $message["time"] = $unixepoch;
47 |
48 | return $message;
49 | }
50 |
51 | protected function tagsToString(array $tags)
52 | {
53 | $tagLine = "";
54 | if (count($tags) > 0) {
55 | array_walk($tags, function (&$value, $key) {
56 | $value = "{$this->addSlashes($key)}={$this->addSlashes($value)}";
57 | });
58 | $tagLine = sprintf(",%s", implode(",", $tags));
59 | }
60 |
61 | return $tagLine;
62 | }
63 |
64 | protected function pointsToString(array $elements)
65 | {
66 | array_walk($elements, function (&$value, $key) {
67 | $dataType = gettype($value);
68 | if (!in_array($dataType, ["string", "double", "boolean", "integer"])) {
69 | $dataType = "serializable";
70 | }
71 | $dataType = ucfirst($dataType);
72 | if ($dataType!='Null') {
73 | $value = call_user_func([$this, "convert{$dataType}"], $value);
74 | $value = "{$this->addSlashes($key)}={$value}";
75 | }
76 | });
77 | $elements = array_filter($elements);
78 | return implode(",", $elements);
79 | }
80 |
81 | protected function convertSerializable($value)
82 | {
83 | return "{$value}";
84 | }
85 |
86 | protected function convertString($value)
87 | {
88 | return "\"{$value}\"";
89 | }
90 |
91 | protected function convertInteger($value)
92 | {
93 | return "{$value}i" ;
94 | }
95 |
96 | protected function convertDouble($value)
97 | {
98 | return $value;
99 | }
100 |
101 | protected function convertBoolean($value)
102 | {
103 | return (($value) ? "true" : "false");
104 | }
105 |
106 | /**
107 | * Returns strings with space, comma, or equals sign characters backslashed per Influx write protocol syntax
108 | *
109 | * @param string $value
110 | * @return string
111 | */
112 | private function addSlashes($value)
113 | {
114 | return str_replace([
115 | ' ',
116 | ',',
117 | '='
118 | ], [
119 | '\ ',
120 | '\,',
121 | '\='
122 | ], $value);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/Client.php:
--------------------------------------------------------------------------------
1 | reader = $reader;
19 | $this->writer = $writer;
20 | }
21 |
22 | public function getReader()
23 | {
24 | return $this->reader;
25 | }
26 |
27 | public function getWriter()
28 | {
29 | return $this->writer;
30 | }
31 |
32 | public function mark($name, array $values = [])
33 | {
34 | $data = $name;
35 | if (!is_array($name)) {
36 | $data =[];
37 | $data['points'][0]['measurement'] = $name;
38 | $data['points'][0]['fields'] = $values;
39 | }
40 |
41 | return $this->getWriter()->send($data);
42 | }
43 |
44 | public function query($query)
45 | {
46 | return $this->getReader()->query($query);
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Manager.php:
--------------------------------------------------------------------------------
1 | client = $client;
16 | $this->queries = [];
17 | }
18 |
19 | public function addQuery($name, callable $query = null)
20 | {
21 | if ($query === null) {
22 | list($name, $query) = $this->fromObjectToNameCallableList($name);
23 | }
24 |
25 | $this->queries[$name] = $query;
26 | }
27 |
28 | private function fromObjectToNameCallableList($name)
29 | {
30 | if (is_object($name) && is_callable($name)) {
31 | if (method_exists($name, "__toString")) {
32 | return [(string)$name, $name];
33 | }
34 | }
35 |
36 | throw new InvalidArgumentException("Your command should implements '__toString' method and should be a callable thing");
37 | }
38 |
39 | public function __call($name, $args)
40 | {
41 | if (method_exists($this->client, $name)) {
42 | return call_user_func_array([$this->client, $name], $args);
43 | }
44 |
45 | if (array_key_exists($name, $this->queries)) {
46 | $query = call_user_func_array($this->queries[$name], $args);
47 | return $this->client->query($query);
48 | }
49 |
50 | throw new RuntimeException("The method you are using is not allowed: '{$name}', do you have to add it with 'addQuery'");
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/CreateDatabase.php:
--------------------------------------------------------------------------------
1 | num = boolval((string)$value);
11 | }
12 |
13 | public function __toString()
14 | {
15 | return ($this->num) ? "true" : "false";
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/Type/FloatType.php:
--------------------------------------------------------------------------------
1 | num = floatval((string)$value);
11 | }
12 |
13 | public function __toString()
14 | {
15 | return (string)$this->num;
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/Type/IntType.php:
--------------------------------------------------------------------------------
1 | num = intval((string)$value);
11 | }
12 |
13 | public function __toString()
14 | {
15 | return $this->num . "i";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Type/StringType.php:
--------------------------------------------------------------------------------
1 | num = strval($value);
11 | }
12 |
13 | public function __toString()
14 | {
15 | return "\"" . $this->num . "\"";
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/tests/integration/Adapter/Http/ReaderTest.php:
--------------------------------------------------------------------------------
1 | markTestIncomplete("Missing reader test cases");
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/tests/integration/Adapter/Http/WriterTest.php:
--------------------------------------------------------------------------------
1 | getClient()->createDatabase($options->getDatabase());
20 |
21 | $http = new GuzzleHttpClient();
22 | $adapter = new Writer($http, $options);
23 |
24 | $adapter->send([
25 | "points" => [
26 | [
27 | "measurement" => "vm-serie",
28 | "fields" => [
29 | "cpu" => 18.12,
30 | "free" => 712423,
31 | "valid" => true,
32 | "overclock" => false,
33 | ],
34 | ],
35 | ]
36 | ]);
37 |
38 | $this->assertSerieExists($options->getDatabase(), "vm-serie");
39 | $this->assertSerieCount($options->getDatabase(), "vm-serie", 1);
40 | $this->assertValueExistsInSerie($options->getDatabase(), "vm-serie", "cpu", 18.12);
41 | $this->assertValueExistsInSerie($options->getDatabase(), "vm-serie", "free", 712423);
42 | $this->assertValueExistsInSerie($options->getDatabase(), "vm-serie", "valid", true);
43 | $this->assertValueExistsInSerie($options->getDatabase(), "vm-serie", "overclock", false);
44 | }
45 |
46 | public function getDifferentOptions()
47 | {
48 | return [
49 | [(new Options())->setPort(8086)->setDatabase("tcp.test")],
50 | [(new Options())->setPort(9000)->setDatabase("proxy.test")->setPrefix("/influxdb")],
51 | ];
52 | }
53 | }
54 |
55 |
56 |
--------------------------------------------------------------------------------
/tests/integration/Adapter/Udp/WriterTest.php:
--------------------------------------------------------------------------------
1 | setPort(4444);
13 | $adapter = new Writer($options);
14 |
15 | $this->getClient()->createDatabase("udp.test");
16 |
17 | $adapter->write("cpu value=12.33 " . (int)(microtime(true)*1e9));
18 |
19 | sleep(2);
20 |
21 | $this->assertSerieExists("udp.test", "cpu");
22 | $this->assertSerieCount("udp.test", "cpu", 1);
23 | $this->assertValueExistsInSerie("udp.test", "cpu", "value", 12.33);
24 | }
25 |
26 | /**
27 | * @dataProvider getDifferentOptions
28 | */
29 | public function testWriteSimplePointsUsingSendMethod(UdpOptions $options)
30 | {
31 | $adapter = new Writer($options);
32 |
33 | $this->getClient()->createDatabase("udp.test");
34 |
35 | $adapter->send([
36 | "retentionPolicy" => "default",
37 | "points" => [
38 | [
39 | "measurement" => "mem",
40 | "fields" => [
41 | "value" => 1233,
42 | "value_float" => 1233.34,
43 | "with_string" => "this is a string",
44 | "with_bool" => true,
45 | ],
46 | ],
47 | ],
48 | ]);
49 |
50 | sleep(2);
51 |
52 | $this->assertSerieExists("udp.test", "mem");
53 | $this->assertSerieCount("udp.test", "mem", 1);
54 | $this->assertValueExistsInSerie("udp.test", "mem", "value", 1233);
55 | $this->assertValueExistsInSerie("udp.test", "mem", "value_float", 1233.34);
56 | $this->assertValueExistsInSerie("udp.test", "mem", "with_string", "this is a string");
57 | $this->assertValueExistsInSerie("udp.test", "mem", "with_bool", true);
58 | }
59 |
60 | public function getDifferentOptions()
61 | {
62 | return [
63 | [(new UdpOptions())->setPort(4444)],
64 | ];
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/integration/ClientTest.php:
--------------------------------------------------------------------------------
1 | getClient()->createDatabase("tcp.test");
23 | $this->getClient()->createDatabase("udp.test");
24 | }
25 |
26 | public function testSimpleMarkPublicSignature()
27 | {
28 | $options = new Options();
29 | $options->setDatabase("tcp.test");
30 |
31 | $guzzleHttp = new GuzzleHttpClient();
32 | $writer = new Writer($guzzleHttp, $options);
33 | $reader = new Reader($guzzleHttp, $options);
34 | $client = new Client($reader, $writer);
35 |
36 | $client->mark("vm", ["mark" => "element"]);
37 |
38 | $this->assertSerieExists("tcp.test", "vm");
39 | $this->assertSerieCount("tcp.test", "vm", 1);
40 | $this->assertValueExistsInSerie("tcp.test", "vm", "mark", "element");
41 | }
42 |
43 | public function testDirectMessagesMarkPublicSignature()
44 | {
45 | $options = new Options();
46 | $options->setDatabase("tcp.test");
47 |
48 | $guzzleHttp = new GuzzleHttpClient();
49 | $writer = new Writer($guzzleHttp, $options);
50 | $reader = new Reader($guzzleHttp, $options);
51 | $client = new Client($reader, $writer);
52 |
53 | $client->mark([
54 | "database" => "tcp.test",
55 | "retentionPolicy" => "default",
56 | "points" => [
57 | [
58 | "measurement" => "tt",
59 | "fields" => [
60 | "cpu" => 1,
61 | "mem" => 2,
62 | ],
63 | ]
64 | ],
65 | ]);
66 |
67 | $this->assertSerieExists("tcp.test", "tt");
68 | $this->assertSerieCount("tcp.test", "tt", 1);
69 | $this->assertValueExistsInSerie("tcp.test", "tt", "cpu", 1);
70 | $this->assertValueExistsInSerie("tcp.test", "tt", "mem", 2);
71 | }
72 |
73 | /**
74 | * Test that we handle socket problems correctly in the UDP
75 | * adapter, and that they don't inturrupt the user's application.
76 | *
77 | * @group udp
78 | */
79 | public function testReplicateIssue27()
80 | {
81 | $options = new \InfluxDB\Adapter\Udp\Options();
82 |
83 | // Configure options
84 | $options->setHost('172.16.1.182');
85 | $options->setPort(4444);
86 |
87 | $guzzleHttp = new GuzzleHttpClient();
88 | $writer = new UdpWriter($options);
89 | $reader = new Reader($guzzleHttp, new Options());
90 | $client = new Client($reader, $writer);
91 | $client->mark("udp.test", ["mark" => "element"]);
92 | }
93 |
94 | /**
95 | * @group udp
96 | */
97 | public function testWriteUDPPackagesToNoOne()
98 | {
99 | $options = new \InfluxDB\Adapter\Udp\Options();
100 | $options->setHost("127.0.0.1");
101 | $options->setPort(64071); //This is a wrong port
102 |
103 | $guzzleHttp = new GuzzleHttpClient();
104 | $writer = new UdpWriter($options);
105 | $reader = new Reader($guzzleHttp, new Options());
106 | $client = new Client($reader, $writer);
107 |
108 | $client->mark("udp.test", ["mark" => "element"]);
109 | }
110 |
111 | /**
112 | * @group udp
113 | */
114 | public function testWriteUDPPackagesToInvalidHostname()
115 | {
116 | $options = new \InfluxDB\Adapter\Udp\Options();
117 | $options->setHost("www.test-invalid.this-is-not-a-tld");
118 | $options->setPort(15984);
119 |
120 | $guzzleHttp = new GuzzleHttpClient();
121 | $writer = new UdpWriter($options);
122 | $reader = new Reader($guzzleHttp, new Options());
123 | $client = new Client($reader, $writer);
124 |
125 | $client->mark("udp.test", ["mark" => "element"]);
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/tests/integration/Framework/TestCase.php:
--------------------------------------------------------------------------------
1 | options = new HttpOptions();
22 | $guzzleHttp = new GuzzleHttpClient();
23 | $writer = new Writer($guzzleHttp, $options);
24 | $reader = new Reader($guzzleHttp, $options);
25 |
26 | $client = $this->client = new Manager(new Client($reader, $writer));
27 |
28 | $client->addQuery(new CreateDatabase());
29 | $client->addQuery(new DeleteDatabase());
30 | $client->addQuery(new GetDatabases());
31 |
32 | $this->dropAll();
33 | }
34 |
35 | public function tearDown()
36 | {
37 | $this->dropAll();
38 | }
39 |
40 | private function dropAll()
41 | {
42 | $databases = $this->getClient()->getDatabases();
43 | if (array_key_exists("values", $databases["results"][0]["series"][0])) {
44 | foreach ($databases["results"][0]["series"][0]["values"] as $database) {
45 | $this->getClient()->deleteDatabase($database[0]);
46 | }
47 | }
48 | }
49 |
50 | public function assertValueExistsInSerie($database, $serieName, $column, $value)
51 | {
52 | $this->getOptions()->setDatabase($database);
53 | $body = $this->getClient()->query("select {$column} from \"{$serieName}\"");
54 |
55 | foreach ($body["results"][0]["series"][0]["values"] as $result) {
56 | if ($result[1] == $value) {
57 | return $this->assertTrue(true);
58 | }
59 | }
60 |
61 | return $this->fail("Missing value '{$value}'");
62 | }
63 |
64 | public function assertSerieCount($database, $serieName, $count)
65 | {
66 | $this->getOptions()->setDatabase($database);
67 | $body = $this->getClient()->query("select * from \"{$serieName}\"");
68 |
69 | $this->assertCount(1, $body["results"][0]["series"][0]["values"]);
70 | }
71 |
72 | public function assertSerieExists($database, $serieName)
73 | {
74 | $this->getOptions()->setDatabase($database);
75 | $body = $this->getClient()->query("show measurements");
76 |
77 | foreach ($body["results"][0]["series"][0]["values"] as $result) {
78 | if ($result[0] == $serieName) {
79 | return $this->assertTrue(true);
80 | }
81 | }
82 |
83 | return $this->fail("Missing serie with name '{$serieName}' in database '{$database}'");
84 | }
85 |
86 | public function assertDatabasesCount($count)
87 | {
88 | $databases = $this->client->getDatabases();
89 | $databaseList = [];
90 | if (array_key_exists("values", $databases["results"][0]["series"][0])) {
91 | $databaseList = $databases["results"][0]["series"][0]["values"];
92 | }
93 |
94 | $this->assertCount($count, $databaseList);
95 | }
96 |
97 | public function getOptions()
98 | {
99 | return $this->options;
100 | }
101 |
102 | public function getClient()
103 | {
104 | return $this->client;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tests/integration/ManagerTest.php:
--------------------------------------------------------------------------------
1 | addQuery(new CreateDatabase());
27 | $manager->addQuery(new DeleteDatabase());
28 | $manager->addQuery(new GetDatabases());
29 |
30 | $manager->createDatabase("one");
31 | $manager->createDatabase("two");
32 | $manager->createDatabase("walter");
33 |
34 | $databases = $manager->getDatabases();
35 |
36 | $this->assertCount(3, $databases["results"][0]["series"][0]["values"]);
37 | }
38 |
39 | public function testDropExistingDatabase()
40 | {
41 | $options = new Options();
42 | $guzzleHttp = new GuzzleHttpClient();
43 | $writer = new Writer($guzzleHttp, $options);
44 | $reader = new Reader($guzzleHttp, $options);
45 | $client = new Client($reader, $writer);
46 | $manager = new Manager($client);
47 |
48 | $manager->addQuery(new CreateDatabase());
49 | $manager->addQuery(new DeleteDatabase());
50 | $manager->addQuery(new GetDatabases());
51 |
52 | $manager->createDatabase("walter");
53 | $this->assertDatabasesCount(1);
54 |
55 | $manager->deleteDatabase("walter");
56 | $this->assertDatabasesCount(0);
57 | }
58 |
59 | public function testListActiveDatabases()
60 | {
61 | $options = new Options();
62 | $guzzleHttp = new GuzzleHttpClient();
63 | $writer = new Writer($guzzleHttp, $options);
64 | $reader = new Reader($guzzleHttp, $options);
65 | $client = new Client($reader, $writer);
66 | $manager = new Manager($client);
67 |
68 | $manager->addQuery(new CreateDatabase());
69 | $manager->addQuery(new DeleteDatabase());
70 | $manager->addQuery(new GetDatabases());
71 |
72 | $manager->createDatabase("one");
73 | $manager->createDatabase("two");
74 |
75 | $databases = $manager->getDatabases();
76 |
77 | $this->assertCount(2, $databases["results"][0]["series"][0]["values"]);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/tests/unit/Adapter/Http/ReaderTest.php:
--------------------------------------------------------------------------------
1 | getMethod("getHttpQueryEndpoint");
25 | $method->setAccessible(true);
26 |
27 | $endpoint = $method->invokeArgs($adapter, []);
28 | $this->assertEquals($final, $endpoint);
29 | }
30 |
31 | public function getQueryEndpoints()
32 | {
33 | return [
34 | ["http://localhost:9000/query", (new Options())->setHost("localhost")->setPort(9000)],
35 | ["https://localhost:9000/query", (new Options())->setHost("localhost")->setPort(9000)->setProtocol("https")],
36 | ["http://localhost:9000/influxdb/query", (new Options())->setHost("localhost")->setPort(9000)->setPrefix("/influxdb")],
37 | ];
38 | }
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/tests/unit/Adapter/Http/WriterTest.php:
--------------------------------------------------------------------------------
1 | getMethod("getHttpSeriesEndpoint");
25 | $method->setAccessible(true);
26 |
27 | $endpoint = $method->invokeArgs($adapter, []);
28 | $this->assertEquals($final, $endpoint);
29 | }
30 |
31 | public function getWriteEndpoints()
32 | {
33 | return [
34 | ["http://localhost:9000/write", (new Options())->setHost("localhost")->setPort(9000)],
35 | ["https://localhost:9000/write", (new Options())->setHost("localhost")->setPort(9000)->setProtocol("https")],
36 | ["http://localhost:9000/influxdb/write", (new Options())->setHost("localhost")->setPort(9000)->setPrefix("/influxdb")],
37 | ];
38 | }
39 |
40 | public function testMergeWithDefaultOptions()
41 | {
42 | $options = new Options();
43 | $options->setDatabase("db");
44 | $httpClient = $this->prophesize("GuzzleHttp\\Client");
45 | $httpClient->post(Argument::Any(), [
46 | "auth" => ["root", "root"],
47 | "query" => [
48 | "db" => "db",
49 | "retentionPolicy" => "default",
50 | ],
51 | "body" => null,
52 | ])->shouldBeCalledTimes(1);
53 | $adapter = new Writer($httpClient->reveal(), $options);
54 | $adapter->send([]);
55 | }
56 |
57 | /**
58 | * @dataProvider getMessages
59 | */
60 | public function testMessageComposition($options, $send, $regexp)
61 | {
62 | $guzzleHttp = $this->prophesize("GuzzleHttp\Client");
63 | $guzzleHttp->post("http://localhost:8086/write", Argument::that(function($val) use ($regexp) {
64 | $body = $val["body"];
65 | $this->assertRegExp($regexp, $body);
66 | return true;
67 | }))->shouldBeCalledTimes(1);
68 | $adapter = new Writer($guzzleHttp->reveal(), $options);
69 |
70 | $adapter->send($send);
71 | }
72 |
73 | public function getMessages()
74 | {
75 | return [
76 | [
77 | (new Options())->setDatabase("db"),
78 | [
79 | "time" => "2009-11-10T23:00:00Z",
80 | "points" => [
81 | [
82 | "measurement" => "tcp.test",
83 | "fields" => [
84 | "mark" => "element"
85 | ]
86 | ]
87 | ]
88 | ],
89 | '/tcp.test mark="element" 1257894000000000000/i'
90 | ],
91 | [
92 | (new Options())->setDatabase("db"),
93 | [
94 | "points" => [
95 | [
96 | "measurement" => "tcp.test",
97 | "fields" => [
98 | "mark" => "element"
99 | ]
100 | ],
101 | [
102 | "measurement" => "tcp.test",
103 | "fields" => [
104 | "mark" => "element2"
105 | ]
106 | ],
107 | ]
108 | ],
109 | '/tcp.test mark="element" \d+\ntcp.test mark="element2" \d+/i'
110 | ],
111 | [
112 | (new Options())->setDatabase("db"),
113 | [
114 | "points" => [
115 | [
116 | "measurement" => "tcp.test",
117 | "fields" => [
118 | "mark" => "element"
119 | ]
120 | ]
121 | ]
122 | ],
123 | '/tcp.test mark="element" \d+/i'
124 | ],
125 | [
126 | (new Options())->setDatabase("db"),
127 | [
128 | "time" => "2009-11-10T23:00:00Z",
129 | "points" => [
130 | [
131 | "measurement" => "tcp.test",
132 | "time" => "2009-11-10T23:00:00Z",
133 | "fields" => [
134 | "mark" => "element"
135 | ]
136 | ]
137 | ]
138 | ],
139 | '/tcp.test mark="element" 1257894000000000000/i'
140 | ],
141 | [
142 | (new Options())->setDatabase("db"),
143 | [
144 | "time" => "2009-11-10T23:00:00Z",
145 | "points" => [
146 | [
147 | "measurement" => "tcp.test",
148 | "time" => "2009-11-10T23:00:00Z",
149 | "fields" => [
150 | "mark" => "element"
151 | ]
152 | ],
153 | [
154 | "measurement" => "tcp.test",
155 | "fields" => [
156 | "mark" => "element2"
157 | ]
158 | ],
159 | ]
160 | ],
161 | '/tcp.test mark="element" 1257894000000000000\ntcp.test mark="element2" 1257894000000000000$/i'
162 | ],
163 | [
164 | (new Options())->setDatabase("db"),
165 | [
166 | "points" => [
167 | [
168 | "measurement" => "tcp.test",
169 | "time" => "2009-11-10T23:00:00Z",
170 | "fields" => [
171 | "mark" => "element",
172 | ]
173 | ]
174 | ]
175 | ],
176 | '/tcp.test mark="element" 1257894000000000000$/i'
177 | ],
178 | [
179 | (new Options())->setDatabase("db")->setTags(["dc" => "us-west"]),
180 | [
181 | "points" => [
182 | [
183 | "measurement" => "tcp.test",
184 | "fields" => [
185 | "mark" => "element"
186 | ]
187 | ]
188 | ]
189 | ],
190 | '/tcp.test,dc=us-west mark="element" \d+/i'
191 | ],
192 | [
193 | (new Options())->setDatabase("db")->setTags(["dc" => "us-west"]),
194 | [
195 | "tags" => ["region" => "us"],
196 | "points" => [
197 | [
198 | "measurement" => "tcp.test",
199 | "fields" => [
200 | "mark" => "element"
201 | ]
202 | ]
203 | ]
204 | ],
205 | '/tcp.test,dc=us-west,region=us mark="element" \d+/i'
206 | ],
207 | [
208 | (new Options())->setDatabase("db")->setTags(["dc" => "us-west"]),
209 | [
210 | "tags" => ["region" => "us"],
211 | "points" => [
212 | [
213 | "measurement" => "tcp.test",
214 | "tags" => [
215 | "tt" => "fi",
216 | ],
217 | "fields" => [
218 | "mark" => "element"
219 | ]
220 | ]
221 | ]
222 | ],
223 | '/tcp.test,dc=us-west,region=us,tt=fi mark="element" \d+$/i'
224 | ],
225 | [
226 | (new Options())->setDatabase("db")->setTags(["dc" => "us-west"]),
227 | [
228 | "tags" => ["region" => "us"],
229 | "points" => [
230 | [
231 | "measurement" => "tcp.test",
232 | "fields" => [
233 | "mark" => "element"
234 | ]
235 | ],
236 | [
237 | "measurement" => "tcp.test",
238 | "fields" => [
239 | "mark" => "element2"
240 | ]
241 | ]
242 | ]
243 | ],
244 | '/tcp.test,dc=us-west,region=us mark="element" \d+\ntcp.test,dc=us-west,region=us mark="element2" \d+$/i'
245 | ],
246 | [
247 | (new Options())->setDatabase("db"),
248 | [
249 | "points" => [
250 | [
251 | "measurement" => "tcp.test",
252 | "fields" => [
253 | "mark" => "element",
254 | "value" => 12,
255 | ]
256 | ]
257 | ]
258 | ],
259 | '/tcp.test mark="element",value=12i \d+/i'
260 | ],
261 | ];
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/tests/unit/Adapter/Udp/WriterTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder("InfluxDB\Adapter\Udp\Writer")
20 | ->setConstructorArgs([new Options()])
21 | ->setMethods(["write"])
22 | ->getMock();
23 | $object->expects($this->once())
24 | ->method("write")
25 | ->with($response);
26 |
27 | $object->send($input);
28 | }
29 |
30 | public function getMessages()
31 | {
32 | return [
33 | [
34 | [
35 | "time" => "2009-11-10T23:00:00Z",
36 | "points" => [
37 | [
38 | "measurement" => "cpu",
39 | "fields" => [
40 | "value" => 1.,
41 | ],
42 | ],
43 | ],
44 | ],
45 | "cpu value=1 1257894000000000000"
46 | ],
47 | [
48 | [
49 | "time" => "2009-11-10T23:00:00Z",
50 | "points" => [
51 | [
52 | "measurement" => "cpu",
53 | "fields" => [
54 | "value" => 1.,
55 | "string" => "escape",
56 | ],
57 | ],
58 | ],
59 | ],
60 | "cpu value=1,string=\"escape\" 1257894000000000000"
61 | ],
62 | [
63 | [
64 | "tags" => [
65 | "region" => "us-west",
66 | "host" => "serverA",
67 | "env" => "prod",
68 | "target" => "servers",
69 | "zone" => "1c",
70 | ],
71 | "time" => "2009-11-10T23:00:00Z",
72 | "points" => [
73 | [
74 | "measurement" => "cpu",
75 | "fields" => [
76 | "cpu" => 18.12,
77 | "free" => 712432.,
78 | ],
79 | ],
80 | ],
81 | ],
82 | "cpu,region=us-west,host=serverA,env=prod,target=servers,zone=1c cpu=18.12,free=712432 1257894000000000000"
83 | ],
84 | [
85 | [
86 | "tags" => [
87 | "region" => "us-west",
88 | "host" => "serverA",
89 | "env" => "prod",
90 | "target" => "servers",
91 | "zone" => "1c",
92 | ],
93 | "time" => "2009-11-10T23:00:00Z",
94 | "points" => [
95 | [
96 | "measurement" => "cpu",
97 | "fields" => [
98 | "cpu" => 18.12,
99 | ],
100 | ],
101 | [
102 | "measurement" => "mem",
103 | "fields" => [
104 | "free" => 712432.,
105 | ],
106 | ],
107 | ],
108 | ],
109 | <<getMockBuilder("InfluxDB\\Adapter\\Udp\\Writer")
124 | ->setConstructorArgs([$options])
125 | ->setMethods(["write", "generateTimeInNanoSeconds"])
126 | ->getMock();
127 |
128 | $adapter->expects($this->any())
129 | ->method("generateTimeInNanoSeconds")
130 | ->will($this->returnValue(1245));
131 |
132 | $adapter->expects($this->once())
133 | ->method("write")
134 | ->with($this->matchesRegularExpression("/udp.test mark=\"element\" \d+/i"));
135 |
136 | $adapter->send([
137 | "points" => [
138 | [
139 | "measurement" => "udp.test",
140 | "fields" => [
141 | "mark" => "element"
142 | ]
143 | ]
144 | ]
145 | ]);
146 | }
147 |
148 | /**
149 | * @group udp
150 | */
151 | public function testSendMultipleMeasurementWithUdpIp()
152 | {
153 | $options = new Options();
154 | $adapter = $this->getMockBuilder("InfluxDB\\Adapter\\Udp\\Writer")
155 | ->setConstructorArgs([$options])
156 | ->setMethods(["write", "generateTimeInNanoSeconds"])
157 | ->getMock();
158 |
159 | $adapter->expects($this->any())
160 | ->method("generateTimeInNanoSeconds")
161 | ->will($this->onConsecutiveCalls(1245, 1246));
162 |
163 | $adapter->expects($this->once())
164 | ->method("write")
165 | ->with($this->matchesRegularExpression(<<send([
172 | "points" => [
173 | [
174 | "measurement" => "mem",
175 | "fields" => [
176 | "free" => 712423.,
177 | ],
178 | ],
179 | [
180 | "measurement" => "cpu",
181 | "fields" => [
182 | "cpu" => 18.12,
183 | ],
184 | ],
185 | ]
186 | ]);
187 | }
188 |
189 | /**
190 | * @group udp
191 | */
192 | public function testFillWithGlobalTags()
193 | {
194 | $options = (new Options())->setTags(["dc" => "eu-west"]);
195 | $adapter = $this->getMockBuilder("InfluxDB\\Adapter\\Udp\\Writer")
196 | ->setConstructorArgs([$options])
197 | ->setMethods(["write"])
198 | ->getMock();
199 |
200 | $adapter->expects($this->once())
201 | ->method("write")
202 | ->with($this->matchesRegularExpression("/mem,dc=eu-west free=712423 \d+/i"));
203 |
204 | $adapter->send([
205 | "points" => [
206 | [
207 | "measurement" => "mem",
208 | "fields" => [
209 | "free" => 712423.,
210 | ],
211 | ],
212 | ]
213 | ]);
214 | }
215 |
216 | /**
217 | * @group udp
218 | */
219 | public function testMergeGlobalTags()
220 | {
221 | $options = (new Options())
222 | ->setTags(["dc" => "eu-west"]);
223 | $adapter = $this->getMockBuilder("InfluxDB\\Adapter\\Udp\\Writer")
224 | ->setConstructorArgs([$options])
225 | ->setMethods(["write", "generateTimeInNanoSeconds"])
226 | ->getMock();
227 |
228 | $adapter->expects($this->any())
229 | ->method("generateTimeInNanoSeconds")
230 | ->will($this->returnValue(1245));
231 |
232 | $adapter->expects($this->once())
233 | ->method("write")
234 | ->with($this->matchesRegularExpression(<<send([
240 | "tags" => [
241 | "region" => "eu-west-1",
242 | ],
243 | "points" => [
244 | [
245 | "measurement" => "mem",
246 | "fields" => [
247 | "free" => 712423.,
248 | ],
249 | ],
250 | ]
251 | ]);
252 | }
253 |
254 | /**
255 | * @group udp
256 | */
257 | public function testMergeFullTagsPositions()
258 | {
259 | $options = (new Options())
260 | ->setTags(["dc" => "eu-west"]);
261 | $adapter = $this->getMockBuilder("InfluxDB\\Adapter\\Udp\\Writer")
262 | ->setConstructorArgs([$options])
263 | ->setMethods(["write", "generateTimeInNanoSeconds"])
264 | ->getMock();
265 |
266 | $adapter->expects($this->any())
267 | ->method("generateTimeInNanoSeconds")
268 | ->will($this->returnValue(1245));
269 |
270 | $adapter->expects($this->once())
271 | ->method("write")
272 | ->with($this->matchesRegularExpression(<<send([
278 | "tags" => [
279 | "region" => "eu-west-1",
280 | ],
281 | "points" => [
282 | [
283 | "measurement" => "mem",
284 | "tags" => [
285 | "location" => "ireland",
286 | ],
287 | "fields" => [
288 | "free" => 712423.,
289 | ],
290 | ],
291 | ]
292 | ]);
293 | }
294 |
295 | /**
296 | * @dataProvider getMessagesWithIntegers
297 | */
298 | public function testWithIntegers($input, $response)
299 | {
300 | $options = new Options();
301 |
302 | $object = $this->getMockBuilder("InfluxDB\Adapter\Udp\Writer")
303 | ->setConstructorArgs([$options])
304 | ->setMethods(["write"])
305 | ->getMock();
306 | $object->expects($this->once())
307 | ->method("write")
308 | ->with($response);
309 |
310 | $object->send($input);
311 | }
312 |
313 | public function getMessagesWithIntegers()
314 | {
315 | return [
316 | [
317 | [
318 | "time" => "2009-11-10T23:00:00Z",
319 | "points" => [
320 | [
321 | "measurement" => "cpu",
322 | "fields" => [
323 | "value" => 1,
324 | ],
325 | ],
326 | ],
327 | ],
328 | "cpu value=1i 1257894000000000000"
329 | ],
330 | [
331 | [
332 | "time" => "2009-11-10T23:00:00Z",
333 | "points" => [
334 | [
335 | "measurement" => "cpu",
336 | "fields" => [
337 | "value" => 1,
338 | "string" => "escape",
339 | ],
340 | ],
341 | ],
342 | ],
343 | "cpu value=1i,string=\"escape\" 1257894000000000000"
344 | ],
345 | [
346 | [
347 | "tags" => [
348 | "region" => "us-west",
349 | "host" => "serverA",
350 | "env" => "prod",
351 | "target" => "servers",
352 | "zone" => "1c",
353 | ],
354 | "time" => "2009-11-10T23:00:00Z",
355 | "points" => [
356 | [
357 | "measurement" => "cpu",
358 | "fields" => [
359 | "cpu" => 18.12,
360 | "free" => 712432,
361 | ],
362 | ],
363 | ],
364 | ],
365 | "cpu,region=us-west,host=serverA,env=prod,target=servers,zone=1c cpu=18.12,free=712432i 1257894000000000000"
366 | ],
367 | [
368 | [
369 | "tags" => [
370 | "region" => "us-west",
371 | "host" => "serverA",
372 | "env" => "prod",
373 | "target" => "servers",
374 | "zone" => "1c",
375 | ],
376 | "time" => "2009-11-10T23:00:00Z",
377 | "points" => [
378 | [
379 | "measurement" => "cpu",
380 | "fields" => [
381 | "cpu" => 18.12,
382 | ],
383 | ],
384 | [
385 | "measurement" => "mem",
386 | "fields" => [
387 | "free" => 712432,
388 | ],
389 | ],
390 | ],
391 | ],
392 | <<getMockBuilder("InfluxDB\\Adapter\\WriterTrait")
16 | ->getMockForTrait();
17 |
18 | $method = new ReflectionMethod(get_class($helper), "pointsToString");
19 | $method->setAccessible(true);
20 |
21 | $this->assertEquals($result, $method->invokeArgs($helper, [$message]));
22 | }
23 |
24 | public function getElements()
25 | {
26 | return [
27 | [["one" => "two"], "one=\"two\""],
28 | [["one with space" => "two"], "one\\ with\\ space=\"two\""],
29 | [["one with,comma" => "two"], "one\\ with\\,comma=\"two\""],
30 | [["one" => "two", "three" => "four"], "one=\"two\",three=\"four\""],
31 | [["one" => true, "three" => false], "one=true,three=false"],
32 | [["one" => true, "three" => 0., "four" => 1.], "one=true,three=0,four=1"],
33 | [["one" => true, "three" => false], "one=true,three=false"],
34 | [["one" => true, "three" => 0, "four" => 1], "one=true,three=0i,four=1i"],
35 | [["one" => 12, "three" => 14], "one=12i,three=14i"],
36 | [["one" => 12.1, "three" => 14], "one=12.1,three=14i"],
37 | [["one" => 12., "three" => 14], "one=12,three=14i"],
38 | [["one" => (double)12, "three" => 14], "one=12,three=14i"],
39 | [["one" => (double)12, "three" => (double)14], "one=12,three=14"],
40 | [["one" => (double)"12", "three" => (int)"14"], "one=12,three=14i"],
41 | [["one" => (double)"12", "three" => new IntType("14")], "one=12,three=14i"],
42 | [["one" => (double)"12", "three" => new IntType(14.12)], "one=12,three=14i"],
43 | [["one" => (double)"12", "three" => new IntType(14)], "one=12,three=14i"],
44 | [["one" => (double)"12", "three" => new FloatType(14)], "one=12,three=14"],
45 | [["one" => (double)"12", "three" => new FloatType("14")], "one=12,three=14"],
46 | [["one" => (double)"12", "three" => new FloatType("14.123")], "one=12,three=14.123"],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/unit/ClientTest.php:
--------------------------------------------------------------------------------
1 | prophesize("InfluxDB\\Adapter\\QueryableInterface");
16 | $writer = $this->prophesize("InfluxDB\\Adapter\\WritableInterface");
17 | $writer->send([
18 | "points" => [
19 | [
20 | "measurement" => "tcp.test",
21 | "fields" => [
22 | "mark" => "element"
23 | ]
24 | ]
25 | ]
26 | ])->shouldBeCalledTimes(1);
27 |
28 | $object = new Client($reader->reveal(), $writer->reveal());
29 | $object->mark("tcp.test", ["mark" => "element"]);
30 | }
31 |
32 | public function testWriteDirectMessages()
33 | {
34 | $reader = $this->prophesize("InfluxDB\\Adapter\\QueryableInterface");
35 | $writer = $this->prophesize("InfluxDB\\Adapter\\WritableInterface");
36 | $writer->send([
37 | "tags" => [
38 | "dc" => "eu-west-1",
39 | ],
40 | "points" => [
41 | [
42 | "measurement" => "vm-serie",
43 | "fields" => [
44 | "cpu" => 18.12,
45 | "free" => 712423,
46 | ]
47 | ]
48 | ]
49 | ])->shouldBeCalledTimes(1);
50 | $object = new Client($reader->reveal(), $writer->reveal());
51 |
52 | $object->mark([
53 | "tags" => [
54 | "dc" => "eu-west-1",
55 | ],
56 | "points" => [
57 | [
58 | "measurement" => "vm-serie",
59 | "fields" => [
60 | "cpu" => 18.12,
61 | "free" => 712423,
62 | ],
63 | ],
64 | ]
65 | ]);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/unit/ManagerTest.php:
--------------------------------------------------------------------------------
1 | prophesize("InfluxDB\Client");
11 | $client->query("CREATE DATABASE mydb")->shouldBeCalledTimes(1);
12 |
13 | $manager = new Manager($client->reveal());
14 | $manager->addQuery("createDatabase", function($name) {
15 | return "CREATE DATABASE {$name}";
16 | });
17 |
18 | $manager->createDatabase("mydb");
19 | }
20 |
21 | public function testQueryCommandReturnsTheCommandData()
22 | {
23 | $client = $this->prophesize("InfluxDB\Client");
24 | $client->query(Argument::Any())->willReturn("OK");
25 |
26 | $manager = new Manager($client->reveal());
27 | $manager->addQuery("anything", function() {});
28 |
29 | $data = $manager->anything();
30 | $this->assertEquals("OK", $data);
31 | }
32 |
33 | public function testInvokableCommands()
34 | {
35 | $client = $this->prophesize("InfluxDB\Client");
36 | $client->query("CREATE DATABASE mydb")->shouldBeCalledTimes(1);
37 |
38 | $manager = new Manager($client->reveal());
39 | $manager->addQuery(new CreateDatabaseMock());
40 |
41 | $manager->createDatabase("mydb");
42 | }
43 |
44 | /**
45 | * @expectedException InvalidArgumentException
46 | */
47 | public function testNotCallableMethods()
48 | {
49 | $client = $this->prophesize("InfluxDB\Client");
50 |
51 | $manager = new Manager($client->reveal());
52 | $manager->addQuery(new NotCallable());
53 | }
54 |
55 | /**
56 | * @expectedException InvalidArgumentException
57 | */
58 | public function testClassWithoutNameException()
59 | {
60 | $client = $this->prophesize("InfluxDB\Client");
61 |
62 | $manager = new Manager($client->reveal());
63 | $manager->addQuery(new NoName());
64 | }
65 |
66 | public function testFallbackToClientMethods()
67 | {
68 | $client = $this->prophesize("InfluxDB\Client");
69 | $client->mark("hello", ["data" => true])->shouldBeCalledTimes(1);
70 |
71 | $manager = new Manager($client->reveal());
72 | $manager->mark("hello", ["data" => true]);
73 | }
74 |
75 | /**
76 | * @expectedException RuntimeException
77 | * @expectedExceptionMessage The method you are using is not allowed: 'missingMethod', do you have to add it with 'addQuery'
78 | */
79 | public function testCallMissingMethod()
80 | {
81 | $client = $this->prophesize("InfluxDB\Client");
82 | $manager = new Manager($client->reveal());
83 | $manager->missingMethod();
84 | }
85 | }
86 |
87 | class NoName
88 | {
89 | public function __invoke($args)
90 | {
91 | return "TEST";
92 | }
93 | }
94 |
95 | class NotCallable
96 | {
97 | public function __toString()
98 | {
99 | return "hello";
100 | }
101 | }
102 |
103 | class CreateDatabaseMock
104 | {
105 | public function __invoke($name)
106 | {
107 | return "CREATE DATABASE {$name}";
108 | }
109 |
110 | public function __toString()
111 | {
112 | return "createDatabase";
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tests/unit/Query/CreateDatabaseTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($query, $res);
15 | }
16 |
17 | public function queries()
18 | {
19 | return [
20 | ["mydb", 'CREATE DATABASE "mydb"'],
21 | ['my"db"', 'CREATE DATABASE "my\"db\""'],
22 | ["my'db'", "CREATE DATABASE \"my\'db\'\""],
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/unit/Query/DeleteDatabaseTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($query, $res);
15 | }
16 |
17 | public function queries()
18 | {
19 | return [
20 | ["mydb", 'DROP DATABASE "mydb"'],
21 | ['my"db"', 'DROP DATABASE "my\"db\""'],
22 | ["my'db'", "DROP DATABASE \"my\'db\'\""],
23 | ];
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/tests/unit/Query/GetDatabasesTest.php:
--------------------------------------------------------------------------------
1 | assertEquals("show databases", $res);
12 | }
13 | }
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/unit/Type/BoolTypeTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($out, new BoolType($in));
12 | }
13 |
14 | public function boolProvider()
15 | {
16 | return [
17 | [true, "true"],
18 | ["1", "true"],
19 | [1, "true"],
20 | ["something", "true"],
21 | [12, "true"],
22 |
23 | [false, "false"],
24 | ["0", "false"],
25 | [0, "false"],
26 | [null, "false"],
27 | ];
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/tests/unit/Type/FloatTypeTest.php:
--------------------------------------------------------------------------------
1 | assertSame($out, (string)$in);
13 | }
14 |
15 | public function floatProvider()
16 | {
17 | return [
18 | [12.12, "12.12"],
19 | ["12.12", "12.12"],
20 | ["12", "12"],
21 | [12, "12"],
22 | [new FloatType("12.12"), "12.12"],
23 | [new FloatType(12.12), "12.12"],
24 | ["invalid", "0"],
25 | [null, "0"],
26 | [new FloatType("invalid"), "0"],
27 | [new FloatType(null), "0"],
28 | [true, "1"],
29 | [false, "0"],
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/unit/Type/IntTypeTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($out, new IntType($in));
12 | }
13 |
14 | public function intProvider()
15 | {
16 | return [
17 | ["12", "12i"],
18 | [12, "12i"],
19 | [12.12, "12i"],
20 | [new IntType(12.12), "12i"],
21 | [new IntType("12.12"), "12i"],
22 | ["invalid", "0i"],
23 | [null, "0i"],
24 | [new IntType("invalid"), "0i"],
25 | [new IntType(null), "0i"],
26 | [true, "1i"],
27 | [false, "0i"],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/unit/Type/StringTypeTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($out, new StringType($in));
12 | }
13 |
14 | public function stringProvider()
15 | {
16 | return [
17 | [true, '"1"'],
18 | ["walter", '"walter"'],
19 | ["12", '"12"'],
20 | ["12.153", '"12.153"'],
21 | [12.153, '"12.153"'],
22 | [12, '"12"'],
23 | ];
24 | }
25 | }
26 |
27 |
28 |
--------------------------------------------------------------------------------