prometheus-client 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +83 -6
- data/lib/prometheus/client/counter.rb +7 -4
- data/lib/prometheus/client/gauge.rb +5 -0
- data/lib/prometheus/client/metric.rb +12 -19
- data/lib/prometheus/client/rack/collector.rb +31 -5
- data/lib/prometheus/client/rack/exporter.rb +6 -8
- data/lib/prometheus/client/registry.rb +5 -0
- data/lib/prometheus/client/summary.rb +36 -0
- data/lib/prometheus/client/version.rb +1 -1
- metadata +20 -8
- checksums.yaml +0 -15
- data/lib/prometheus/client/histogram.rb +0 -19
- data/lib/prometheus/client/histogram/bucket.rb +0 -19
data/README.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
# Prometheus Ruby Client
|
2
2
|
|
3
|
+
A suite of instrumentation metric primitives for Ruby that can be exposed
|
4
|
+
through a JSON web services interface. Intended to be used together with a
|
5
|
+
[Prometheus server][1].
|
6
|
+
|
3
7
|
## Usage
|
4
8
|
|
9
|
+
### Library
|
10
|
+
|
5
11
|
```ruby
|
6
12
|
require 'prometheus/client'
|
7
13
|
|
@@ -10,14 +16,40 @@ prometheus = Prometheus::Client.registry
|
|
10
16
|
|
11
17
|
# create a new counter metric
|
12
18
|
http_requests = Prometheus::Client::Counter.new
|
13
|
-
|
14
19
|
# register the metric
|
15
|
-
prometheus.register(:http_requests, 'A counter of
|
20
|
+
prometheus.register(:http_requests, 'A counter of HTTP requests made', http_requests)
|
21
|
+
|
22
|
+
# equivalent helper function
|
23
|
+
http_requests = prometheus.counter(:http_requests, 'A counter of HTTP requests made')
|
16
24
|
|
17
25
|
# start using the counter
|
18
26
|
http_requests.increment
|
19
27
|
```
|
20
28
|
|
29
|
+
### Rack middleware
|
30
|
+
|
31
|
+
There are two [Rack][2] middlewares available, one to expose a metrics HTTP
|
32
|
+
endpoint to be scraped by a prometheus server and one to trace all HTTP
|
33
|
+
requests.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# config.ru
|
37
|
+
|
38
|
+
require 'rack'
|
39
|
+
require 'prometheus/client/rack/collector'
|
40
|
+
require 'prometheus/client/rack/exporter'
|
41
|
+
|
42
|
+
use Prometheus::Client::Rack::Collector
|
43
|
+
use Prometheus::Client::Rack::Exporter
|
44
|
+
run lambda { |env| [200, {'Content-Type' => 'text/html'}, ['OK']] }
|
45
|
+
```
|
46
|
+
|
47
|
+
Start the server and have a look at the metrics endpoint:
|
48
|
+
[http://localhost:5000/metrics](http://localhost:5000/metrics).
|
49
|
+
|
50
|
+
For further instructions and other scripts to get started, have a look at the
|
51
|
+
integrated [example application](examples/rack/README.md).
|
52
|
+
|
21
53
|
## Metrics
|
22
54
|
|
23
55
|
The following metric types are currently supported.
|
@@ -26,21 +58,64 @@ The following metric types are currently supported.
|
|
26
58
|
|
27
59
|
A Counter is a metric that exposes merely a sum or tally of things.
|
28
60
|
|
61
|
+
```ruby
|
62
|
+
counter = Prometheus::Client::Counter.new
|
63
|
+
|
64
|
+
# increment the counter for a given label set
|
65
|
+
counter.increment(service: 'foo')
|
66
|
+
|
67
|
+
# increment by a given value
|
68
|
+
counter.increment({ service: 'bar' }, 5)
|
69
|
+
|
70
|
+
# decrement the counter
|
71
|
+
counter.decrement(service: 'exceptional')
|
72
|
+
|
73
|
+
# get current value for a given label set
|
74
|
+
counter.get(service: 'bar')
|
75
|
+
# => 5
|
76
|
+
```
|
77
|
+
|
29
78
|
### Gauge
|
30
79
|
|
31
80
|
A Gauge is a metric that exposes merely an instantaneous value or some
|
32
81
|
snapshot thereof.
|
33
82
|
|
83
|
+
```ruby
|
84
|
+
gauge = Prometheus::Client::Gauge.new
|
85
|
+
|
86
|
+
# set a value
|
87
|
+
gauge.set({ role: 'base' }, 'up')
|
88
|
+
|
89
|
+
# retrieve the current value for a given label set
|
90
|
+
gauge.get({ role: 'problematic' })
|
91
|
+
# => 'down'
|
92
|
+
```
|
93
|
+
|
94
|
+
### Summary
|
95
|
+
|
96
|
+
The Summary is an accumulator for samples. It captures Numeric data and provides
|
97
|
+
an efficient percentile calculation mechanism.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
summary = Prometheus::Client::Summary.new
|
101
|
+
|
102
|
+
# record a value
|
103
|
+
summary.add({ service: 'slow' }, Benchmark.realtime { service.call(arg) })
|
104
|
+
|
105
|
+
# retrieve the current quantile values
|
106
|
+
summary.get({ service: 'database' })
|
107
|
+
# => { 0.5: 1.233122, 0.9: 83.4323, 0.99: 341.3428231 }
|
108
|
+
```
|
109
|
+
|
34
110
|
## Todo
|
35
111
|
|
36
|
-
* add histogram support
|
37
112
|
* add push support to a vanilla prometheus exporter
|
38
|
-
* add tests for Rack middlewares
|
39
113
|
* use a more performant JSON library
|
114
|
+
* add protobuf support
|
40
115
|
|
41
116
|
## Tests
|
42
117
|
|
43
|
-
[![Build Status][
|
118
|
+
[![Build Status][3]](http://travis-ci.org/prometheus/client_ruby)
|
44
119
|
|
45
120
|
Install necessary development gems with `bundle install` and run tests with
|
46
121
|
rspec:
|
@@ -49,4 +124,6 @@ rspec:
|
|
49
124
|
rspec
|
50
125
|
```
|
51
126
|
|
52
|
-
[1]: https://
|
127
|
+
[1]: https://github.com/prometheus/prometheus
|
128
|
+
[2]: http://rack.github.io/
|
129
|
+
[3]: https://secure.travis-ci.org/prometheus/client_ruby.png?branch=master
|
@@ -3,10 +3,6 @@ require 'prometheus/client/metric'
|
|
3
3
|
module Prometheus
|
4
4
|
module Client
|
5
5
|
class Counter < Metric
|
6
|
-
def default
|
7
|
-
0
|
8
|
-
end
|
9
|
-
|
10
6
|
def type
|
11
7
|
:counter
|
12
8
|
end
|
@@ -19,6 +15,13 @@ module Prometheus
|
|
19
15
|
def decrement(labels = {}, by = 1)
|
20
16
|
increment(labels, -by)
|
21
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def default
|
22
|
+
0
|
23
|
+
end
|
24
|
+
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
@@ -7,12 +7,7 @@ module Prometheus
|
|
7
7
|
class Metric
|
8
8
|
def initialize
|
9
9
|
@mutex = Mutex.new
|
10
|
-
@values = Hash.new
|
11
|
-
end
|
12
|
-
|
13
|
-
# Default value
|
14
|
-
def default
|
15
|
-
nil
|
10
|
+
@values = Hash.new { |hash, key| hash[key] = default }
|
16
11
|
end
|
17
12
|
|
18
13
|
# Returns the metric type
|
@@ -20,23 +15,11 @@ module Prometheus
|
|
20
15
|
raise NotImplementedError
|
21
16
|
end
|
22
17
|
|
23
|
-
# Returns all values
|
24
|
-
def value
|
25
|
-
@values.map do |labels, value|
|
26
|
-
{ :labels => labels, :value => value }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
18
|
# Returns the value for the given label set
|
31
19
|
def get(labels = {})
|
32
20
|
@values[label_set_for(labels)]
|
33
21
|
end
|
34
22
|
|
35
|
-
# Sets the value for the given label set
|
36
|
-
def set(labels, value)
|
37
|
-
@values[label_set_for(labels)] = value
|
38
|
-
end
|
39
|
-
|
40
23
|
# Generates JSON representation
|
41
24
|
def to_json(*json)
|
42
25
|
{
|
@@ -45,7 +28,17 @@ module Prometheus
|
|
45
28
|
}.to_json(*json)
|
46
29
|
end
|
47
30
|
|
48
|
-
|
31
|
+
private
|
32
|
+
|
33
|
+
def default
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def value
|
38
|
+
@values.map do |labels, value|
|
39
|
+
{ :labels => labels, :value => get(labels) }
|
40
|
+
end
|
41
|
+
end
|
49
42
|
|
50
43
|
def label_set_for(labels)
|
51
44
|
LabelSet.new(labels)
|
@@ -14,11 +14,7 @@ module Prometheus
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def call(env) # :nodoc:
|
17
|
-
|
18
|
-
@app.call(env)
|
19
|
-
ensure
|
20
|
-
@requests.increment
|
21
|
-
@requests_duration.increment({}, ((Time.now - start) * 1_000_000).to_i)
|
17
|
+
trace(env) { @app.call(env) }
|
22
18
|
end
|
23
19
|
|
24
20
|
protected
|
@@ -26,6 +22,36 @@ module Prometheus
|
|
26
22
|
def init_metrics
|
27
23
|
@requests = @registry.counter(:http_requests_total, 'A counter of the total number of HTTP requests made')
|
28
24
|
@requests_duration = @registry.counter(:http_request_durations_total_microseconds, 'The total amount of time Rack has spent answering HTTP requests (microseconds).')
|
25
|
+
@durations = @registry.summary(:http_request_durations_microseconds, 'A histogram of the response latency for requests made (microseconds).')
|
26
|
+
end
|
27
|
+
|
28
|
+
def trace(env, &block)
|
29
|
+
start = Time.now
|
30
|
+
response = yield
|
31
|
+
rescue => exception
|
32
|
+
raise
|
33
|
+
ensure
|
34
|
+
duration = ((Time.now - start) * 1_000_000).to_i
|
35
|
+
record(duration, env, response, exception)
|
36
|
+
end
|
37
|
+
|
38
|
+
def record(duration, env, response, exception)
|
39
|
+
labels = {
|
40
|
+
:method => env['REQUEST_METHOD'].downcase,
|
41
|
+
:path => env['PATH_INFO'].to_s,
|
42
|
+
}
|
43
|
+
|
44
|
+
if response
|
45
|
+
labels[:code] = response.first.to_s
|
46
|
+
else
|
47
|
+
labels[:exception] = exception.class.name
|
48
|
+
end
|
49
|
+
|
50
|
+
@requests.increment(labels)
|
51
|
+
@requests_duration.increment(labels, duration)
|
52
|
+
@durations.add(labels, duration)
|
53
|
+
rescue => error
|
54
|
+
# TODO: log unexpected exception during request recording
|
29
55
|
end
|
30
56
|
|
31
57
|
end
|
@@ -6,10 +6,14 @@ module Prometheus
|
|
6
6
|
class Exporter
|
7
7
|
attr_reader :app, :registry, :path
|
8
8
|
|
9
|
+
API_VERSION = '0.0.2'
|
10
|
+
CONTENT_TYPE = 'application/json; schema="prometheus/telemetry"; version=' + API_VERSION
|
11
|
+
HEADERS = { 'Content-Type' => CONTENT_TYPE }
|
12
|
+
|
9
13
|
def initialize(app, options = {})
|
10
14
|
@app = app
|
11
15
|
@registry = options[:registry] || Client.registry
|
12
|
-
@path = options[:path] || '/metrics
|
16
|
+
@path = options[:path] || '/metrics'
|
13
17
|
end
|
14
18
|
|
15
19
|
def call(env)
|
@@ -23,13 +27,7 @@ module Prometheus
|
|
23
27
|
protected
|
24
28
|
|
25
29
|
def metrics_response
|
26
|
-
|
27
|
-
headers = {
|
28
|
-
'Content-Type' => 'application/json',
|
29
|
-
'Content-Length' => json.size.to_s
|
30
|
-
}
|
31
|
-
|
32
|
-
[200, headers, [json]]
|
30
|
+
[200, HEADERS, [@registry.to_json]]
|
33
31
|
end
|
34
32
|
|
35
33
|
end
|
@@ -3,6 +3,7 @@ require 'thread'
|
|
3
3
|
|
4
4
|
require 'prometheus/client/container'
|
5
5
|
require 'prometheus/client/counter'
|
6
|
+
require 'prometheus/client/summary'
|
6
7
|
require 'prometheus/client/gauge'
|
7
8
|
|
8
9
|
module Prometheus
|
@@ -36,6 +37,10 @@ module Prometheus
|
|
36
37
|
register(name, docstring, Counter.new, base_labels).metric
|
37
38
|
end
|
38
39
|
|
40
|
+
def summary(name, docstring, base_labels = {})
|
41
|
+
register(name, docstring, Summary.new, base_labels).metric
|
42
|
+
end
|
43
|
+
|
39
44
|
def gauge(name, docstring, base_labels = {})
|
40
45
|
register(name, docstring, Gauge.new, base_labels).metric
|
41
46
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'quantile'
|
2
|
+
require 'prometheus/client/metric'
|
3
|
+
|
4
|
+
module Prometheus
|
5
|
+
module Client
|
6
|
+
class Summary < Metric
|
7
|
+
def type
|
8
|
+
:histogram
|
9
|
+
end
|
10
|
+
|
11
|
+
# Records a given value.
|
12
|
+
def add(labels, value)
|
13
|
+
label_set = label_set_for(labels)
|
14
|
+
synchronize { @values[label_set].observe(value) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the value for the given label set
|
18
|
+
def get(labels = {})
|
19
|
+
synchronize do
|
20
|
+
estimator = @values[label_set_for(labels)]
|
21
|
+
estimator.invariants.inject({}) do |memo, invariant|
|
22
|
+
memo[invariant.quantile] = estimator.query(invariant.quantile)
|
23
|
+
memo
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def default
|
31
|
+
Quantile::Estimator.new
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Tobias Schmidt
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
12
|
-
dependencies:
|
12
|
+
date: 2013-11-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: quantile
|
16
|
+
requirement: &19137520 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *19137520
|
13
25
|
description:
|
14
26
|
email:
|
15
27
|
- ts@soundcloud.com
|
@@ -20,40 +32,40 @@ files:
|
|
20
32
|
- README.md
|
21
33
|
- lib/prometheus/client/counter.rb
|
22
34
|
- lib/prometheus/client/gauge.rb
|
23
|
-
- lib/prometheus/client/histogram/bucket.rb
|
24
35
|
- lib/prometheus/client/metric.rb
|
25
36
|
- lib/prometheus/client/container.rb
|
26
37
|
- lib/prometheus/client/registry.rb
|
27
38
|
- lib/prometheus/client/rack/collector.rb
|
28
39
|
- lib/prometheus/client/rack/exporter.rb
|
29
|
-
- lib/prometheus/client/histogram.rb
|
30
40
|
- lib/prometheus/client/version.rb
|
31
41
|
- lib/prometheus/client/label_set.rb
|
42
|
+
- lib/prometheus/client/summary.rb
|
32
43
|
- lib/prometheus/client.rb
|
33
44
|
- lib/prometheus.rb
|
34
45
|
homepage: https://github.com/prometheus/client_ruby
|
35
46
|
licenses:
|
36
47
|
- Apache 2.0
|
37
|
-
metadata: {}
|
38
48
|
post_install_message:
|
39
49
|
rdoc_options: []
|
40
50
|
require_paths:
|
41
51
|
- lib
|
42
52
|
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
43
54
|
requirements:
|
44
55
|
- - ! '>='
|
45
56
|
- !ruby/object:Gem::Version
|
46
57
|
version: '0'
|
47
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
48
60
|
requirements:
|
49
61
|
- - ! '>='
|
50
62
|
- !ruby/object:Gem::Version
|
51
63
|
version: '0'
|
52
64
|
requirements: []
|
53
65
|
rubyforge_project:
|
54
|
-
rubygems_version:
|
66
|
+
rubygems_version: 1.8.5
|
55
67
|
signing_key:
|
56
|
-
specification_version:
|
68
|
+
specification_version: 3
|
57
69
|
summary: A suite of instrumentation metric primitives for Ruby that can be exposed
|
58
70
|
through a JSON web services interface.
|
59
71
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
---
|
2
|
-
!binary "U0hBMQ==":
|
3
|
-
metadata.gz: !binary |-
|
4
|
-
OTQ3NjhkOGY4ZjA3Zjg0MDZiNWIyMjc1MDc2YmZmMjI5Y2IxMGIxYg==
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZjBhYjc4OTA2YWIxNzdjYmY5YjNjYTYwM2I2ZDBiMjJiNTc1NTEwOA==
|
7
|
-
SHA512:
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MTFlNDlkZDZhNjA1ZGE4M2EzN2Q2NTQ2M2M3N2E5NGZkOWFmNjg0YzEyZmQy
|
10
|
-
NGRiNDgyNTVhMDU1ODkzMmUzYjBhN2E1MjNkNDc4M2ExMjVjY2ZjMmVkMWU5
|
11
|
-
MDZmMThkMjE4ZGE1MzNiZDcwMWUxMjU3N2EzOGJmNmRiMWJkZTI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YWE3ZWI4MmU4MjUyOTkyMjk3MWRkMzNkYWIxZTc4MDUxMWQ0OTk0NzIxZTNl
|
14
|
-
OTMzNGIxNTkxOTgyNDc3ODczM2E2ODM0YjM2MTFhYTIzZjdjOTRhMDI0N2Yy
|
15
|
-
ODkzNTQyYTg4MjcwMmM4OTdmNDcyNzgzOTZkYmNlMGFiOTQ4MzM=
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'prometheus/client/metric'
|
2
|
-
|
3
|
-
module Prometheus
|
4
|
-
module Client
|
5
|
-
class Histogram < Metric
|
6
|
-
def type
|
7
|
-
:histogram
|
8
|
-
end
|
9
|
-
|
10
|
-
def add(labels, timing)
|
11
|
-
raise NotImplementedError
|
12
|
-
end
|
13
|
-
|
14
|
-
def measure(labels, &block)
|
15
|
-
raise NotImplementedError
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Prometheus
|
2
|
-
module Client
|
3
|
-
class Histogram
|
4
|
-
class Bucket
|
5
|
-
attr_reader :observations
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@observations = 0
|
9
|
-
@timings = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def add(timing)
|
13
|
-
# TODO: mutex
|
14
|
-
@timmings << timing
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|