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.
@@ -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=
@@ -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
@@ -0,0 +1,2 @@
1
+ module Prometheus
2
+ end
@@ -0,0 +1,12 @@
1
+ require 'prometheus/client/registry'
2
+
3
+ module Prometheus
4
+ module Client
5
+
6
+ # Returns a default registry object
7
+ def self.registry
8
+ @@registry ||= Registry.new
9
+ end
10
+
11
+ end
12
+ end
@@ -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,11 @@
1
+ require 'prometheus/client/metric'
2
+
3
+ module Prometheus
4
+ module Client
5
+ class Gauge < Metric
6
+ def type
7
+ :gauge
8
+ end
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,5 @@
1
+ module Prometheus
2
+ module Client
3
+ VERSION = '0.1.0'
4
+ end
5
+ 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: []