prometheus-client 0.1.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.
- checksums.yaml +15 -0
- data/README.md +52 -0
- data/lib/prometheus.rb +2 -0
- data/lib/prometheus/client.rb +12 -0
- data/lib/prometheus/client/container.rb +26 -0
- data/lib/prometheus/client/counter.rb +24 -0
- data/lib/prometheus/client/gauge.rb +11 -0
- data/lib/prometheus/client/histogram.rb +19 -0
- data/lib/prometheus/client/histogram/bucket.rb +19 -0
- data/lib/prometheus/client/label_set.rb +44 -0
- data/lib/prometheus/client/metric.rb +59 -0
- data/lib/prometheus/client/rack/collector.rb +34 -0
- data/lib/prometheus/client/rack/exporter.rb +38 -0
- data/lib/prometheus/client/registry.rb +56 -0
- data/lib/prometheus/client/version.rb +5 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
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=
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Prometheus Ruby Client
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
require 'prometheus/client'
|
7
|
+
|
8
|
+
# returns a default registry
|
9
|
+
prometheus = Prometheus::Client.registry
|
10
|
+
|
11
|
+
# create a new counter metric
|
12
|
+
http_requests = Prometheus::Client::Counter.new
|
13
|
+
|
14
|
+
# register the metric
|
15
|
+
prometheus.register(:http_requests, 'A counter of the total number of HTTP requests made', http_requests)
|
16
|
+
|
17
|
+
# start using the counter
|
18
|
+
http_requests.increment
|
19
|
+
```
|
20
|
+
|
21
|
+
## Metrics
|
22
|
+
|
23
|
+
The following metric types are currently supported.
|
24
|
+
|
25
|
+
### Counter
|
26
|
+
|
27
|
+
A Counter is a metric that exposes merely a sum or tally of things.
|
28
|
+
|
29
|
+
### Gauge
|
30
|
+
|
31
|
+
A Gauge is a metric that exposes merely an instantaneous value or some
|
32
|
+
snapshot thereof.
|
33
|
+
|
34
|
+
## Todo
|
35
|
+
|
36
|
+
* add histogram support
|
37
|
+
* add push support to a vanilla prometheus exporter
|
38
|
+
* add tests for Rack middlewares
|
39
|
+
* use a more performant JSON library
|
40
|
+
|
41
|
+
## Tests
|
42
|
+
|
43
|
+
[![Build Status][1]](http://travis-ci.org/prometheus/client_ruby)
|
44
|
+
|
45
|
+
Install necessary development gems with `bundle install` and run tests with
|
46
|
+
rspec:
|
47
|
+
|
48
|
+
```bash
|
49
|
+
rspec
|
50
|
+
```
|
51
|
+
|
52
|
+
[1]: https://secure.travis-ci.org/prometheus/client_ruby.png?branch=master
|
data/lib/prometheus.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'prometheus/client/label_set'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
# Metric Container
|
6
|
+
class Container
|
7
|
+
attr_reader :name, :docstring, :metric, :base_labels
|
8
|
+
|
9
|
+
def initialize(name, docstring, metric, base_labels)
|
10
|
+
@name = name
|
11
|
+
@docstring = docstring
|
12
|
+
@metric = metric
|
13
|
+
@base_labels = LabelSet.new(base_labels)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_json(*json)
|
17
|
+
{
|
18
|
+
'baseLabels' => base_labels.merge(:name => name),
|
19
|
+
'docstring' => docstring,
|
20
|
+
'metric' => metric
|
21
|
+
}.to_json(*json)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'prometheus/client/metric'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
class Counter < Metric
|
6
|
+
def default
|
7
|
+
0
|
8
|
+
end
|
9
|
+
|
10
|
+
def type
|
11
|
+
:counter
|
12
|
+
end
|
13
|
+
|
14
|
+
def increment(labels = {}, by = 1)
|
15
|
+
label_set = label_set_for(labels)
|
16
|
+
synchronize { @values[label_set] += by }
|
17
|
+
end
|
18
|
+
|
19
|
+
def decrement(labels = {}, by = 1)
|
20
|
+
increment(labels, -by)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -0,0 +1,19 @@
|
|
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
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Prometheus
|
2
|
+
module Client
|
3
|
+
# LabelSet is a pseudo class used to ensure given labels are semantically
|
4
|
+
# correct.
|
5
|
+
class LabelSet
|
6
|
+
# TODO: we might allow setting :instance in the future
|
7
|
+
RESERVED_LABELS = [:name, :job, :instance]
|
8
|
+
|
9
|
+
class LabelSetError < StandardError; end
|
10
|
+
class InvalidLabelSetError < LabelSetError; end
|
11
|
+
class InvalidLabelError < LabelSetError; end
|
12
|
+
class ReservedLabelError < LabelSetError; end
|
13
|
+
|
14
|
+
# A list of validated label sets
|
15
|
+
@@validated = {}
|
16
|
+
|
17
|
+
def self.new(labels)
|
18
|
+
validate(labels)
|
19
|
+
labels
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def self.validate(labels)
|
25
|
+
@@validated[labels.hash] ||= begin
|
26
|
+
labels.keys.each do |key|
|
27
|
+
unless Symbol === key
|
28
|
+
raise InvalidLabelError, "label name #{key} is not a symbol"
|
29
|
+
end
|
30
|
+
|
31
|
+
if RESERVED_LABELS.include?(key)
|
32
|
+
raise ReservedLabelError, "labels may not contain reserved #{key} label"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
rescue NoMethodError
|
39
|
+
raise InvalidLabelSetError, "#{labels} is not a valid label set"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'prometheus/client/label_set'
|
3
|
+
|
4
|
+
module Prometheus
|
5
|
+
module Client
|
6
|
+
# Metric
|
7
|
+
class Metric
|
8
|
+
def initialize
|
9
|
+
@mutex = Mutex.new
|
10
|
+
@values = Hash.new(default)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Default value
|
14
|
+
def default
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the metric type
|
19
|
+
def type
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns all values
|
24
|
+
def value
|
25
|
+
@values.map do |labels, value|
|
26
|
+
{ :labels => labels, :value => value }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the value for the given label set
|
31
|
+
def get(labels = {})
|
32
|
+
@values[label_set_for(labels)]
|
33
|
+
end
|
34
|
+
|
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
|
+
# Generates JSON representation
|
41
|
+
def to_json(*json)
|
42
|
+
{
|
43
|
+
'type' => type,
|
44
|
+
'value' => value
|
45
|
+
}.to_json(*json)
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def label_set_for(labels)
|
51
|
+
LabelSet.new(labels)
|
52
|
+
end
|
53
|
+
|
54
|
+
def synchronize(&block)
|
55
|
+
@mutex.synchronize(&block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'prometheus/client'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
module Rack
|
6
|
+
class Collector
|
7
|
+
attr_reader :app, :registry
|
8
|
+
|
9
|
+
def initialize(app, options = {})
|
10
|
+
@app = app
|
11
|
+
@registry = options[:registry] || Client.registry
|
12
|
+
|
13
|
+
init_metrics
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env) # :nodoc:
|
17
|
+
start = Time.now
|
18
|
+
@app.call(env)
|
19
|
+
ensure
|
20
|
+
@requests.increment
|
21
|
+
@requests_duration.increment({}, ((Time.now - start) * 1_000_000).to_i)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def init_metrics
|
27
|
+
@requests = @registry.counter(:http_requests_total, 'A counter of the total number of HTTP requests made')
|
28
|
+
@requests_duration = @registry.counter(:http_request_durations_total_microseconds, 'The total amount of time Rack has spent answering HTTP requests (microseconds).')
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'prometheus/client'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
module Rack
|
6
|
+
class Exporter
|
7
|
+
attr_reader :app, :registry, :path
|
8
|
+
|
9
|
+
def initialize(app, options = {})
|
10
|
+
@app = app
|
11
|
+
@registry = options[:registry] || Client.registry
|
12
|
+
@path = options[:path] || '/metrics.json'
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
if env['PATH_INFO'] == @path
|
17
|
+
metrics_response
|
18
|
+
else
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def metrics_response
|
26
|
+
json = @registry.to_json
|
27
|
+
headers = {
|
28
|
+
'Content-Type' => 'application/json',
|
29
|
+
'Content-Length' => json.size.to_s
|
30
|
+
}
|
31
|
+
|
32
|
+
[200, headers, [json]]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
require 'prometheus/client/container'
|
5
|
+
require 'prometheus/client/counter'
|
6
|
+
require 'prometheus/client/gauge'
|
7
|
+
|
8
|
+
module Prometheus
|
9
|
+
module Client
|
10
|
+
# Registry
|
11
|
+
#
|
12
|
+
#
|
13
|
+
class Registry
|
14
|
+
class AlreadyRegisteredError < StandardError; end
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
@containers = {}
|
18
|
+
@mutex = Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def register(name, docstring, metric, base_labels = {})
|
22
|
+
container = Container.new(name, docstring, metric, base_labels)
|
23
|
+
|
24
|
+
@mutex.synchronize do
|
25
|
+
if exist?(name)
|
26
|
+
raise AlreadyRegisteredError, "#{name} has already been registered"
|
27
|
+
else
|
28
|
+
@containers[name] = container
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
container
|
33
|
+
end
|
34
|
+
|
35
|
+
def counter(name, docstring, base_labels = {})
|
36
|
+
register(name, docstring, Counter.new, base_labels).metric
|
37
|
+
end
|
38
|
+
|
39
|
+
def gauge(name, docstring, base_labels = {})
|
40
|
+
register(name, docstring, Gauge.new, base_labels).metric
|
41
|
+
end
|
42
|
+
|
43
|
+
def exist?(name)
|
44
|
+
@containers.has_key?(name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get(name)
|
48
|
+
@containers[name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_json(*json)
|
52
|
+
@containers.values.to_json(*json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prometheus-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Schmidt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- ts@soundcloud.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- README.md
|
21
|
+
- lib/prometheus/client/counter.rb
|
22
|
+
- lib/prometheus/client/gauge.rb
|
23
|
+
- lib/prometheus/client/histogram/bucket.rb
|
24
|
+
- lib/prometheus/client/metric.rb
|
25
|
+
- lib/prometheus/client/container.rb
|
26
|
+
- lib/prometheus/client/registry.rb
|
27
|
+
- lib/prometheus/client/rack/collector.rb
|
28
|
+
- lib/prometheus/client/rack/exporter.rb
|
29
|
+
- lib/prometheus/client/histogram.rb
|
30
|
+
- lib/prometheus/client/version.rb
|
31
|
+
- lib/prometheus/client/label_set.rb
|
32
|
+
- lib/prometheus/client.rb
|
33
|
+
- lib/prometheus.rb
|
34
|
+
homepage: https://github.com/prometheus/client_ruby
|
35
|
+
licenses:
|
36
|
+
- Apache 2.0
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 2.1.2
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: A suite of instrumentation metric primitives for Ruby that can be exposed
|
58
|
+
through a JSON web services interface.
|
59
|
+
test_files: []
|