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 +4 -4
- data/README.md +17 -17
- data/lib/prometheus/client/counter.rb +1 -1
- data/lib/prometheus/client/gauge.rb +5 -1
- data/lib/prometheus/client/histogram.rb +2 -2
- data/lib/prometheus/client/metric.rb +0 -5
- data/lib/prometheus/client/push.rb +9 -3
- data/lib/prometheus/client/registry.rb +1 -2
- data/lib/prometheus/client/version.rb +1 -1
- data/lib/prometheus/middleware/collector.rb +91 -0
- data/lib/prometheus/middleware/exporter.rb +91 -0
- metadata +7 -7
- data/lib/prometheus/client/rack/collector.rb +0 -82
- data/lib/prometheus/client/rack/exporter.rb +0 -91
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7df7b1114d199d5da7e201aa5a3d42898c5db9a
|
4
|
+
data.tar.gz: 5bea74f933571336d6dba20f9b5a28aa12321b52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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/
|
49
|
-
require 'prometheus/
|
48
|
+
require 'prometheus/middleware/collector'
|
49
|
+
require 'prometheus/middleware/exporter'
|
50
50
|
|
51
|
-
use Rack::Deflater, if: ->(
|
52
|
-
use Prometheus::
|
53
|
-
use Prometheus::
|
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 ->(
|
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
|
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.
|
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.
|
180
|
-
[7]: https://coveralls.io/repos/prometheus/client_ruby/badge.
|
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/
|
183
|
-
[10]: lib/prometheus/
|
182
|
+
[9]: lib/prometheus/middleware/exporter.rb
|
183
|
+
[10]: lib/prometheus/middleware/collector.rb
|
@@ -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
|
-
|
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
|
@@ -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
|
-
|
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
|
@@ -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.
|
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:
|
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:
|
66
|
+
version: 1.3.1
|
67
67
|
requirements: []
|
68
68
|
rubyforge_project:
|
69
|
-
rubygems_version: 2.
|
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
|