elastic-apm 3.1.0 → 3.2.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/.ci/.jenkins_exclude.yml +47 -0
- data/.ci/.jenkins_framework.yml +4 -0
- data/.ci/.jenkins_master_framework.yml +1 -0
- data/.ci/.jenkins_ruby.yml +1 -0
- data/.ci/downstreamTests.groovy +1 -1
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/CHANGELOG.asciidoc +24 -0
- data/Dockerfile +43 -0
- data/Gemfile +34 -15
- data/README.md +30 -1
- data/bin/dev +54 -0
- data/bin/run-tests +27 -0
- data/docker-compose.yml +32 -0
- data/docs/api.asciidoc +13 -2
- data/docs/configuration.asciidoc +30 -0
- data/docs/getting-started-rack.asciidoc +24 -0
- data/docs/release-notes.asciidoc +1 -1
- data/lib/elastic_apm.rb +12 -1
- data/lib/elastic_apm/agent.rb +15 -3
- data/lib/elastic_apm/central_config.rb +39 -19
- data/lib/elastic_apm/child_durations.rb +42 -0
- data/lib/elastic_apm/config.rb +27 -11
- data/lib/elastic_apm/context/request/socket.rb +1 -1
- data/lib/elastic_apm/context_builder.rb +1 -1
- data/lib/elastic_apm/error.rb +10 -0
- data/lib/elastic_apm/error/exception.rb +7 -0
- data/lib/elastic_apm/grape.rb +48 -0
- data/lib/elastic_apm/instrumenter.rb +77 -4
- data/lib/elastic_apm/logging.rb +0 -2
- data/lib/elastic_apm/metrics.rb +39 -26
- data/lib/elastic_apm/metrics/breakdown_set.rb +14 -0
- data/lib/elastic_apm/metrics/{cpu_mem.rb → cpu_mem_set.rb} +62 -54
- data/lib/elastic_apm/metrics/metric.rb +117 -0
- data/lib/elastic_apm/metrics/set.rb +106 -0
- data/lib/elastic_apm/metrics/span_scoped_set.rb +39 -0
- data/lib/elastic_apm/metrics/transaction_set.rb +11 -0
- data/lib/elastic_apm/metrics/vm_set.rb +44 -0
- data/lib/elastic_apm/metricset.rb +31 -4
- data/lib/elastic_apm/normalizers.rb +6 -0
- data/lib/elastic_apm/normalizers/grape.rb +5 -0
- data/lib/elastic_apm/normalizers/grape/endpoint_run.rb +47 -0
- data/lib/elastic_apm/normalizers/rails/active_record.rb +16 -5
- data/lib/elastic_apm/opentracing.rb +4 -4
- data/lib/elastic_apm/rails.rb +12 -2
- data/lib/elastic_apm/railtie.rb +1 -5
- data/lib/elastic_apm/sinatra.rb +1 -1
- data/lib/elastic_apm/span.rb +15 -10
- data/lib/elastic_apm/spies.rb +0 -1
- data/lib/elastic_apm/sql_summarizer.rb +8 -6
- data/lib/elastic_apm/subscriber.rb +4 -1
- data/lib/elastic_apm/transaction.rb +6 -6
- data/lib/elastic_apm/transport/base.rb +7 -0
- data/lib/elastic_apm/transport/connection.rb +11 -69
- data/lib/elastic_apm/transport/connection/http.rb +43 -35
- data/lib/elastic_apm/transport/connection/proxy_pipe.rb +0 -3
- data/lib/elastic_apm/transport/headers.rb +62 -0
- data/lib/elastic_apm/transport/serializers.rb +0 -2
- data/lib/elastic_apm/transport/serializers/metricset_serializer.rb +19 -6
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +3 -3
- data/lib/elastic_apm/transport/user_agent.rb +31 -0
- data/lib/elastic_apm/transport/worker.rb +1 -2
- data/lib/elastic_apm/version.rb +1 -1
- metadata +20 -6
- data/lib/elastic_apm/metrics/vm.rb +0 -60
- data/lib/elastic_apm/util/prefixed_logger.rb +0 -18
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'elastic_apm/subscriber'
|
4
|
+
require 'elastic_apm/normalizers/grape'
|
5
|
+
|
6
|
+
module ElasticAPM
|
7
|
+
# Module for starting the ElasticAPM agent and hooking into Grape.
|
8
|
+
module Grape
|
9
|
+
extend self
|
10
|
+
|
11
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
12
|
+
# Start the ElasticAPM agent and hook into Grape.
|
13
|
+
#
|
14
|
+
# @param app [Grape::API] A Grape app.
|
15
|
+
# @param config [Config, Hash] An instance of Config or a Hash config.
|
16
|
+
# @return [true, nil] true if the agent was started, nil otherwise.
|
17
|
+
def start(app, config = {})
|
18
|
+
config = Config.new(config) unless config.is_a?(Config)
|
19
|
+
configure_app(app, config)
|
20
|
+
|
21
|
+
ElasticAPM.start(config).tap do |agent|
|
22
|
+
attach_subscriber(agent)
|
23
|
+
end
|
24
|
+
|
25
|
+
ElasticAPM.running?
|
26
|
+
rescue StandardError => e
|
27
|
+
config.logger.error format('Failed to start: %s', e.message)
|
28
|
+
config.logger.debug "Backtrace:\n" + e.backtrace.join("\n")
|
29
|
+
end
|
30
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def configure_app(app, config)
|
35
|
+
config.service_name ||= app.name
|
36
|
+
config.framework_name ||= 'Grape'
|
37
|
+
config.framework_version ||= ::Grape::VERSION
|
38
|
+
config.logger ||= app.logger
|
39
|
+
config.__root_path ||= Dir.pwd
|
40
|
+
end
|
41
|
+
|
42
|
+
def attach_subscriber(agent)
|
43
|
+
return unless agent
|
44
|
+
|
45
|
+
agent.instrumenter.subscriber = ElasticAPM::Subscriber.new(agent)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'elastic_apm/trace_context'
|
4
|
+
require 'elastic_apm/child_durations'
|
4
5
|
require 'elastic_apm/span'
|
5
6
|
require 'elastic_apm/transaction'
|
6
7
|
require 'elastic_apm/span_helpers'
|
@@ -39,10 +40,11 @@ module ElasticAPM
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
def initialize(config, stacktrace_builder:, &enqueue)
|
43
|
+
def initialize(config, metrics:, stacktrace_builder:, &enqueue)
|
43
44
|
@config = config
|
44
45
|
@stacktrace_builder = stacktrace_builder
|
45
46
|
@enqueue = enqueue
|
47
|
+
@metrics = metrics
|
46
48
|
|
47
49
|
@current = Current.new
|
48
50
|
end
|
@@ -90,7 +92,8 @@ module ElasticAPM
|
|
90
92
|
|
91
93
|
if (transaction = current_transaction)
|
92
94
|
raise ExistingTransactionError,
|
93
|
-
"Transactions may not be nested.\
|
95
|
+
"Transactions may not be nested.\n" \
|
96
|
+
"Already inside #{transaction.inspect}"
|
94
97
|
end
|
95
98
|
|
96
99
|
sampled = trace_context ? trace_context.recorded? : random_sample?(config)
|
@@ -120,6 +123,8 @@ module ElasticAPM
|
|
120
123
|
|
121
124
|
enqueue.call transaction
|
122
125
|
|
126
|
+
update_transaction_metrics(transaction)
|
127
|
+
|
123
128
|
transaction
|
124
129
|
end
|
125
130
|
|
@@ -161,8 +166,9 @@ module ElasticAPM
|
|
161
166
|
name: name,
|
162
167
|
subtype: subtype,
|
163
168
|
action: action,
|
164
|
-
|
165
|
-
|
169
|
+
transaction: transaction,
|
170
|
+
parent: parent,
|
171
|
+
trace_context: trace_context,
|
166
172
|
type: type,
|
167
173
|
context: context,
|
168
174
|
stacktrace_builder: stacktrace_builder
|
@@ -187,6 +193,8 @@ module ElasticAPM
|
|
187
193
|
|
188
194
|
enqueue.call span
|
189
195
|
|
196
|
+
update_span_metrics(span)
|
197
|
+
|
190
198
|
span
|
191
199
|
end
|
192
200
|
|
@@ -220,6 +228,71 @@ module ElasticAPM
|
|
220
228
|
def random_sample?(config)
|
221
229
|
rand <= config.transaction_sample_rate
|
222
230
|
end
|
231
|
+
|
232
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
233
|
+
def update_transaction_metrics(transaction)
|
234
|
+
return unless transaction.config.collect_metrics?
|
235
|
+
|
236
|
+
tags = {
|
237
|
+
'transaction.name': transaction.name,
|
238
|
+
'transaction.type': transaction.type
|
239
|
+
}
|
240
|
+
|
241
|
+
@metrics.get(:transaction).timer(
|
242
|
+
:'transaction.duration.sum.us',
|
243
|
+
tags: tags, reset_on_collect: true
|
244
|
+
).update(transaction.duration)
|
245
|
+
|
246
|
+
@metrics.get(:transaction).counter(
|
247
|
+
:'transaction.duration.count',
|
248
|
+
tags: tags, reset_on_collect: true
|
249
|
+
).inc!
|
250
|
+
|
251
|
+
return unless transaction.sampled?
|
252
|
+
return unless transaction.config.breakdown_metrics?
|
253
|
+
|
254
|
+
@metrics.get(:breakdown).counter(
|
255
|
+
:'transaction.breakdown.count',
|
256
|
+
tags: tags, reset_on_collect: true
|
257
|
+
).inc!
|
258
|
+
|
259
|
+
span_tags = tags.merge('span.type': 'app')
|
260
|
+
|
261
|
+
@metrics.get(:breakdown).timer(
|
262
|
+
:'span.self_time.sum.us',
|
263
|
+
tags: span_tags, reset_on_collect: true
|
264
|
+
).update(transaction.self_time)
|
265
|
+
|
266
|
+
@metrics.get(:breakdown).counter(
|
267
|
+
:'span.self_time.count',
|
268
|
+
tags: span_tags, reset_on_collect: true
|
269
|
+
).inc!
|
270
|
+
end
|
271
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
272
|
+
|
273
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
274
|
+
def update_span_metrics(span)
|
275
|
+
return unless span.transaction.config.breakdown_metrics?
|
276
|
+
|
277
|
+
tags = {
|
278
|
+
'span.type': span.type,
|
279
|
+
'transaction.name': span.transaction.name,
|
280
|
+
'transaction.type': span.transaction.type
|
281
|
+
}
|
282
|
+
|
283
|
+
tags[:'span.subtype'] = span.subtype if span.subtype
|
284
|
+
|
285
|
+
@metrics.get(:breakdown).timer(
|
286
|
+
:'span.self_time.sum.us',
|
287
|
+
tags: tags, reset_on_collect: true
|
288
|
+
).update(span.self_time)
|
289
|
+
|
290
|
+
@metrics.get(:breakdown).counter(
|
291
|
+
:'span.self_time.count',
|
292
|
+
tags: tags, reset_on_collect: true
|
293
|
+
).inc!
|
294
|
+
end
|
295
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
223
296
|
end
|
224
297
|
# rubocop:enable Metrics/ClassLength
|
225
298
|
end
|
data/lib/elastic_apm/logging.rb
CHANGED
data/lib/elastic_apm/metrics.rb
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'elastic_apm/metricset'
|
4
|
-
|
5
3
|
module ElasticAPM
|
6
4
|
# @api private
|
7
5
|
module Metrics
|
8
|
-
MUTEX = Mutex.new
|
9
|
-
|
10
6
|
def self.new(config, &block)
|
11
|
-
|
7
|
+
Registry.new(config, &block)
|
12
8
|
end
|
13
9
|
|
14
10
|
def self.platform
|
@@ -16,24 +12,19 @@ module ElasticAPM
|
|
16
12
|
end
|
17
13
|
|
18
14
|
# @api private
|
19
|
-
class
|
15
|
+
class Registry
|
20
16
|
include Logging
|
21
17
|
|
22
18
|
TIMEOUT_INTERVAL = 5 # seconds
|
23
19
|
|
24
|
-
def initialize(config,
|
20
|
+
def initialize(config, &block)
|
25
21
|
@config = config
|
26
|
-
@labels = labels
|
27
|
-
@samplers = [CpuMem, VM].map do |kls|
|
28
|
-
debug "Adding metrics collector '#{kls}'"
|
29
|
-
kls.new(config)
|
30
|
-
end
|
31
22
|
@callback = block
|
32
23
|
end
|
33
24
|
|
34
|
-
attr_reader :config, :
|
25
|
+
attr_reader :config, :sets, :callback
|
35
26
|
|
36
|
-
# rubocop:disable Metrics/MethodLength
|
27
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
37
28
|
def start
|
38
29
|
unless config.collect_metrics?
|
39
30
|
debug 'Skipping metrics'
|
@@ -42,6 +33,16 @@ module ElasticAPM
|
|
42
33
|
|
43
34
|
debug 'Starting metrics'
|
44
35
|
|
36
|
+
@sets = {
|
37
|
+
system: CpuMemSet,
|
38
|
+
vm: VMSet,
|
39
|
+
breakdown: BreakdownSet,
|
40
|
+
transaction: TransactionSet
|
41
|
+
}.each_with_object({}) do |(key, kls), sets|
|
42
|
+
debug "Adding metrics collector '#{kls}'"
|
43
|
+
sets[key] = kls.new(config)
|
44
|
+
end
|
45
|
+
|
45
46
|
@timer_task = Concurrent::TimerTask.execute(
|
46
47
|
run_now: true,
|
47
48
|
execution_interval: config.metrics_interval,
|
@@ -60,7 +61,7 @@ module ElasticAPM
|
|
60
61
|
|
61
62
|
@running = true
|
62
63
|
end
|
63
|
-
# rubocop:enable Metrics/MethodLength
|
64
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
64
65
|
|
65
66
|
def stop
|
66
67
|
return unless running?
|
@@ -75,24 +76,36 @@ module ElasticAPM
|
|
75
76
|
!!@running
|
76
77
|
end
|
77
78
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
79
|
+
def get(key)
|
80
|
+
sets.fetch(key)
|
81
|
+
end
|
81
82
|
|
82
|
-
|
83
|
+
def collect_and_send
|
84
|
+
metricsets = collect
|
85
|
+
metricsets.compact!
|
86
|
+
metricsets.each do |m|
|
87
|
+
callback.call(m)
|
88
|
+
end
|
83
89
|
end
|
84
90
|
|
85
91
|
def collect
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
92
|
+
sets.each_value.each_with_object([]) do |set, arr|
|
93
|
+
samples = set.collect
|
94
|
+
next unless samples
|
95
|
+
arr.concat(samples)
|
91
96
|
end
|
92
97
|
end
|
93
98
|
end
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
97
|
-
require 'elastic_apm/
|
98
|
-
|
102
|
+
require 'elastic_apm/metricset'
|
103
|
+
|
104
|
+
require 'elastic_apm/metrics/metric'
|
105
|
+
require 'elastic_apm/metrics/set'
|
106
|
+
|
107
|
+
require 'elastic_apm/metrics/cpu_mem_set'
|
108
|
+
require 'elastic_apm/metrics/vm_set'
|
109
|
+
require 'elastic_apm/metrics/span_scoped_set'
|
110
|
+
require 'elastic_apm/metrics/transaction_set'
|
111
|
+
require 'elastic_apm/metrics/breakdown_set'
|
@@ -3,100 +3,108 @@
|
|
3
3
|
module ElasticAPM
|
4
4
|
module Metrics
|
5
5
|
# @api private
|
6
|
-
class
|
6
|
+
class CpuMemSet < Set
|
7
7
|
include Logging
|
8
8
|
|
9
9
|
# @api private
|
10
10
|
class Sample
|
11
11
|
# rubocop:disable Metrics/ParameterLists
|
12
12
|
def initialize(
|
13
|
+
page_size:,
|
14
|
+
process_cpu_usage:,
|
15
|
+
process_memory_rss:,
|
16
|
+
process_memory_size:,
|
13
17
|
system_cpu_total:,
|
14
18
|
system_cpu_usage:,
|
15
|
-
system_memory_total:,
|
16
19
|
system_memory_free:,
|
17
|
-
|
18
|
-
process_memory_size:,
|
19
|
-
process_memory_rss:,
|
20
|
-
page_size:
|
20
|
+
system_memory_total:
|
21
21
|
)
|
22
|
+
@page_size = page_size
|
23
|
+
@process_cpu_usage = process_cpu_usage
|
24
|
+
@process_memory_rss = process_memory_rss
|
25
|
+
@process_memory_size = process_memory_size
|
22
26
|
@system_cpu_total = system_cpu_total
|
23
27
|
@system_cpu_usage = system_cpu_usage
|
24
|
-
@system_memory_total = system_memory_total
|
25
28
|
@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
|
29
|
+
@system_memory_total = system_memory_total
|
30
30
|
end
|
31
31
|
# rubocop:enable Metrics/ParameterLists
|
32
32
|
|
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
|
33
|
+
attr_accessor(
|
34
|
+
:page_size,
|
35
|
+
:process_cpu_usage,
|
36
|
+
:process_memory_rss,
|
37
|
+
:process_memory_size,
|
38
|
+
:system_cpu_total,
|
39
|
+
:system_cpu_usage,
|
40
|
+
:system_memory_free,
|
41
|
+
:system_memory_total
|
42
|
+
)
|
47
43
|
end
|
48
44
|
|
49
45
|
def initialize(config)
|
50
|
-
|
46
|
+
super
|
47
|
+
|
51
48
|
@sampler = sampler_for_platform(Metrics.platform)
|
49
|
+
read! # set @previous on boot
|
52
50
|
end
|
53
51
|
|
54
|
-
attr_reader :config
|
52
|
+
attr_reader :config
|
55
53
|
|
56
|
-
def
|
57
|
-
|
54
|
+
def collect
|
55
|
+
read!
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def sampler_for_platform(platform)
|
62
|
+
case platform
|
63
|
+
when :linux then Linux.new
|
64
|
+
else
|
65
|
+
warn "Unsupported platform '#{platform}' - Disabling system metrics"
|
66
|
+
disable!
|
67
|
+
nil
|
68
|
+
end
|
58
69
|
end
|
59
70
|
|
60
71
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
61
|
-
def
|
62
|
-
return
|
72
|
+
def read!
|
73
|
+
return if disabled?
|
63
74
|
|
64
|
-
current = sample
|
75
|
+
current = @sampler.sample
|
65
76
|
|
66
77
|
unless @previous
|
67
78
|
@previous = current
|
68
79
|
return
|
69
80
|
end
|
70
81
|
|
71
|
-
|
82
|
+
cpu_usage_pct, cpu_process_pct = calculate_deltas(current, @previous)
|
72
83
|
|
73
|
-
|
74
|
-
|
84
|
+
gauge(:'system.cpu.total.norm.pct').value = cpu_usage_pct
|
85
|
+
gauge(:'system.memory.actual.free').value = current.system_memory_free
|
86
|
+
gauge(:'system.memory.total').value = current.system_memory_total
|
87
|
+
gauge(:'system.process.cpu.total.norm.pct').value = cpu_process_pct
|
88
|
+
gauge(:'system.process.memory.size').value = current.process_memory_size
|
89
|
+
gauge(:'system.process.memory.rss.bytes').value =
|
90
|
+
current.process_memory_rss * current.page_size
|
75
91
|
|
76
92
|
@previous = current
|
77
|
-
|
78
|
-
{
|
79
|
-
'system.cpu.total.norm.pct': cpu_usage_pct,
|
80
|
-
'system.memory.actual.free': current.system_memory_free,
|
81
|
-
'system.memory.total': current.system_memory_total,
|
82
|
-
'system.process.cpu.total.norm.pct': cpu_process_pct,
|
83
|
-
'system.process.memory.size': current.process_memory_size,
|
84
|
-
'system.process.memory.rss.bytes':
|
85
|
-
current.process_memory_rss * current.page_size
|
86
|
-
}
|
87
93
|
end
|
88
94
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
89
95
|
|
90
|
-
|
96
|
+
def calculate_deltas(current, previous)
|
97
|
+
system_cpu_total =
|
98
|
+
current.system_cpu_total - previous.system_cpu_total
|
99
|
+
system_cpu_usage =
|
100
|
+
current.system_cpu_usage - previous.system_cpu_usage
|
101
|
+
process_cpu_usage =
|
102
|
+
current.process_cpu_usage - previous.process_cpu_usage
|
91
103
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
warn "Unsupported platform '#{platform}' - Disabling metrics"
|
97
|
-
@disabled = true
|
98
|
-
nil
|
99
|
-
end
|
104
|
+
cpu_usage_pct = system_cpu_usage.to_f / system_cpu_total
|
105
|
+
cpu_process_pct = process_cpu_usage.to_f / system_cpu_total
|
106
|
+
|
107
|
+
[cpu_usage_pct, cpu_process_pct]
|
100
108
|
end
|
101
109
|
|
102
110
|
# @api private
|