The official Ruby client library for InfluxDB. Maintained by @toddboom and @dmke.
- Platform support
- Ruby support
- Installation
- Usage
- Advanced Topics
- List of configuration options
- Testing
- Contributing
Support for InfluxDB v0.8.x is now deprecated. The final version of this library that will support the older InfluxDB interface is
v0.1.9
, which is available as a gem and tagged on this repository.If you're reading this message, then you should only expect support for InfluxDB v0.9.1 and higher.
Since v0.4.0, this gem requires Ruby >= 2.2.0. Support for MRI < 2.2 is still available in the v0.3.x series, see stable-03 branch for documentation.
$ [sudo] gem install influxdb
Or add it to your Gemfile
, and run bundle install
.
All examples assume you have a require "influxdb"
in your code.
Connecting to a single host:
influxdb = InfluxDB::Client.new # default connects to localhost:8086
# or
influxdb = InfluxDB::Client.new host: "influxdb.domain.com"
Connecting to multiple hosts (with built-in load balancing and failover):
influxdb = InfluxDB::Client.new hosts: ["influxdb1.domain.com", "influxdb2.domain.com"]
You can also provide a URL to connect to your server. This is particulary useful for 12-factor apps, i.e. you can put the configuration in an environment variable:
url = ENV["INFLUXDB_URL"] || "https://influxdb.example.com:8086/database_name?retry=3"
influxdb = InfluxDB::Client.new url: url
Please note, that the config options found in the URL have a lower precedence than those explicitly given in the options hash. This means, that the following sample will use an open-timeout of 10 seconds:
url = "https://influxdb.example.com:8086/database_name?open_timeout=3"
influxdb = InfluxDB::Client.new url: url, open_timeout: 10
Write some data:
username = 'foo'
password = 'bar'
database = 'site_development'
name = 'foobar'
influxdb = InfluxDB::Client.new database, username: username, password: password
# Enumerator that emits a sine wave
Value = (0..360).to_a.map {|i| Math.send(:sin, i / 10.0) * 10 }.each
loop do
data = {
values: { value: Value.next },
tags: { wave: 'sine' } # tags are optional
}
influxdb.write_point(name, data)
sleep 1
end
Write data with time precision (precision can be set in 2 ways):
username = 'foo'
password = 'bar'
database = 'site_development'
name = 'foobar'
time_precision = 's'
# either in the client initialization:
influxdb = InfluxDB::Client.new database,
username: username,
password: password,
time_precision: time_precision
data = {
values: { value: 0 },
timestamp: Time.now.to_i # timestamp is optional, if not provided point will be saved with current time
}
influxdb.write_point(name, data)
# or in a method call:
influxdb.write_point(name, data, time_precision)
The default precision in this gem is "s"
(second), as Ruby's Time#to_i
operates on this resolution.
If you write data points with sub-second resolution, you have to configure
your client instance with a more granular time_precision
option and you
need to provide timestamp values which reflect this precision. If you don't do
this, your points will be squashed!
A point is uniquely identified by the measurement name, tag set, and timestamp. If you submit a new point with the same measurement, tag set, and timestamp as an existing point, the field set becomes the union of the old field set and the new field set, where any ties go to the new field set. This is the intended behavior.
See [How does InfluxDB handle duplicate points?][docs-faq] for details.
For example, this is how to specify millisecond precision (which moves the pitfall from the second- to the millisecond barrier):
influxdb = InfluxDB::Client.new(time_precision: "ms")
time = (Time.now.to_r * 1000).to_i
# A faster, albeit less readable alternative:
# time = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
influxdb.write_point("foobar", { values: { n: 42 }, timestamp: time })
Allowed values for time_precision
are:
"ns"
ornil
for nanosecond"u"
for microsecond"ms"
for millisecond"s"
for second"m"
for minute"h"
for hour
Write data with a specific retention policy:
database = 'site_development'
name = 'foobar'
precision = 's'
retention = '1h.cpu'
influxdb = InfluxDB::Client.new database,
username: "foo",
password: "bar"
data = {
values: { value: 0 },
tags: { foo: 'bar', bar: 'baz' },
timestamp: Time.now.to_i
}
influxdb.write_point(name, data, precision, retention)
Write data while choosing the database:
database = 'site_development'
name = 'foobar'
precision = 's'
retention = '1h.cpu'
influxdb = InfluxDB::Client.new {
username: "foo",
password: "bar"
}
data = {
values: { value: 0 },
tags: { foo: 'bar', bar: 'baz' }
timestamp: Time.now.to_i
}
influxdb.write_point(name, data, precision, retention, database)
Write multiple points in a batch (performance boost):
data = [
{
series: 'cpu',
tags: { host: 'server_1', region: 'us' },
values: { internal: 5, external: 0.453345 }
},
{
series: 'gpu',
values: { value: 0.9999 },
}
]
influxdb.write_points(data)
# you can also specify precision in method call
precision = 'm'
influxdb.write_points(data, precision)
Write multiple points in a batch with a specific retention policy:
data = [
{
series: 'cpu',
tags: { host: 'server_1', region: 'us' },
values: { internal: 5, external: 0.453345 }
},
{
series: 'gpu',
values: { value: 0.9999 },
}
]
precision = 'm'
retention = '1h.cpu'
influxdb.write_points(data, precision, retention)
Write asynchronously:
database = 'site_development'
name = 'foobar'
influxdb = InfluxDB::Client.new database,
username: "foo",
password: "bar",
async: true
data = {
values: { value: 0 },
tags: { foo: 'bar', bar: 'baz' },
timestamp: Time.now.to_i
}
influxdb.write_point(name, data)
Using async: true
is a shortcut for the following:
async_options = {
# number of points to write to the server at once
max_post_points: 1000,
# queue capacity
max_queue_size: 10_000,
# number of threads
num_worker_threads: 3,
# max. time (in seconds) a thread sleeps before
# checking if there are new jobs in the queue
sleep_interval: 5,
# whether client will block if queue is full
block_on_full_queue: false
}
influxdb = InfluxDB::Client.new database, async: async_options
Write data via UDP (note that a retention policy cannot be specified for UDP writes):
influxdb = InfluxDB::Client.new udp: { host: "127.0.0.1", port: 4444 }
name = 'hitchhiker'
data = {
values: { value: 666 },
tags: { foo: 'bar', bar: 'baz' }
}
influxdb.write_point(name, data)
Discard write errors:
influxdb = InfluxDB::Client.new(
udp: { host: "127.0.0.1", port: 4444 },
discard_write_errors: true
)
influxdb.write_point('hitchhiker', { values: { value: 666 } })
database = 'site_development'
influxdb = InfluxDB::Client.new database,
username: "foo",
password: "bar"
# without a block:
influxdb.query 'select * from time_series_1 group by region'
# results are grouped by name, but also their tags:
#
# [
# {
# "name"=>"time_series_1",
# "tags"=>{"region"=>"uk"},
# "values"=>[
# {"time"=>"2015-07-09T09:03:31Z", "count"=>32, "value"=>0.9673},
# {"time"=>"2015-07-09T09:03:49Z", "count"=>122, "value"=>0.4444}
# ]
# },
# {
# "name"=>"time_series_1",
# "tags"=>{"region"=>"us"},
# "values"=>[
# {"time"=>"2015-07-09T09:02:54Z", "count"=>55, "value"=>0.4343}
# ]
# }
# ]
# with a block:
influxdb.query 'select * from time_series_1 group by region' do |name, tags, points|
printf "%s [ %p ]\n", name, tags
points.each do |pt|
printf " -> %p\n", pt
end
end
# result:
# time_series_1 [ {"region"=>"uk"} ]
# -> {"time"=>"2015-07-09T09:03:31Z", "count"=>32, "value"=>0.9673}
# -> {"time"=>"2015-07-09T09:03:49Z", "count"=>122, "value"=>0.4444}]
# time_series_1 [ {"region"=>"us"} ]
# -> {"time"=>"2015-07-09T09:02:54Z", "count"=>55, "value"=>0.4343}
If you would rather receive points with integer timestamp, it's possible to set
epoch
parameter:
# globally, on client initialization:
influxdb = InfluxDB::Client.new database, epoch: 's'
influxdb.query 'select * from time_series group by region'
# [
# {
# "name"=>"time_series",
# "tags"=>{"region"=>"uk"},
# "values"=>[
# {"time"=>1438411376, "count"=>32, "value"=>0.9673}
# ]
# }
# ]
# or for a specific query call:
influxdb.query 'select * from time_series group by region', epoch: 'ms'
# [
# {
# "name"=>"time_series",
# "tags"=>{"region"=>"uk"},
# "values"=>[
# {"time"=>1438411376000, "count"=>32, "value"=>0.9673}
# ]
# }
# ]
Working with parameterized query strings works as expected:
influxdb = InfluxDB::Client.new database
named_parameter_query = "select * from time_series_0 where time > %{min_time}"
influxdb.query named_parameter_query, params: { min_time: 0 }
# compiles to:
# select * from time_series_0 where time > 0
positional_params_query = "select * from time_series_0 where f = %{1} and i < %{2}"
influxdb.query positional_params_query, params: ["foobar", 42]
# compiles to (note the automatic escaping):
# select * from time_series_0 where f = 'foobar' and i < 42
Create a database:
database = 'site_development'
influxdb.create_database(database)
Delete a database:
database = 'site_development'
influxdb.delete_database(database)
List databases:
influxdb.list_databases
Create a user for a database:
database = 'site_development'
new_username = 'foo'
new_password = 'bar'
permission = :write
# with all permissions
influxdb.create_database_user(database, new_username, new_password)
# with specified permission - options are: :read, :write, :all
influxdb.create_database_user(database, new_username, new_password, permissions: permission)
Update a user password:
username = 'foo'
new_password = 'bar'
influxdb.update_user_password(username, new_password)
Grant user privileges on database:
username = 'foobar'
database = 'foo'
permission = :read # options are :read, :write, :all
influxdb.grant_user_privileges(username, database, permission)
Revoke user privileges from database:
username = 'foobar'
database = 'foo'
permission = :write # options are :read, :write, :all
influxdb.revoke_user_privileges(username, database, permission)
Delete a user:
username = 'foobar'
influxdb.delete_user(username)
List users:
influxdb.list_users
Create cluster admin:
username = 'foobar'
password = 'pwd'
influxdb.create_cluster_admin(username, password)
List cluster admins:
influxdb.list_cluster_admins
Revoke cluster admin privileges from user:
username = 'foobar'
influxdb.revoke_cluster_admin_privileges(username)
List continuous queries of a database:
database = 'foo'
influxdb.list_continuous_queries(database)
Create a continuous query for a database:
database = 'foo'
name = 'clicks_count'
query = 'SELECT COUNT(name) INTO clicksCount_1h FROM clicks GROUP BY time(1h)'
influxdb.create_continuous_query(name, database, query)
Additionally, you can specify the resample interval and the time range over which the CQ runs:
influxdb.create_continuous_query(name, database, query, resample_every: "10m", resample_for: "65m")
Delete a continuous query from a database:
database = 'foo'
name = 'clicks_count'
influxdb.delete_continuous_query(name, database)
List retention policies of a database:
database = 'foo'
influxdb.list_retention_policies(database)
Create a retention policy for a database:
database = 'foo'
name = '1h.cpu'
duration = '10m'
replication = 2
influxdb.create_retention_policy(name, database, duration, replication)
Delete a retention policy from a database:
database = 'foo'
name = '1h.cpu'
influxdb.delete_retention_policy(name, database)
Alter a retention policy for a database:
database = 'foo'
name = '1h.cpu'
duration = '10m'
replication = 2
influxdb.alter_retention_policy(name, database, duration, replication)
By default, InfluxDB::Client will denormalize points (received from InfluxDB as
columns and rows). If you want to get raw data add denormalize: false
to
the initialization options or to query itself:
influxdb.query 'select * from time_series_1 group by region', denormalize: false
# [
# {
# "name"=>"time_series_1",
# "tags"=>{"region"=>"uk"},
# "columns"=>["time", "count", "value"],
# "values"=>[
# ["2015-07-09T09:03:31Z", 32, 0.9673],
# ["2015-07-09T09:03:49Z", 122, 0.4444]
# ]
# },
# {
# "name"=>"time_series_1",
# "tags"=>{"region"=>"us"},
# "columns"=>["time", "count", "value"],
# "values"=>[
# ["2015-07-09T09:02:54Z", 55, 0.4343]
# ]
# }
# ]
influxdb.query 'select * from time_series_1 group by region', denormalize: false do |name, tags, points|
printf "%s [ %p ]\n", name, tags
points.each do |key, values|
printf " %p -> %p\n", key, values
end
end
# time_series_1 [ {"region"=>"uk"} ]
# columns -> ["time", "count", "value"]
# values -> [["2015-07-09T09:03:31Z", 32, 0.9673], ["2015-07-09T09:03:49Z", 122, 0.4444]]}
# time_series_1 [ {"region"=>"us"} ]
# columns -> ["time", "count", "value"]
# values -> [["2015-07-09T09:02:54Z", 55, 0.4343]]}
You can also pick the database to query from:
influxdb.query 'select * from time_series_1', database: 'database'
If you expect large quantities of data in a response, you may want to enable
JSON streaming by setting a chunk_size
:
influxdb = InfluxDB::Client.new database,
username: username,
password: password,
chunk_size: 10000
See the [official documentation][docs-chunking] for more details.
By default, InfluxDB::Client will keep trying (with exponential fall-off) to
connect to the database until it gets a connection. If you want to retry only
a finite number of times (or disable retries altogether), you can pass the
:retry
option.
:retry
can be either true
, false
or an Integer
to retry infinite times,
disable retries or retry a finite number of times, respectively. Passing 0
is
equivalent to false
and -1
is equivalent to true
.
$ irb -r influxdb
> influxdb = InfluxDB::Client.new 'database', retry: 8
=> #<InfluxDB::Client:0x00000002bb5ce0 ...>
> influxdb.query 'select * from serie limit 1'
E, [2016-08-31T23:55:18.287947 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.01s.
E, [2016-08-31T23:55:18.298455 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.02s.
E, [2016-08-31T23:55:18.319122 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.04s.
E, [2016-08-31T23:55:18.359785 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.08s.
E, [2016-08-31T23:55:18.440422 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.16s.
E, [2016-08-31T23:55:18.600936 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.32s.
E, [2016-08-31T23:55:18.921740 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 0.64s.
E, [2016-08-31T23:55:19.562428 #23476] WARN -- InfluxDB: Failed to contact host localhost: #<Errno::ECONNREFUSED: Failed to open TCP connection to localhost:8086 (Connection refused - connect(2) for "localhost" port 8086)> - retrying in 1.28s.
InfluxDB::ConnectionError: Tried 8 times to reconnect but failed.
This index might be out of date. Please refer to InfluxDB::DEFAULT_CONFIG_OPTIONS
,
found in lib/influxdb/config.rb
for the source of truth.
Category | Option | Default value | Notes |
---|---|---|---|
HTTP connection | :host or :hosts |
"localhost" | can be an array and can include port |
:port |
8086 | fallback port, unless provided by :host option |
|
:prefix |
"" | URL path prefix (e.g. server is behind reverse proxy) | |
:username |
"root" | user credentials | |
:password |
"root" | user credentials | |
:open_timeout |
5 | socket timeout | |
:read_timeout |
300 | socket timeout | |
:auth_method |
"params" | "params", "basic_auth" or "none" | |
Retry | :retry |
-1 | max. number of retry attempts (reading and writing) |
:initial_delay |
0.01 | initial wait time (doubles every retry attempt) | |
:max_delay |
30 | max. wait time when retrying | |
SSL/HTTPS | :use_ssl |
false | whether or not to use SSL (HTTPS) |
:verify_ssl |
true | verify vertificate when using SSL | |
:ssl_ca_cert |
false | path to or name of CA cert | |
Database | :database |
empty | name of database |
:time_precision |
"s" | time resolution for data send to server | |
:epoch |
false | time resolution for server responses (false = server default) | |
Writer | :async |
false | Async options hash, details here |
:udp |
false | UDP connection info, details here | |
:discard_write_errors |
false | suppress UDP socket errors | |
Query | :chunk_size |
empty | details here |
:denormalize |
true | format of result |
git clone git@github.com:influxdata/influxdb-ruby.git
cd influxdb-ruby
bundle
bundle exec rake
- Fork this repository on GitHub.
- Make your changes.
- Add tests.
- Add an entry in the
CHANGELOG.md
in the "unreleased" section on top.
- Run the tests:
bundle exec rake
. - Send a pull request.
- Please rebase against the master branch.
- If your changes look good, we'll merge them.