prometheus-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []