prometheus-client 0.6.0 → 0.7.0.pre.rc.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ca1c148a74709f3c2fbbba112f651babdf43fbe
4
- data.tar.gz: e55c7b9be73218b6a252a5a624fc8a865d00d851
3
+ metadata.gz: c7df7b1114d199d5da7e201aa5a3d42898c5db9a
4
+ data.tar.gz: 5bea74f933571336d6dba20f9b5a28aa12321b52
5
5
  SHA512:
6
- metadata.gz: 337ad7b5c4315463492d5120b4652bd0e4d58c1b2a53fa8be05c5f1d02c7b567133196e31e5b43899001f25fd896c7f60d4cccda717d1d8fede675aaa21276e0
7
- data.tar.gz: fcbb6c9963f8f0e5c5c532209fecf8643fad16a8943b74fd601644972ff25bb30f8c0e0be02b307c0247fb7a83549d21a54fe1f75850df795000d7756c9092ab
6
+ metadata.gz: bdfb89648fb64ee9c9bbfaaf4d4158834b3cbdc79d562530fa61d4511f8e95b2e15f4e01c374fedeb985dbf1c69fa3d5748260d29eaf5e87ed784350e1613437
7
+ data.tar.gz: acb12ac03128cb6387930d6f4fb43997be306fa590cd9cad706c319f514509cc631e2103152d57294e68738a4a30f42e0c6102a21db4d6ca9335d1bca646bec5
data/README.md CHANGED
@@ -35,7 +35,7 @@ http_requests.increment
35
35
  ### Rack middleware
36
36
 
37
37
  There are two [Rack][2] middlewares available, one to expose a metrics HTTP
38
- endpoint to be scraped by a prometheus server ([Exporter][9]) and one to trace all HTTP
38
+ endpoint to be scraped by a Prometheus server ([Exporter][9]) and one to trace all HTTP
39
39
  requests ([Collector][10]).
40
40
 
41
41
  It's highly recommended to enable gzip compression for the metrics endpoint,
@@ -45,14 +45,14 @@ for example by including the `Rack::Deflater` middleware.
45
45
  # config.ru
46
46
 
47
47
  require 'rack'
48
- require 'prometheus/client/rack/collector'
49
- require 'prometheus/client/rack/exporter'
48
+ require 'prometheus/middleware/collector'
49
+ require 'prometheus/middleware/exporter'
50
50
 
51
- use Rack::Deflater, if: ->(env, status, headers, body) { body.any? && body[0].length > 512 }
52
- use Prometheus::Client::Rack::Collector
53
- use Prometheus::Client::Rack::Exporter
51
+ use Rack::Deflater, if: ->(_, _, _, body) { body.any? && body[0].length > 512 }
52
+ use Prometheus::Middleware::Collector
53
+ use Prometheus::Middleware::Exporter
54
54
 
55
- run ->(env) { [200, {'Content-Type' => 'text/html'}, ['OK']] }
55
+ run ->(_) { [200, {'Content-Type' => 'text/html'}, ['OK']] }
56
56
  ```
57
57
 
58
58
  Start the server and have a look at the metrics endpoint:
@@ -85,6 +85,10 @@ Prometheus::Client::Push.new(
85
85
  # If you want to replace any previously pushed metrics for a given instance,
86
86
  # use the #replace method.
87
87
  Prometheus::Client::Push.new('my-batch-job', 'instance').replace(prometheus)
88
+
89
+ # If you want to delete all previously pushed metrics for a given instance,
90
+ # use the #delete method.
91
+ Prometheus::Client::Push.new('my-batch-job', 'instance').delete
88
92
  ```
89
93
 
90
94
  ## Metrics
@@ -137,7 +141,7 @@ histogram = Prometheus::Client::Histogram.new(:service_latency_seconds, '...')
137
141
  # record a value
138
142
  histogram.observe({ service: 'users' }, Benchmark.realtime { service.call(arg) })
139
143
 
140
- # retrieve the current quantile values
144
+ # retrieve the current bucket values
141
145
  histogram.get({ service: 'users' })
142
146
  # => { 0.005 => 3, 0.01 => 15, 0.025 => 18, ..., 2.5 => 42, 5 => 42, 10 = >42 }
143
147
  ```
@@ -158,10 +162,6 @@ summary.get({ service: 'database' })
158
162
  # => { 0.5 => 0.1233122, 0.9 => 3.4323, 0.99 => 5.3428231 }
159
163
  ```
160
164
 
161
- ## Todo
162
-
163
- * add protobuf support
164
-
165
165
  ## Tests
166
166
 
167
167
  Install necessary development gems with `bundle install` and run tests with
@@ -173,11 +173,11 @@ rake
173
173
 
174
174
  [1]: https://github.com/prometheus/prometheus
175
175
  [2]: http://rack.github.io/
176
- [3]: https://secure.travis-ci.org/prometheus/client_ruby.png?branch=master
176
+ [3]: https://secure.travis-ci.org/prometheus/client_ruby.svg?branch=master
177
177
  [4]: https://badge.fury.io/rb/prometheus-client.svg
178
178
  [5]: https://gemnasium.com/prometheus/client_ruby.svg
179
- [6]: https://codeclimate.com/github/prometheus/client_ruby.png
180
- [7]: https://coveralls.io/repos/prometheus/client_ruby/badge.png?branch=master
179
+ [6]: https://codeclimate.com/github/prometheus/client_ruby.svg
180
+ [7]: https://coveralls.io/repos/prometheus/client_ruby/badge.svg?branch=master
181
181
  [8]: https://github.com/prometheus/pushgateway
182
- [9]: lib/prometheus/client/rack/exporter.rb
183
- [10]: lib/prometheus/client/rack/collector.rb
182
+ [9]: lib/prometheus/middleware/exporter.rb
183
+ [10]: lib/prometheus/middleware/collector.rb
@@ -20,7 +20,7 @@ module Prometheus
20
20
  private
21
21
 
22
22
  def default
23
- 0
23
+ 0.0
24
24
  end
25
25
  end
26
26
  end
@@ -13,7 +13,11 @@ module Prometheus
13
13
 
14
14
  # Sets the value for the given label set
15
15
  def set(labels, value)
16
- @values[label_set_for(labels)] = value
16
+ unless value.is_a?(Numeric)
17
+ raise ArgumentError, 'value must be a number'
18
+ end
19
+
20
+ @values[label_set_for(labels)] = value.to_f
17
21
  end
18
22
  end
19
23
  end
@@ -14,10 +14,10 @@ module Prometheus
14
14
 
15
15
  def initialize(buckets)
16
16
  @sum = 0.0
17
- @total = 0
17
+ @total = 0.0
18
18
 
19
19
  buckets.each do |bucket|
20
- self[bucket] = 0
20
+ self[bucket] = 0.0
21
21
  end
22
22
  end
23
23
 
@@ -23,11 +23,6 @@ module Prometheus
23
23
  @base_labels = base_labels
24
24
  end
25
25
 
26
- # Returns the metric type
27
- def type
28
- raise NotImplementedError
29
- end
30
-
31
26
  # Returns the value for the given label set
32
27
  def get(labels = {})
33
28
  @validator.valid?(labels)
@@ -16,6 +16,7 @@ module Prometheus
16
16
  PATH = '/metrics/jobs/%s'.freeze
17
17
  INSTANCE_PATH = '/metrics/jobs/%s/instances/%s'.freeze
18
18
  HEADER = { 'Content-Type' => Formats::Text::CONTENT_TYPE }.freeze
19
+ SUPPORTED_SCHEMES = %w(http https).freeze
19
20
 
20
21
  attr_reader :job, :instance, :gateway, :path
21
22
 
@@ -26,6 +27,7 @@ module Prometheus
26
27
  @uri = parse(@gateway)
27
28
  @path = build_path(job, instance)
28
29
  @http = Net::HTTP.new(@uri.host, @uri.port)
30
+ @http.use_ssl = @uri.scheme == 'https'
29
31
  end
30
32
 
31
33
  def add(registry)
@@ -36,16 +38,20 @@ module Prometheus
36
38
  request('PUT', registry)
37
39
  end
38
40
 
41
+ def delete
42
+ @http.send_request('DELETE', path)
43
+ end
44
+
39
45
  private
40
46
 
41
47
  def parse(url)
42
48
  uri = URI.parse(url)
43
49
 
44
- if uri.scheme == 'http'
45
- uri
46
- else
50
+ unless SUPPORTED_SCHEMES.include?(uri.scheme)
47
51
  raise ArgumentError, 'only HTTP gateway URLs are supported currently.'
48
52
  end
53
+
54
+ uri
49
55
  rescue URI::InvalidURIError => e
50
56
  raise ArgumentError, "#{url} is not a valid URL: #{e}"
51
57
  end
@@ -24,9 +24,8 @@ module Prometheus
24
24
  @mutex.synchronize do
25
25
  if exist?(name.to_sym)
26
26
  raise AlreadyRegisteredError, "#{name} has already been registered"
27
- else
28
- @metrics[name.to_sym] = metric
29
27
  end
28
+ @metrics[name.to_sym] = metric
30
29
  end
31
30
 
32
31
  metric
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Prometheus
4
4
  module Client
5
- VERSION = '0.6.0'
5
+ VERSION = '0.7.0-rc.1'
6
6
  end
7
7
  end
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'prometheus/client'
4
+
5
+ module Prometheus
6
+ module Middleware
7
+ # Collector is a Rack middleware that provides a sample implementation of a
8
+ # HTTP tracer.
9
+ #
10
+ # By default metrics are registered on the global registry. Set the
11
+ # `:registry` option to use a custom registry.
12
+ #
13
+ # The request counter metric is broken down by code, method and path by
14
+ # default. Set the `:counter_label_builder` option to use a custom label
15
+ # builder.
16
+ #
17
+ # The request duration metric is broken down by method and path by default.
18
+ # Set the `:duration_label_builder` option to use a custom label builder.
19
+ class Collector
20
+ attr_reader :app, :registry
21
+
22
+ def initialize(app, options = {})
23
+ @app = app
24
+ @registry = options[:registry] || Client.registry
25
+ @counter_lb = options[:counter_label_builder] || COUNTER_LB
26
+ @duration_lb = options[:duration_label_builder] || DURATION_LB
27
+
28
+ init_request_metrics
29
+ init_exception_metrics
30
+ end
31
+
32
+ def call(env) # :nodoc:
33
+ trace(env) { @app.call(env) }
34
+ end
35
+
36
+ protected
37
+
38
+ COUNTER_LB = proc do |env, code|
39
+ {
40
+ code: code,
41
+ method: env['REQUEST_METHOD'].downcase,
42
+ path: env['PATH_INFO'].to_s,
43
+ }
44
+ end
45
+
46
+ DURATION_LB = proc do |env, _|
47
+ {
48
+ method: env['REQUEST_METHOD'].downcase,
49
+ path: env['PATH_INFO'].to_s,
50
+ }
51
+ end
52
+
53
+ def init_request_metrics
54
+ @requests = @registry.counter(
55
+ :http_server_requests_total,
56
+ 'The total number of HTTP requests handled by the Rack application.',
57
+ )
58
+ @durations = @registry.histogram(
59
+ :http_server_request_duration_seconds,
60
+ 'The HTTP response duration of the Rack application.',
61
+ )
62
+ end
63
+
64
+ def init_exception_metrics
65
+ @exceptions = @registry.counter(
66
+ :http_server_exceptions_total,
67
+ 'The total number of exceptions raised by the Rack application.',
68
+ )
69
+ end
70
+
71
+ def trace(env)
72
+ start = Time.now
73
+ yield.tap do |response|
74
+ duration = [(Time.now - start).to_f, 0.0].max
75
+ record(env, response.first.to_s, duration)
76
+ end
77
+ rescue => exception
78
+ @exceptions.increment(exception: exception.class.name)
79
+ raise
80
+ end
81
+
82
+ def record(env, code, duration)
83
+ @requests.increment(@counter_lb.call(env, code))
84
+ @durations.observe(@duration_lb.call(env, code), duration)
85
+ rescue
86
+ # TODO: log unexpected exception during request recording
87
+ nil
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'prometheus/client'
4
+ require 'prometheus/client/formats/text'
5
+
6
+ module Prometheus
7
+ module Middleware
8
+ # Exporter is a Rack middleware that provides a sample implementation of a
9
+ # Prometheus HTTP exposition endpoint.
10
+ #
11
+ # By default it will export the state of the global registry and expose it
12
+ # under `/metrics`. Use the `:registry` and `:path` options to change the
13
+ # defaults.
14
+ class Exporter
15
+ attr_reader :app, :registry, :path
16
+
17
+ FORMATS = [Client::Formats::Text].freeze
18
+ FALLBACK = Client::Formats::Text
19
+
20
+ def initialize(app, options = {})
21
+ @app = app
22
+ @registry = options[:registry] || Client.registry
23
+ @path = options[:path] || '/metrics'
24
+ @acceptable = build_dictionary(FORMATS, FALLBACK)
25
+ end
26
+
27
+ def call(env)
28
+ if env['PATH_INFO'] == @path
29
+ format = negotiate(env, @acceptable)
30
+ format ? respond_with(format) : not_acceptable(FORMATS)
31
+ else
32
+ @app.call(env)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def negotiate(env, formats)
39
+ parse(env.fetch('HTTP_ACCEPT', '*/*')).each do |content_type, _|
40
+ return formats[content_type] if formats.key?(content_type)
41
+ end
42
+
43
+ nil
44
+ end
45
+
46
+ def parse(header)
47
+ header.split(/\s*,\s*/).map do |type|
48
+ attributes = type.split(/\s*;\s*/)
49
+ quality = extract_quality(attributes)
50
+
51
+ [attributes.join('; '), quality]
52
+ end.sort_by(&:last).reverse
53
+ end
54
+
55
+ def extract_quality(attributes, default = 1.0)
56
+ quality = default
57
+
58
+ attributes.delete_if do |attr|
59
+ quality = attr.split('q=').last.to_f if attr.start_with?('q=')
60
+ end
61
+
62
+ quality
63
+ end
64
+
65
+ def respond_with(format)
66
+ [
67
+ 200,
68
+ { 'Content-Type' => format::CONTENT_TYPE },
69
+ [format.marshal(@registry)],
70
+ ]
71
+ end
72
+
73
+ def not_acceptable(formats)
74
+ types = formats.map { |format| format::MEDIA_TYPE }
75
+
76
+ [
77
+ 406,
78
+ { 'Content-Type' => 'text/plain' },
79
+ ["Supported media types: #{types.join(', ')}"],
80
+ ]
81
+ end
82
+
83
+ def build_dictionary(formats, fallback)
84
+ formats.each_with_object('*/*' => fallback) do |format, memo|
85
+ memo[format::CONTENT_TYPE] = format
86
+ memo[format::MEDIA_TYPE] = format
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0.pre.rc.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-08 00:00:00.000000000 Z
11
+ date: 2017-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: quantile
@@ -41,11 +41,11 @@ files:
41
41
  - lib/prometheus/client/label_set_validator.rb
42
42
  - lib/prometheus/client/metric.rb
43
43
  - lib/prometheus/client/push.rb
44
- - lib/prometheus/client/rack/collector.rb
45
- - lib/prometheus/client/rack/exporter.rb
46
44
  - lib/prometheus/client/registry.rb
47
45
  - lib/prometheus/client/summary.rb
48
46
  - lib/prometheus/client/version.rb
47
+ - lib/prometheus/middleware/collector.rb
48
+ - lib/prometheus/middleware/exporter.rb
49
49
  homepage: https://github.com/prometheus/client_ruby
50
50
  licenses:
51
51
  - Apache 2.0
@@ -61,12 +61,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
61
  version: '0'
62
62
  required_rubygems_version: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ">="
64
+ - - ">"
65
65
  - !ruby/object:Gem::Version
66
- version: '0'
66
+ version: 1.3.1
67
67
  requirements: []
68
68
  rubyforge_project:
69
- rubygems_version: 2.5.1
69
+ rubygems_version: 2.6.8
70
70
  signing_key:
71
71
  specification_version: 4
72
72
  summary: A suite of instrumentation metric primitivesthat can be exposed through a
@@ -1,82 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'prometheus/client'
4
-
5
- module Prometheus
6
- module Client
7
- module Rack
8
- # Collector is a Rack middleware that provides a sample implementation of
9
- # a HTTP tracer. The default label builder can be modified to export a
10
- # different set of labels per recorded metric.
11
- class Collector
12
- attr_reader :app, :registry
13
-
14
- def initialize(app, options = {}, &label_builder)
15
- @app = app
16
- @registry = options[:registry] || Client.registry
17
- @label_builder = label_builder || DEFAULT_LABEL_BUILDER
18
-
19
- init_request_metrics
20
- init_exception_metrics
21
- end
22
-
23
- def call(env) # :nodoc:
24
- trace(env) { @app.call(env) }
25
- end
26
-
27
- protected
28
-
29
- DEFAULT_LABEL_BUILDER = proc do |env|
30
- {
31
- method: env['REQUEST_METHOD'].downcase,
32
- host: env['HTTP_HOST'].to_s,
33
- path: env['PATH_INFO'].to_s,
34
- }
35
- end
36
-
37
- def init_request_metrics
38
- @requests = @registry.counter(
39
- :http_requests_total,
40
- 'A counter of the total number of HTTP requests made.',
41
- )
42
- @durations = @registry.summary(
43
- :http_request_duration_seconds,
44
- 'A histogram of the response latency.',
45
- )
46
- end
47
-
48
- def init_exception_metrics
49
- @exceptions = @registry.counter(
50
- :http_exceptions_total,
51
- 'A counter of the total number of exceptions raised.',
52
- )
53
- end
54
-
55
- def trace(env)
56
- start = Time.now
57
- yield.tap do |response|
58
- duration = (Time.now - start).to_f
59
- record(labels(env, response), duration)
60
- end
61
- rescue => exception
62
- @exceptions.increment(exception: exception.class.name)
63
- raise
64
- end
65
-
66
- def labels(env, response)
67
- @label_builder.call(env).tap do |labels|
68
- labels[:code] = response.first.to_s
69
- end
70
- end
71
-
72
- def record(labels, duration)
73
- @requests.increment(labels)
74
- @durations.observe(labels, duration)
75
- rescue
76
- # TODO: log unexpected exception during request recording
77
- nil
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,91 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'prometheus/client'
4
- require 'prometheus/client/formats/text'
5
-
6
- module Prometheus
7
- module Client
8
- module Rack
9
- # Exporter is a Rack middleware that provides a sample implementation of
10
- # a Prometheus HTTP client API.
11
- class Exporter
12
- attr_reader :app, :registry, :path
13
-
14
- FORMATS = [Formats::Text].freeze
15
- FALLBACK = Formats::Text
16
-
17
- def initialize(app, options = {})
18
- @app = app
19
- @registry = options[:registry] || Client.registry
20
- @path = options[:path] || '/metrics'
21
- @acceptable = build_dictionary(FORMATS, FALLBACK)
22
- end
23
-
24
- def call(env)
25
- if env['PATH_INFO'] == @path
26
- format = negotiate(env['HTTP_ACCEPT'], @acceptable)
27
- format ? respond_with(format) : not_acceptable(FORMATS)
28
- else
29
- @app.call(env)
30
- end
31
- end
32
-
33
- private
34
-
35
- def negotiate(accept, formats)
36
- accept = '*/*' if accept.to_s.empty?
37
-
38
- parse(accept).each do |content_type, _|
39
- return formats[content_type] if formats.key?(content_type)
40
- end
41
-
42
- nil
43
- end
44
-
45
- def parse(header)
46
- header.to_s.split(/\s*,\s*/).map do |type|
47
- attributes = type.split(/\s*;\s*/)
48
- quality = extract_quality(attributes)
49
-
50
- [attributes.join('; '), quality]
51
- end.sort_by(&:last).reverse
52
- end
53
-
54
- def extract_quality(attributes, default = 1.0)
55
- quality = default
56
-
57
- attributes.delete_if do |attr|
58
- quality = attr.split('q=').last.to_f if attr.start_with?('q=')
59
- end
60
-
61
- quality
62
- end
63
-
64
- def respond_with(format)
65
- [
66
- 200,
67
- { 'Content-Type' => format::CONTENT_TYPE },
68
- [format.marshal(@registry)],
69
- ]
70
- end
71
-
72
- def not_acceptable(formats)
73
- types = formats.map { |format| format::MEDIA_TYPE }
74
-
75
- [
76
- 406,
77
- { 'Content-Type' => 'text/plain' },
78
- ["Supported media types: #{types.join(', ')}"],
79
- ]
80
- end
81
-
82
- def build_dictionary(formats, fallback)
83
- formats.each_with_object('*/*' => fallback) do |format, memo|
84
- memo[format::CONTENT_TYPE] = format
85
- memo[format::MEDIA_TYPE] = format
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end