atatus 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +72 -22
- data/LICENSE +1 -1
- data/atatus.gemspec +2 -2
- data/lib/atatus.rb +76 -16
- data/lib/atatus/agent.rb +78 -29
- data/lib/atatus/central_config.rb +72 -27
- data/lib/atatus/central_config/cache_control.rb +18 -1
- data/lib/atatus/child_durations.rb +64 -0
- data/lib/atatus/collector/base.rb +61 -29
- data/lib/atatus/collector/builder.rb +46 -2
- data/lib/atatus/collector/hist.rb +54 -0
- data/lib/atatus/collector/transport.rb +41 -11
- data/lib/atatus/config.rb +129 -28
- data/lib/atatus/config/bytes.rb +17 -0
- data/lib/atatus/config/duration.rb +17 -0
- data/lib/atatus/config/options.rb +29 -9
- data/lib/atatus/config/regexp_list.rb +17 -0
- data/lib/atatus/config/wildcard_pattern_list.rb +64 -0
- data/lib/atatus/context.rb +32 -1
- data/lib/atatus/context/request.rb +17 -0
- data/lib/atatus/context/request/socket.rb +18 -1
- data/lib/atatus/context/request/url.rb +17 -0
- data/lib/atatus/context/response.rb +27 -2
- data/lib/atatus/context/user.rb +17 -0
- data/lib/atatus/context_builder.rb +19 -4
- data/lib/atatus/deprecations.rb +17 -0
- data/lib/atatus/error.rb +27 -0
- data/lib/atatus/error/exception.rb +24 -0
- data/lib/atatus/error/log.rb +17 -0
- data/lib/atatus/error_builder.rb +17 -2
- data/lib/atatus/grape.rb +62 -0
- data/lib/atatus/graphql.rb +91 -0
- data/lib/atatus/grpc.rb +99 -0
- data/lib/atatus/instrumenter.rb +135 -30
- data/lib/atatus/internal_error.rb +17 -0
- data/lib/atatus/logging.rb +17 -2
- data/lib/atatus/metadata.rb +17 -0
- data/lib/atatus/metadata/process_info.rb +17 -0
- data/lib/atatus/metadata/service_info.rb +21 -6
- data/lib/atatus/metadata/system_info.rb +22 -3
- data/lib/atatus/metadata/system_info/container_info.rb +49 -10
- data/lib/atatus/metadata/system_info/hw_info.rb +1 -1
- data/lib/atatus/metrics.rb +69 -27
- data/lib/atatus/metrics/breakdown_set.rb +31 -0
- data/lib/atatus/metrics/{cpu_mem.rb → cpu_mem_set.rb} +110 -63
- data/lib/atatus/metrics/metric.rb +140 -0
- data/lib/atatus/metrics/set.rb +123 -0
- data/lib/atatus/metrics/span_scoped_set.rb +56 -0
- data/lib/atatus/metrics/transaction_set.rb +26 -0
- data/lib/atatus/metrics/vm_set.rb +58 -0
- data/lib/atatus/metricset.rb +48 -4
- data/lib/atatus/middleware.rb +28 -8
- data/lib/atatus/naively_hashable.rb +17 -0
- data/lib/atatus/normalizers.rb +23 -9
- data/lib/atatus/normalizers/grape.rb +22 -0
- data/lib/atatus/normalizers/grape/endpoint_run.rb +65 -0
- data/lib/atatus/normalizers/rails.rb +27 -0
- data/lib/atatus/normalizers/rails/action_controller.rb +44 -0
- data/lib/atatus/normalizers/rails/action_mailer.rb +43 -0
- data/lib/atatus/normalizers/{action_view.rb → rails/action_view.rb} +17 -0
- data/lib/atatus/normalizers/rails/active_record.rb +80 -0
- data/lib/atatus/opentracing.rb +75 -42
- data/lib/atatus/rails.rb +29 -13
- data/lib/atatus/railtie.rb +19 -6
- data/lib/atatus/resque.rb +29 -0
- data/lib/atatus/sinatra.rb +53 -0
- data/lib/atatus/span.rb +44 -15
- data/lib/atatus/span/context.rb +43 -28
- data/lib/atatus/span/context/db.rb +43 -0
- data/lib/atatus/span/context/destination.rb +77 -0
- data/lib/atatus/span/context/http.rb +43 -0
- data/lib/atatus/span_helpers.rb +18 -1
- data/lib/atatus/spies.rb +33 -15
- data/lib/atatus/spies/action_dispatch.rb +27 -6
- data/lib/atatus/spies/delayed_job.rb +26 -5
- data/lib/atatus/spies/dynamo_db.rb +62 -0
- data/lib/atatus/spies/elasticsearch.rb +53 -7
- data/lib/atatus/spies/faraday.rb +54 -20
- data/lib/atatus/spies/http.rb +36 -6
- data/lib/atatus/spies/json.rb +18 -0
- data/lib/atatus/spies/mongo.rb +41 -10
- data/lib/atatus/spies/net_http.rb +52 -11
- data/lib/atatus/spies/rake.rb +42 -23
- data/lib/atatus/spies/redis.rb +17 -0
- data/lib/atatus/spies/resque.rb +57 -0
- data/lib/atatus/spies/sequel.rb +54 -17
- data/lib/atatus/spies/shoryuken.rb +69 -0
- data/lib/atatus/spies/sidekiq.rb +46 -25
- data/lib/atatus/spies/sinatra.rb +20 -4
- data/lib/atatus/spies/sneakers.rb +74 -0
- data/lib/atatus/spies/sucker_punch.rb +58 -0
- data/lib/atatus/spies/tilt.rb +20 -1
- data/lib/atatus/sql.rb +36 -0
- data/lib/atatus/sql/signature.rb +169 -0
- data/lib/atatus/sql/tokenizer.rb +264 -0
- data/lib/atatus/sql/tokens.rb +63 -0
- data/lib/atatus/sql_summarizer.rb +24 -6
- data/lib/atatus/stacktrace.rb +17 -0
- data/lib/atatus/stacktrace/frame.rb +17 -3
- data/lib/atatus/stacktrace_builder.rb +23 -3
- data/lib/atatus/subscriber.rb +23 -4
- data/lib/atatus/trace_context.rb +84 -51
- data/lib/atatus/trace_context/traceparent.rb +111 -0
- data/lib/atatus/trace_context/tracestate.rb +148 -0
- data/lib/atatus/transaction.rb +74 -18
- data/lib/atatus/transport/base.rb +44 -27
- data/lib/atatus/transport/connection.rb +28 -72
- data/lib/atatus/transport/connection/http.rb +58 -35
- data/lib/atatus/transport/connection/proxy_pipe.rb +24 -5
- data/lib/atatus/transport/filters.rb +18 -1
- data/lib/atatus/transport/filters/hash_sanitizer.rb +77 -0
- data/lib/atatus/transport/filters/secrets_filter.rb +30 -55
- data/lib/atatus/transport/headers.rb +83 -0
- data/lib/atatus/transport/serializers.rb +17 -5
- data/lib/atatus/transport/serializers/context_serializer.rb +30 -3
- data/lib/atatus/transport/serializers/error_serializer.rb +17 -2
- data/lib/atatus/transport/serializers/metadata_serializer.rb +44 -22
- data/lib/atatus/transport/serializers/metricset_serializer.rb +34 -6
- data/lib/atatus/transport/serializers/span_serializer.rb +47 -12
- data/lib/atatus/transport/serializers/transaction_serializer.rb +18 -2
- data/lib/atatus/transport/user_agent.rb +48 -0
- data/lib/atatus/transport/worker.rb +31 -7
- data/lib/atatus/util.rb +18 -1
- data/lib/atatus/util/inflector.rb +17 -0
- data/lib/atatus/util/lru_cache.rb +17 -0
- data/lib/atatus/util/throttle.rb +17 -0
- data/lib/atatus/version.rb +19 -1
- metadata +46 -26
- data/Rakefile +0 -19
- data/bench/.gitignore +0 -2
- data/bench/app.rb +0 -53
- data/bench/benchmark.rb +0 -36
- data/bench/report.rb +0 -55
- data/bench/rubyprof.rb +0 -39
- data/bench/stackprof.rb +0 -23
- data/bin/build_docs +0 -5
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/bin/with_framework +0 -7
- data/lib/atatus/metrics/vm.rb +0 -60
- data/lib/atatus/normalizers/action_controller.rb +0 -27
- data/lib/atatus/normalizers/action_mailer.rb +0 -26
- data/lib/atatus/normalizers/active_record.rb +0 -45
- data/lib/atatus/util/prefixed_logger.rb +0 -18
- data/vendor/.gitkeep +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
# frozen_string_literal: true
|
|
19
|
+
|
|
20
|
+
module Atatus
|
|
21
|
+
module Metrics
|
|
22
|
+
# @api private
|
|
23
|
+
class BreakdownSet < SpanScopedSet
|
|
24
|
+
def initialize(config)
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
disable! unless config.breakdown_metrics?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,107 +1,161 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
1
18
|
# frozen_string_literal: true
|
|
2
19
|
|
|
3
20
|
module Atatus
|
|
4
21
|
module Metrics
|
|
5
22
|
# @api private
|
|
6
|
-
class
|
|
23
|
+
class CpuMemSet < Set
|
|
7
24
|
include Logging
|
|
8
25
|
|
|
9
26
|
# @api private
|
|
10
27
|
class Sample
|
|
11
28
|
# rubocop:disable Metrics/ParameterLists
|
|
12
29
|
def initialize(
|
|
30
|
+
page_size:,
|
|
31
|
+
process_cpu_usage:,
|
|
32
|
+
process_memory_rss:,
|
|
33
|
+
process_memory_size:,
|
|
13
34
|
system_cpu_total:,
|
|
14
35
|
system_cpu_usage:,
|
|
15
|
-
system_memory_total:,
|
|
16
36
|
system_memory_free:,
|
|
17
|
-
|
|
18
|
-
process_memory_size:,
|
|
19
|
-
process_memory_rss:,
|
|
20
|
-
page_size:
|
|
37
|
+
system_memory_total:
|
|
21
38
|
)
|
|
39
|
+
@page_size = page_size
|
|
40
|
+
@process_cpu_usage = process_cpu_usage
|
|
41
|
+
@process_memory_rss = process_memory_rss
|
|
42
|
+
@process_memory_size = process_memory_size
|
|
22
43
|
@system_cpu_total = system_cpu_total
|
|
23
44
|
@system_cpu_usage = system_cpu_usage
|
|
24
|
-
@system_memory_total = system_memory_total
|
|
25
45
|
@system_memory_free = system_memory_free
|
|
26
|
-
@
|
|
27
|
-
@process_memory_size = process_memory_size
|
|
28
|
-
@process_memory_rss = process_memory_rss
|
|
29
|
-
@page_size = page_size
|
|
46
|
+
@system_memory_total = system_memory_total
|
|
30
47
|
end
|
|
31
48
|
# rubocop:enable Metrics/ParameterLists
|
|
32
49
|
|
|
33
|
-
attr_accessor
|
|
34
|
-
:
|
|
35
|
-
:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
sample.process_cpu_usage =
|
|
44
|
-
process_cpu_usage - previous.process_cpu_usage
|
|
45
|
-
end
|
|
46
|
-
end
|
|
50
|
+
attr_accessor(
|
|
51
|
+
:page_size,
|
|
52
|
+
:process_cpu_usage,
|
|
53
|
+
:process_memory_rss,
|
|
54
|
+
:process_memory_size,
|
|
55
|
+
:system_cpu_total,
|
|
56
|
+
:system_cpu_usage,
|
|
57
|
+
:system_memory_free,
|
|
58
|
+
:system_memory_total
|
|
59
|
+
)
|
|
47
60
|
end
|
|
48
61
|
|
|
49
62
|
def initialize(config)
|
|
50
|
-
@
|
|
63
|
+
@vmset_disabled = false
|
|
64
|
+
super
|
|
65
|
+
|
|
51
66
|
@sampler = sampler_for_platform(Metrics.platform)
|
|
67
|
+
read! # set @previous on boot
|
|
52
68
|
end
|
|
53
69
|
|
|
54
|
-
attr_reader :config
|
|
70
|
+
attr_reader :config
|
|
55
71
|
|
|
56
|
-
def
|
|
57
|
-
|
|
72
|
+
def collect
|
|
73
|
+
read!
|
|
74
|
+
super
|
|
58
75
|
end
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def vmset_disable!
|
|
80
|
+
@vmset_disabled = true
|
|
81
|
+
end
|
|
63
82
|
|
|
64
|
-
|
|
83
|
+
def vmset_disabled?
|
|
84
|
+
@vmset_disabled
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def sampler_for_platform(platform)
|
|
88
|
+
case platform
|
|
89
|
+
when :linux then Linux.new
|
|
90
|
+
else
|
|
91
|
+
warn "Unsupported platform '#{platform}' - Disabling system metrics"
|
|
92
|
+
disable!
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def read!
|
|
98
|
+
return if disabled?
|
|
99
|
+
|
|
100
|
+
current = @sampler.sample
|
|
65
101
|
|
|
66
102
|
unless @previous
|
|
67
103
|
@previous = current
|
|
68
104
|
return
|
|
69
105
|
end
|
|
70
106
|
|
|
71
|
-
|
|
107
|
+
cpu_usage_pct, cpu_process_pct = calculate_deltas(current, @previous)
|
|
72
108
|
|
|
73
|
-
|
|
74
|
-
|
|
109
|
+
gauge(:'system.cpu.total.norm.pct').value = cpu_usage_pct
|
|
110
|
+
gauge(:'system.memory.actual.free').value = current.system_memory_free
|
|
111
|
+
gauge(:'system.memory.total').value = current.system_memory_total
|
|
112
|
+
gauge(:'system.process.cpu.total.norm.pct').value = cpu_process_pct
|
|
113
|
+
gauge(:'system.process.memory.size').value = current.process_memory_size
|
|
114
|
+
gauge(:'system.process.memory.rss.bytes').value =
|
|
115
|
+
current.process_memory_rss * current.page_size
|
|
75
116
|
|
|
76
117
|
@previous = current
|
|
77
118
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
119
|
+
return if vmset_disabled?
|
|
120
|
+
|
|
121
|
+
stat = GC.stat
|
|
122
|
+
|
|
123
|
+
gauge(:'ruby.gc.count').value = stat[:count]
|
|
124
|
+
gauge(:'ruby.threads').value = Thread.list.count
|
|
125
|
+
gauge(:'ruby.heap.slots.live').value = stat[:heap_live_slots]
|
|
126
|
+
|
|
127
|
+
gauge(:'ruby.heap.slots.free').value = stat[:heap_free_slots]
|
|
128
|
+
gauge(:'ruby.heap.allocations.total').value =
|
|
129
|
+
stat[:total_allocated_objects]
|
|
130
|
+
|
|
131
|
+
return unless GC::Profiler.enabled?
|
|
132
|
+
@total_time ||= 0
|
|
133
|
+
@total_time += GC::Profiler.total_time
|
|
134
|
+
GC::Profiler.clear
|
|
135
|
+
gauge(:'ruby.gc.time').value = @total_time
|
|
136
|
+
rescue TypeError => e
|
|
137
|
+
error 'VM metrics encountered error: %s', e
|
|
138
|
+
debug('Backtrace:') { e.backtrace.join("\n") }
|
|
139
|
+
|
|
140
|
+
vmset_disable!
|
|
87
141
|
end
|
|
88
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
89
142
|
|
|
90
|
-
|
|
143
|
+
def calculate_deltas(current, previous)
|
|
144
|
+
system_cpu_total =
|
|
145
|
+
current.system_cpu_total - previous.system_cpu_total
|
|
146
|
+
system_cpu_usage =
|
|
147
|
+
current.system_cpu_usage - previous.system_cpu_usage
|
|
148
|
+
process_cpu_usage =
|
|
149
|
+
current.process_cpu_usage - previous.process_cpu_usage
|
|
91
150
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
warn "Unsupported platform '#{platform}' - Disabling metrics"
|
|
97
|
-
@disabled = true
|
|
98
|
-
nil
|
|
99
|
-
end
|
|
151
|
+
cpu_usage_pct = system_cpu_usage.to_f / system_cpu_total
|
|
152
|
+
cpu_process_pct = process_cpu_usage.to_f / system_cpu_total
|
|
153
|
+
|
|
154
|
+
[cpu_usage_pct, cpu_process_pct]
|
|
100
155
|
end
|
|
101
156
|
|
|
102
157
|
# @api private
|
|
103
158
|
class Linux
|
|
104
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
105
159
|
def sample
|
|
106
160
|
proc_stat = ProcStat.new.read!
|
|
107
161
|
proc_self_stat = ProcSelfStat.new.read!
|
|
@@ -118,7 +172,6 @@ module Atatus
|
|
|
118
172
|
page_size: meminfo.page_size
|
|
119
173
|
)
|
|
120
174
|
end
|
|
121
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
122
175
|
|
|
123
176
|
# @api private
|
|
124
177
|
class ProcStat
|
|
@@ -136,8 +189,6 @@ module Atatus
|
|
|
136
189
|
guest
|
|
137
190
|
guest_nice
|
|
138
191
|
].freeze
|
|
139
|
-
|
|
140
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
141
192
|
def read!
|
|
142
193
|
stat =
|
|
143
194
|
IO.readlines('/proc/stat')
|
|
@@ -165,7 +216,6 @@ module Atatus
|
|
|
165
216
|
|
|
166
217
|
self
|
|
167
218
|
end
|
|
168
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
169
219
|
end
|
|
170
220
|
|
|
171
221
|
UTIME_POS = 13
|
|
@@ -196,8 +246,6 @@ module Atatus
|
|
|
196
246
|
# @api private
|
|
197
247
|
class Meminfo
|
|
198
248
|
attr_reader :total, :available, :page_size
|
|
199
|
-
|
|
200
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
201
249
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
202
250
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
203
251
|
def read!
|
|
@@ -232,7 +280,6 @@ module Atatus
|
|
|
232
280
|
end
|
|
233
281
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
234
282
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
235
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
236
283
|
end
|
|
237
284
|
end
|
|
238
285
|
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
# frozen_string_literal: true
|
|
19
|
+
|
|
20
|
+
module Atatus
|
|
21
|
+
module Metrics
|
|
22
|
+
# @api private
|
|
23
|
+
class Metric
|
|
24
|
+
def initialize(
|
|
25
|
+
key,
|
|
26
|
+
initial_value: nil,
|
|
27
|
+
tags: nil,
|
|
28
|
+
reset_on_collect: false
|
|
29
|
+
)
|
|
30
|
+
@key = key
|
|
31
|
+
@initial_value = initial_value
|
|
32
|
+
@value = initial_value
|
|
33
|
+
@tags = tags
|
|
34
|
+
@reset_on_collect = reset_on_collect
|
|
35
|
+
@mutex = Mutex.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :key, :initial_value, :tags, :value
|
|
39
|
+
|
|
40
|
+
def value=(value)
|
|
41
|
+
@mutex.synchronize { @value = value }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset!
|
|
45
|
+
self.value = initial_value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def tags?
|
|
49
|
+
!!tags&.any?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def reset_on_collect?
|
|
53
|
+
@reset_on_collect
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def collect
|
|
57
|
+
@mutex.synchronize do
|
|
58
|
+
collected = @value
|
|
59
|
+
|
|
60
|
+
@value = initial_value if reset_on_collect?
|
|
61
|
+
|
|
62
|
+
return nil if reset_on_collect? && collected == 0
|
|
63
|
+
|
|
64
|
+
collected
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @api private
|
|
70
|
+
class NoopMetric
|
|
71
|
+
def value; end
|
|
72
|
+
|
|
73
|
+
def value=(_); end
|
|
74
|
+
|
|
75
|
+
def collect; end
|
|
76
|
+
|
|
77
|
+
def reset!; end
|
|
78
|
+
|
|
79
|
+
def tags?; end
|
|
80
|
+
|
|
81
|
+
def reset_on_collect?; end
|
|
82
|
+
|
|
83
|
+
def inc!; end
|
|
84
|
+
|
|
85
|
+
def dec!; end
|
|
86
|
+
|
|
87
|
+
def update(_, delta: nil); end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @api private
|
|
91
|
+
class Counter < Metric
|
|
92
|
+
def initialize(key, initial_value: 0, **args)
|
|
93
|
+
super(key, initial_value: initial_value, **args)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def inc!
|
|
97
|
+
@mutex.synchronize do
|
|
98
|
+
@value += 1
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def dec!
|
|
103
|
+
@mutex.synchronize do
|
|
104
|
+
@value -= 1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @api private
|
|
110
|
+
class Gauge < Metric
|
|
111
|
+
def initialize(key, **args)
|
|
112
|
+
super(key, initial_value: 0, **args)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @api private
|
|
117
|
+
class Timer < Metric
|
|
118
|
+
def initialize(key, **args)
|
|
119
|
+
super(key, initial_value: 0, **args)
|
|
120
|
+
@count = 0
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
attr_accessor :count
|
|
124
|
+
|
|
125
|
+
def update(duration, delta: 0)
|
|
126
|
+
@mutex.synchronize do
|
|
127
|
+
@value += duration
|
|
128
|
+
@count += delta
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def reset!
|
|
133
|
+
@mutex.synchronize do
|
|
134
|
+
@value = 0
|
|
135
|
+
@count = 0
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
# frozen_string_literal: true
|
|
19
|
+
|
|
20
|
+
module Atatus
|
|
21
|
+
# @api private
|
|
22
|
+
module Metrics
|
|
23
|
+
NOOP = NoopMetric.new
|
|
24
|
+
|
|
25
|
+
# @api private
|
|
26
|
+
class Set
|
|
27
|
+
include Logging
|
|
28
|
+
|
|
29
|
+
DISTINCT_LABEL_LIMIT = 1000
|
|
30
|
+
|
|
31
|
+
def initialize(config)
|
|
32
|
+
@config = config
|
|
33
|
+
@metrics = {}
|
|
34
|
+
@disabled = false
|
|
35
|
+
@lock = Mutex.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :metrics
|
|
39
|
+
|
|
40
|
+
def disable!
|
|
41
|
+
@disabled = true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def disabled?
|
|
45
|
+
@disabled
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def counter(key, tags: nil, **args)
|
|
49
|
+
metric(Counter, key, tags: tags, **args)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def gauge(key, tags: nil, **args)
|
|
53
|
+
metric(Gauge, key, tags: tags, **args)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def timer(key, tags: nil, **args)
|
|
57
|
+
metric(Timer, key, tags: tags, **args)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def metric(kls, key, tags: nil, **args)
|
|
61
|
+
if @config.disable_metrics.any? { |p| p.match? key }
|
|
62
|
+
return NOOP
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
key = key_with_tags(key, tags)
|
|
66
|
+
return metrics[key] if metrics[key]
|
|
67
|
+
|
|
68
|
+
@lock.synchronize do
|
|
69
|
+
return metrics[key] if metrics[key]
|
|
70
|
+
|
|
71
|
+
metrics[key] =
|
|
72
|
+
if metrics.length < DISTINCT_LABEL_LIMIT
|
|
73
|
+
kls.new(key, tags: tags, **args)
|
|
74
|
+
else
|
|
75
|
+
unless @label_limit_logged
|
|
76
|
+
warn(
|
|
77
|
+
'The limit of %d metricsets has been reached, no new ' \
|
|
78
|
+
'metricsets will be created.', DISTINCT_LABEL_LIMIT
|
|
79
|
+
)
|
|
80
|
+
@label_limit_logged = true
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
NOOP
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def collect
|
|
89
|
+
return if disabled?
|
|
90
|
+
|
|
91
|
+
@lock.synchronize do
|
|
92
|
+
metrics.each_with_object({}) do |(key, metric), sets|
|
|
93
|
+
next unless (value = metric.collect)
|
|
94
|
+
|
|
95
|
+
# metrics have a key of name and flat array of key-value pairs
|
|
96
|
+
# eg [name, key, value, key, value]
|
|
97
|
+
# they can be sent in the same metricset but not if they have
|
|
98
|
+
# differing tags. So, we split the resulting sets by tags first.
|
|
99
|
+
name, *tags = key
|
|
100
|
+
sets[tags] ||= Metricset.new
|
|
101
|
+
|
|
102
|
+
# then we set the `samples` value for the metricset
|
|
103
|
+
set = sets[tags]
|
|
104
|
+
set.samples[name] = value
|
|
105
|
+
|
|
106
|
+
# and finally we copy the tags from the Metric to the Metricset
|
|
107
|
+
set.merge_tags! metric.tags
|
|
108
|
+
end.values
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def key_with_tags(key, tags)
|
|
115
|
+
return key unless tags
|
|
116
|
+
|
|
117
|
+
tuple = tags.keys.zip(tags.values)
|
|
118
|
+
tuple.flatten!
|
|
119
|
+
tuple.unshift(key)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|