prometheus-client-mmap 0.20.3-arm64-darwin
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 +7 -0
- data/README.md +253 -0
- data/ext/fast_mmaped_file/extconf.rb +30 -0
- data/ext/fast_mmaped_file/fast_mmaped_file.c +122 -0
- data/ext/fast_mmaped_file/file_format.c +5 -0
- data/ext/fast_mmaped_file/file_format.h +11 -0
- data/ext/fast_mmaped_file/file_parsing.c +195 -0
- data/ext/fast_mmaped_file/file_parsing.h +27 -0
- data/ext/fast_mmaped_file/file_reading.c +102 -0
- data/ext/fast_mmaped_file/file_reading.h +30 -0
- data/ext/fast_mmaped_file/globals.h +14 -0
- data/ext/fast_mmaped_file/mmap.c +427 -0
- data/ext/fast_mmaped_file/mmap.h +61 -0
- data/ext/fast_mmaped_file/rendering.c +199 -0
- data/ext/fast_mmaped_file/rendering.h +8 -0
- data/ext/fast_mmaped_file/utils.c +56 -0
- data/ext/fast_mmaped_file/utils.h +22 -0
- data/ext/fast_mmaped_file/value_access.c +242 -0
- data/ext/fast_mmaped_file/value_access.h +15 -0
- data/ext/fast_mmaped_file_rs/.cargo/config.toml +23 -0
- data/ext/fast_mmaped_file_rs/Cargo.lock +790 -0
- data/ext/fast_mmaped_file_rs/Cargo.toml +30 -0
- data/ext/fast_mmaped_file_rs/README.md +52 -0
- data/ext/fast_mmaped_file_rs/extconf.rb +30 -0
- data/ext/fast_mmaped_file_rs/src/error.rs +174 -0
- data/ext/fast_mmaped_file_rs/src/file_entry.rs +579 -0
- data/ext/fast_mmaped_file_rs/src/file_info.rs +190 -0
- data/ext/fast_mmaped_file_rs/src/lib.rs +79 -0
- data/ext/fast_mmaped_file_rs/src/macros.rs +14 -0
- data/ext/fast_mmaped_file_rs/src/map.rs +492 -0
- data/ext/fast_mmaped_file_rs/src/mmap.rs +151 -0
- data/ext/fast_mmaped_file_rs/src/parser.rs +346 -0
- data/ext/fast_mmaped_file_rs/src/raw_entry.rs +473 -0
- data/ext/fast_mmaped_file_rs/src/testhelper.rs +222 -0
- data/ext/fast_mmaped_file_rs/src/util.rs +121 -0
- data/lib/2.7/fast_mmaped_file.bundle +0 -0
- data/lib/2.7/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.0/fast_mmaped_file.bundle +0 -0
- data/lib/3.0/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.1/fast_mmaped_file.bundle +0 -0
- data/lib/3.1/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.2/fast_mmaped_file.bundle +0 -0
- data/lib/3.2/fast_mmaped_file_rs.bundle +0 -0
- data/lib/prometheus/client/configuration.rb +23 -0
- data/lib/prometheus/client/counter.rb +27 -0
- data/lib/prometheus/client/formats/text.rb +118 -0
- data/lib/prometheus/client/gauge.rb +40 -0
- data/lib/prometheus/client/helper/entry_parser.rb +132 -0
- data/lib/prometheus/client/helper/file_locker.rb +50 -0
- data/lib/prometheus/client/helper/json_parser.rb +23 -0
- data/lib/prometheus/client/helper/metrics_processing.rb +45 -0
- data/lib/prometheus/client/helper/metrics_representation.rb +51 -0
- data/lib/prometheus/client/helper/mmaped_file.rb +64 -0
- data/lib/prometheus/client/helper/plain_file.rb +29 -0
- data/lib/prometheus/client/histogram.rb +80 -0
- data/lib/prometheus/client/label_set_validator.rb +86 -0
- data/lib/prometheus/client/metric.rb +80 -0
- data/lib/prometheus/client/mmaped_dict.rb +79 -0
- data/lib/prometheus/client/mmaped_value.rb +154 -0
- data/lib/prometheus/client/page_size.rb +17 -0
- data/lib/prometheus/client/push.rb +203 -0
- data/lib/prometheus/client/rack/collector.rb +88 -0
- data/lib/prometheus/client/rack/exporter.rb +96 -0
- data/lib/prometheus/client/registry.rb +65 -0
- data/lib/prometheus/client/simple_value.rb +31 -0
- data/lib/prometheus/client/summary.rb +69 -0
- data/lib/prometheus/client/support/unicorn.rb +35 -0
- data/lib/prometheus/client/uses_value_type.rb +20 -0
- data/lib/prometheus/client/version.rb +5 -0
- data/lib/prometheus/client.rb +58 -0
- data/lib/prometheus.rb +3 -0
- data/vendor/c/hashmap/.gitignore +52 -0
- data/vendor/c/hashmap/LICENSE +21 -0
- data/vendor/c/hashmap/README.md +90 -0
- data/vendor/c/hashmap/_config.yml +1 -0
- data/vendor/c/hashmap/src/hashmap.c +692 -0
- data/vendor/c/hashmap/src/hashmap.h +267 -0
- data/vendor/c/hashmap/test/Makefile +22 -0
- data/vendor/c/hashmap/test/hashmap_test.c +608 -0
- data/vendor/c/jsmn/.travis.yml +4 -0
- data/vendor/c/jsmn/LICENSE +20 -0
- data/vendor/c/jsmn/Makefile +41 -0
- data/vendor/c/jsmn/README.md +168 -0
- data/vendor/c/jsmn/example/jsondump.c +126 -0
- data/vendor/c/jsmn/example/simple.c +76 -0
- data/vendor/c/jsmn/jsmn.c +314 -0
- data/vendor/c/jsmn/jsmn.h +76 -0
- data/vendor/c/jsmn/library.json +16 -0
- data/vendor/c/jsmn/test/test.h +27 -0
- data/vendor/c/jsmn/test/tests.c +407 -0
- data/vendor/c/jsmn/test/testutil.h +94 -0
- metadata +243 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'thread'
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
require 'erb'
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
require 'prometheus/client'
|
11
|
+
require 'prometheus/client/formats/text'
|
12
|
+
require 'prometheus/client/label_set_validator'
|
13
|
+
|
14
|
+
module Prometheus
|
15
|
+
# Client is a ruby implementation for a Prometheus compatible client.
|
16
|
+
module Client
|
17
|
+
# Push implements a simple way to transmit a given registry to a given
|
18
|
+
# Pushgateway.
|
19
|
+
class Push
|
20
|
+
class HttpError < StandardError; end
|
21
|
+
class HttpRedirectError < HttpError; end
|
22
|
+
class HttpClientError < HttpError; end
|
23
|
+
class HttpServerError < HttpError; end
|
24
|
+
|
25
|
+
DEFAULT_GATEWAY = 'http://localhost:9091'.freeze
|
26
|
+
PATH = '/metrics/job/%s'.freeze
|
27
|
+
SUPPORTED_SCHEMES = %w(http https).freeze
|
28
|
+
|
29
|
+
attr_reader :job, :gateway, :path
|
30
|
+
|
31
|
+
def initialize(job:, gateway: DEFAULT_GATEWAY, grouping_key: {}, **kwargs)
|
32
|
+
raise ArgumentError, "job cannot be nil" if job.nil?
|
33
|
+
raise ArgumentError, "job cannot be empty" if job.empty?
|
34
|
+
@validator = LabelSetValidator.new()
|
35
|
+
@validator.validate(grouping_key)
|
36
|
+
|
37
|
+
@mutex = Mutex.new
|
38
|
+
@job = job
|
39
|
+
@gateway = gateway || DEFAULT_GATEWAY
|
40
|
+
@grouping_key = grouping_key
|
41
|
+
@path = build_path(job, grouping_key)
|
42
|
+
|
43
|
+
@uri = parse("#{@gateway}#{@path}")
|
44
|
+
validate_no_basic_auth!(@uri)
|
45
|
+
|
46
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
47
|
+
@http.use_ssl = (@uri.scheme == 'https')
|
48
|
+
@http.open_timeout = kwargs[:open_timeout] if kwargs[:open_timeout]
|
49
|
+
@http.read_timeout = kwargs[:read_timeout] if kwargs[:read_timeout]
|
50
|
+
end
|
51
|
+
|
52
|
+
def basic_auth(user, password)
|
53
|
+
@user = user
|
54
|
+
@password = password
|
55
|
+
end
|
56
|
+
|
57
|
+
def add(registry)
|
58
|
+
synchronize do
|
59
|
+
request(Net::HTTP::Post, registry)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def replace(registry)
|
64
|
+
synchronize do
|
65
|
+
request(Net::HTTP::Put, registry)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete
|
70
|
+
synchronize do
|
71
|
+
request(Net::HTTP::Delete)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def parse(url)
|
78
|
+
uri = URI.parse(url)
|
79
|
+
|
80
|
+
unless SUPPORTED_SCHEMES.include?(uri.scheme)
|
81
|
+
raise ArgumentError, 'only HTTP gateway URLs are supported currently.'
|
82
|
+
end
|
83
|
+
|
84
|
+
uri
|
85
|
+
rescue URI::InvalidURIError => e
|
86
|
+
raise ArgumentError, "#{url} is not a valid URL: #{e}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_path(job, grouping_key)
|
90
|
+
path = format(PATH, ERB::Util::url_encode(job))
|
91
|
+
|
92
|
+
grouping_key.each do |label, value|
|
93
|
+
if value.include?('/')
|
94
|
+
encoded_value = Base64.urlsafe_encode64(value)
|
95
|
+
path += "/#{label}@base64/#{encoded_value}"
|
96
|
+
# While it's valid for the urlsafe_encode64 function to return an
|
97
|
+
# empty string when the input string is empty, it doesn't work for
|
98
|
+
# our specific use case as we're putting the result into a URL path
|
99
|
+
# segment. A double slash (`//`) can be normalised away by HTTP
|
100
|
+
# libraries, proxies, and web servers.
|
101
|
+
#
|
102
|
+
# For empty strings, we use a single padding character (`=`) as the
|
103
|
+
# value.
|
104
|
+
#
|
105
|
+
# See the pushgateway docs for more details:
|
106
|
+
#
|
107
|
+
# https://github.com/prometheus/pushgateway/blob/6393a901f56d4dda62cd0f6ab1f1f07c495b6354/README.md#url
|
108
|
+
elsif value.empty?
|
109
|
+
path += "/#{label}@base64/="
|
110
|
+
else
|
111
|
+
path += "/#{label}/#{ERB::Util::url_encode(value)}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
path
|
116
|
+
end
|
117
|
+
|
118
|
+
def request(req_class, registry = nil)
|
119
|
+
validate_no_label_clashes!(registry) if registry
|
120
|
+
|
121
|
+
req = req_class.new(@uri)
|
122
|
+
req.content_type = Formats::Text::CONTENT_TYPE
|
123
|
+
req.basic_auth(@user, @password) if @user
|
124
|
+
req.body = Formats::Text.marshal(registry) if registry
|
125
|
+
|
126
|
+
response = @http.request(req)
|
127
|
+
validate_response!(response)
|
128
|
+
|
129
|
+
response
|
130
|
+
end
|
131
|
+
|
132
|
+
def synchronize
|
133
|
+
@mutex.synchronize { yield }
|
134
|
+
end
|
135
|
+
|
136
|
+
def validate_no_basic_auth!(uri)
|
137
|
+
if uri.user || uri.password
|
138
|
+
raise ArgumentError, <<~EOF
|
139
|
+
Setting Basic Auth credentials in the gateway URL is not supported, please call the `basic_auth` method.
|
140
|
+
|
141
|
+
Received username `#{uri.user}` in gateway URL. Instead of passing
|
142
|
+
Basic Auth credentials like this:
|
143
|
+
|
144
|
+
```
|
145
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://user:password@localhost:9091")
|
146
|
+
```
|
147
|
+
|
148
|
+
please pass them like this:
|
149
|
+
|
150
|
+
```
|
151
|
+
push = Prometheus::Client::Push.new(job: "my-job", gateway: "http://localhost:9091")
|
152
|
+
push.basic_auth("user", "password")
|
153
|
+
```
|
154
|
+
|
155
|
+
While URLs do support passing Basic Auth credentials using the
|
156
|
+
`http://user:password@example.com/` syntax, the username and
|
157
|
+
password in that syntax have to follow the usual rules for URL
|
158
|
+
encoding of characters per RFC 3986
|
159
|
+
(https://datatracker.ietf.org/doc/html/rfc3986#section-2.1).
|
160
|
+
|
161
|
+
Rather than place the burden of correctly performing that encoding
|
162
|
+
on users of this gem, we decided to have a separate method for
|
163
|
+
supplying Basic Auth credentials, with no requirement to URL encode
|
164
|
+
the characters in them.
|
165
|
+
EOF
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def validate_no_label_clashes!(registry)
|
170
|
+
# There's nothing to check if we don't have a grouping key
|
171
|
+
return if @grouping_key.empty?
|
172
|
+
|
173
|
+
# We could be doing a lot of comparisons, so let's do them against a
|
174
|
+
# set rather than an array
|
175
|
+
grouping_key_labels = @grouping_key.keys.to_set
|
176
|
+
|
177
|
+
registry.metrics.each do |metric|
|
178
|
+
metric.values.keys.first.keys.each do |label|
|
179
|
+
if grouping_key_labels.include?(label)
|
180
|
+
raise LabelSetValidator::InvalidLabelSetError,
|
181
|
+
"label :#{label} from grouping key collides with label of the " \
|
182
|
+
"same name from metric :#{metric.name} and would overwrite it"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def validate_response!(response)
|
189
|
+
status = Integer(response.code)
|
190
|
+
if status >= 300
|
191
|
+
message = "status: #{response.code}, message: #{response.message}, body: #{response.body}"
|
192
|
+
if status <= 399
|
193
|
+
raise HttpRedirectError, message
|
194
|
+
elsif status <= 499
|
195
|
+
raise HttpClientError, message
|
196
|
+
else
|
197
|
+
raise HttpServerError, message
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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 summary of the response latency.',
|
45
|
+
)
|
46
|
+
@durations_hist = @registry.histogram(
|
47
|
+
:http_req_duration_seconds,
|
48
|
+
'A histogram of the response latency.',
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def init_exception_metrics
|
53
|
+
@exceptions = @registry.counter(
|
54
|
+
:http_exceptions_total,
|
55
|
+
'A counter of the total number of exceptions raised.',
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def trace(env)
|
60
|
+
start = Time.now
|
61
|
+
yield.tap do |response|
|
62
|
+
duration = (Time.now - start).to_f
|
63
|
+
record(labels(env, response), duration)
|
64
|
+
end
|
65
|
+
rescue => exception
|
66
|
+
@exceptions.increment(exception: exception.class.name)
|
67
|
+
raise
|
68
|
+
end
|
69
|
+
|
70
|
+
def labels(env, response)
|
71
|
+
@label_builder.call(env).tap do |labels|
|
72
|
+
labels[:code] = response.first.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def record(labels, duration)
|
77
|
+
@requests.increment(labels)
|
78
|
+
@durations.observe(labels, duration)
|
79
|
+
@durations_hist.observe(labels, duration)
|
80
|
+
rescue => exception
|
81
|
+
@exceptions.increment(exception: exception.class.name)
|
82
|
+
raise
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
+
response = if Prometheus::Client.configuration.value_class.multiprocess
|
66
|
+
format.marshal_multiprocess
|
67
|
+
else
|
68
|
+
format.marshal
|
69
|
+
end
|
70
|
+
[
|
71
|
+
200,
|
72
|
+
{ 'Content-Type' => format::CONTENT_TYPE },
|
73
|
+
[response],
|
74
|
+
]
|
75
|
+
end
|
76
|
+
|
77
|
+
def not_acceptable(formats)
|
78
|
+
types = formats.map { |format| format::MEDIA_TYPE }
|
79
|
+
|
80
|
+
[
|
81
|
+
406,
|
82
|
+
{ 'Content-Type' => 'text/plain' },
|
83
|
+
["Supported media types: #{types.join(', ')}"],
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_dictionary(formats, fallback)
|
88
|
+
formats.each_with_object('*/*' => fallback) do |format, memo|
|
89
|
+
memo[format::CONTENT_TYPE] = format
|
90
|
+
memo[format::MEDIA_TYPE] = format
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
require 'prometheus/client/counter'
|
6
|
+
require 'prometheus/client/summary'
|
7
|
+
require 'prometheus/client/gauge'
|
8
|
+
require 'prometheus/client/histogram'
|
9
|
+
|
10
|
+
module Prometheus
|
11
|
+
module Client
|
12
|
+
# Registry
|
13
|
+
class Registry
|
14
|
+
class AlreadyRegisteredError < StandardError; end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@metrics = {}
|
18
|
+
@mutex = Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def register(metric)
|
22
|
+
name = metric.name
|
23
|
+
|
24
|
+
@mutex.synchronize do
|
25
|
+
if exist?(name.to_sym)
|
26
|
+
raise AlreadyRegisteredError, "#{name} has already been registered"
|
27
|
+
else
|
28
|
+
@metrics[name.to_sym] = metric
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
metric
|
33
|
+
end
|
34
|
+
|
35
|
+
def counter(name, docstring, base_labels = {})
|
36
|
+
register(Counter.new(name, docstring, base_labels))
|
37
|
+
end
|
38
|
+
|
39
|
+
def summary(name, docstring, base_labels = {})
|
40
|
+
register(Summary.new(name, docstring, base_labels))
|
41
|
+
end
|
42
|
+
|
43
|
+
def gauge(name, docstring, base_labels = {}, multiprocess_mode = :all)
|
44
|
+
register(Gauge.new(name, docstring, base_labels, multiprocess_mode))
|
45
|
+
end
|
46
|
+
|
47
|
+
def histogram(name, docstring, base_labels = {},
|
48
|
+
buckets = Histogram::DEFAULT_BUCKETS)
|
49
|
+
register(Histogram.new(name, docstring, base_labels, buckets))
|
50
|
+
end
|
51
|
+
|
52
|
+
def exist?(name)
|
53
|
+
@metrics.key?(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get(name)
|
57
|
+
@metrics[name.to_sym]
|
58
|
+
end
|
59
|
+
|
60
|
+
def metrics
|
61
|
+
@metrics.values
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
class SimpleValue
|
6
|
+
def initialize(_type, _metric_name, _name, _labels, *_args)
|
7
|
+
@value = 0.0
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(value)
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def increment(by = 1)
|
15
|
+
@value += by
|
16
|
+
end
|
17
|
+
|
18
|
+
def decrement(by = 1)
|
19
|
+
@value -= by
|
20
|
+
end
|
21
|
+
|
22
|
+
def get
|
23
|
+
@value
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.multiprocess
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'prometheus/client/metric'
|
2
|
+
require 'prometheus/client/uses_value_type'
|
3
|
+
|
4
|
+
module Prometheus
|
5
|
+
module Client
|
6
|
+
# Summary is an accumulator for samples. It captures Numeric data and
|
7
|
+
# provides an efficient quantile calculation mechanism.
|
8
|
+
class Summary < Metric
|
9
|
+
extend Gem::Deprecate
|
10
|
+
|
11
|
+
# Value represents the state of a Summary at a given point.
|
12
|
+
class Value < Hash
|
13
|
+
include UsesValueType
|
14
|
+
attr_accessor :sum, :total
|
15
|
+
|
16
|
+
def initialize(type, name, labels)
|
17
|
+
@sum = value_object(type, name, "#{name}_sum", labels)
|
18
|
+
@total = value_object(type, name, "#{name}_count", labels)
|
19
|
+
end
|
20
|
+
|
21
|
+
def observe(value)
|
22
|
+
@sum.increment(value)
|
23
|
+
@total.increment
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(name, docstring, base_labels = {})
|
28
|
+
super(name, docstring, base_labels)
|
29
|
+
end
|
30
|
+
|
31
|
+
def type
|
32
|
+
:summary
|
33
|
+
end
|
34
|
+
|
35
|
+
# Records a given value.
|
36
|
+
def observe(labels, value)
|
37
|
+
label_set = label_set_for(labels)
|
38
|
+
synchronize { @values[label_set].observe(value) }
|
39
|
+
end
|
40
|
+
|
41
|
+
alias add observe
|
42
|
+
deprecate :add, :observe, 2016, 10
|
43
|
+
|
44
|
+
# Returns the value for the given label set
|
45
|
+
def get(labels = {})
|
46
|
+
@validator.valid?(labels)
|
47
|
+
|
48
|
+
synchronize do
|
49
|
+
@values[labels].sum.get
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns all label sets with their values
|
54
|
+
def values
|
55
|
+
synchronize do
|
56
|
+
@values.each_with_object({}) do |(labels, value), memo|
|
57
|
+
memo[labels] = value.sum
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def default(labels)
|
65
|
+
Value.new(type, @name, labels)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Prometheus
|
2
|
+
module Client
|
3
|
+
module Support
|
4
|
+
module Unicorn
|
5
|
+
def self.worker_pid_provider
|
6
|
+
wid = worker_id
|
7
|
+
if wid.nil?
|
8
|
+
"process_id_#{Process.pid}"
|
9
|
+
else
|
10
|
+
"worker_id_#{wid}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.worker_id
|
15
|
+
match = $0.match(/worker\[([^\]]+)\]/)
|
16
|
+
if match
|
17
|
+
match[1]
|
18
|
+
else
|
19
|
+
object_based_worker_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.object_based_worker_id
|
24
|
+
return unless defined?(::Unicorn::Worker)
|
25
|
+
|
26
|
+
workers = ObjectSpace.each_object(::Unicorn::Worker)
|
27
|
+
return if workers.nil?
|
28
|
+
|
29
|
+
workers_first = workers.first
|
30
|
+
workers_first.nr unless workers_first.nil?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'prometheus/client/simple_value'
|
2
|
+
|
3
|
+
module Prometheus
|
4
|
+
module Client
|
5
|
+
# Module providing convenience methods for creating value_object
|
6
|
+
module UsesValueType
|
7
|
+
def value_class
|
8
|
+
Prometheus::Client.configuration.value_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def value_object(type, metric_name, name, labels, *args)
|
12
|
+
value_class.new(type, metric_name, name, labels, *args)
|
13
|
+
rescue StandardError => e
|
14
|
+
Prometheus::Client.logger.info("error #{e} while creating instance of #{value_class} defaulting to SimpleValue")
|
15
|
+
Prometheus::Client.logger.debug("error #{e} backtrace #{e.backtrace.join("\n")}")
|
16
|
+
Prometheus::Client::SimpleValue.new(type, metric_name, name, labels)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'prometheus/client/registry'
|
2
|
+
require 'prometheus/client/configuration'
|
3
|
+
require 'prometheus/client/mmaped_value'
|
4
|
+
|
5
|
+
module Prometheus
|
6
|
+
# Client is a ruby implementation for a Prometheus compatible client.
|
7
|
+
module Client
|
8
|
+
class << self
|
9
|
+
attr_writer :configuration
|
10
|
+
|
11
|
+
def configuration
|
12
|
+
@configuration ||= Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure
|
16
|
+
yield(configuration)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a default registry object
|
20
|
+
def registry
|
21
|
+
@registry ||= Registry.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def logger
|
25
|
+
configuration.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
def pid
|
29
|
+
configuration.pid_provider.call
|
30
|
+
end
|
31
|
+
|
32
|
+
# Resets the registry and reinitializes all metrics files.
|
33
|
+
# Use case: clean up everything in specs `before` block,
|
34
|
+
# to prevent leaking the state between specs which are updating metrics.
|
35
|
+
def reset!
|
36
|
+
@registry = nil
|
37
|
+
::Prometheus::Client::MmapedValue.reset_and_reinitialize
|
38
|
+
end
|
39
|
+
|
40
|
+
def cleanup!
|
41
|
+
Dir.glob("#{configuration.multiprocess_files_dir}/*.db").each { |f| File.unlink(f) if File.exist?(f) }
|
42
|
+
end
|
43
|
+
|
44
|
+
# With `force: false`: reinitializes metric files only for processes with the changed PID.
|
45
|
+
# With `force: true`: reinitializes all metrics files.
|
46
|
+
# Always keeps the registry.
|
47
|
+
# Use case (`force: false`): pick up new metric files on each worker start,
|
48
|
+
# without resetting already registered files for the master or previously initialized workers.
|
49
|
+
def reinitialize_on_pid_change(force: false)
|
50
|
+
if force
|
51
|
+
::Prometheus::Client::MmapedValue.reset_and_reinitialize
|
52
|
+
else
|
53
|
+
::Prometheus::Client::MmapedValue.reinitialize_on_pid_change
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/prometheus.rb
ADDED