elastic-apm 4.5.0 → 4.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ci/.jenkins_exclude.yml +86 -29
- data/.ci/.jenkins_framework.yml +4 -3
- data/.ci/{.jenkins_master_framework.yml → .jenkins_main_framework.yml} +0 -0
- data/.ci/.jenkins_ruby.yml +1 -1
- data/.ci/.jenkins_ruby_benchmarks.yml +6 -0
- data/.ci/Jenkinsfile +16 -37
- data/.ci/jobs/apm-agent-ruby-mbp.yml +1 -1
- data/.github/PULL_REQUEST_TEMPLATE.md +5 -5
- data/.pre-commit-config.yaml +2 -2
- data/CHANGELOG.asciidoc +38 -0
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +11 -2
- data/README.md +1 -1
- data/Rakefile +2 -2
- data/bench/report.rb +1 -1
- data/docs/api.asciidoc +2 -2
- data/docs/configuration.asciidoc +7 -5
- data/docs/introduction.asciidoc +3 -3
- data/docs/log-correlation.asciidoc +1 -1
- data/docs/upgrading.asciidoc +1 -1
- data/elastic-apm.gemspec +3 -2
- data/lib/elastic_apm/central_config.rb +5 -0
- data/lib/elastic_apm/config/server_info.rb +50 -0
- data/lib/elastic_apm/config.rb +25 -4
- data/lib/elastic_apm/error.rb +2 -1
- data/lib/elastic_apm/error_builder.rb +1 -0
- data/lib/elastic_apm/instrumenter.rb +4 -2
- data/lib/elastic_apm/metadata/system_info/container_info.rb +4 -3
- data/lib/elastic_apm/metadata/system_info.rb +1 -1
- data/lib/elastic_apm/metrics.rb +1 -4
- data/lib/elastic_apm/span/context/links.rb +32 -0
- data/lib/elastic_apm/span/context/service.rb +55 -0
- data/lib/elastic_apm/span/context.rb +19 -3
- data/lib/elastic_apm/span.rb +3 -0
- data/lib/elastic_apm/span_helpers.rb +2 -2
- data/lib/elastic_apm/spies/elasticsearch.rb +11 -1
- data/lib/elastic_apm/spies/mongo.rb +5 -12
- data/lib/elastic_apm/spies/racecar.rb +77 -0
- data/lib/elastic_apm/spies/redis.rb +1 -1
- data/lib/elastic_apm/spies/sequel.rb +9 -0
- data/lib/elastic_apm/spies/sns.rb +1 -1
- data/lib/elastic_apm/spies/sqs.rb +1 -0
- data/lib/elastic_apm/trace_context/tracestate.rb +1 -1
- data/lib/elastic_apm/trace_context.rb +1 -1
- data/lib/elastic_apm/transport/base.rb +1 -3
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +25 -0
- data/lib/elastic_apm/version.rb +1 -1
- data/lib/elastic_apm.rb +1 -0
- metadata +29 -9
data/elastic-apm.gemspec
CHANGED
@@ -22,8 +22,8 @@ require 'elastic_apm/version'
|
|
22
22
|
Gem::Specification.new do |spec|
|
23
23
|
spec.name = 'elastic-apm'
|
24
24
|
spec.version = ElasticAPM::VERSION
|
25
|
-
spec.authors = ['Mikkel Malmberg']
|
26
|
-
spec.email = ['
|
25
|
+
spec.authors = ['Mikkel Malmberg', 'Emily Stolfo']
|
26
|
+
spec.email = ['info@elastic.co']
|
27
27
|
|
28
28
|
spec.summary = 'The official Elastic APM agent for Ruby'
|
29
29
|
spec.homepage = 'https://github.com/elastic/apm-agent-ruby'
|
@@ -37,6 +37,7 @@ Gem::Specification.new do |spec|
|
|
37
37
|
|
38
38
|
spec.add_dependency('concurrent-ruby', '~> 1.0')
|
39
39
|
spec.add_dependency('http', '>= 3.0')
|
40
|
+
spec.add_runtime_dependency('ruby2_keywords')
|
40
41
|
|
41
42
|
spec.require_paths = ['lib']
|
42
43
|
end
|
@@ -181,6 +181,11 @@ module ElasticAPM
|
|
181
181
|
DEFAULT_MAX_AGE
|
182
182
|
end
|
183
183
|
|
184
|
+
if seconds < 5
|
185
|
+
debug "Next fetch is too low (#{seconds}s) - increasing to default"
|
186
|
+
seconds = 5
|
187
|
+
end
|
188
|
+
|
184
189
|
@scheduled_task =
|
185
190
|
Concurrent::ScheduledTask
|
186
191
|
.execute(seconds) { fetch_and_apply_config }
|
@@ -0,0 +1,50 @@
|
|
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 ElasticAPM
|
21
|
+
class Config
|
22
|
+
# @api private
|
23
|
+
class ServerInfo
|
24
|
+
attr_reader :payload, :config, :http
|
25
|
+
|
26
|
+
VERSION_8_0 = '8.0'
|
27
|
+
VERSION_0 = '0'
|
28
|
+
|
29
|
+
def initialize(config)
|
30
|
+
@config = config
|
31
|
+
@http = Transport::Connection::Http.new(config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute
|
35
|
+
resp = http.get(config.server_url)
|
36
|
+
@payload = JSON.parse(resp.body)
|
37
|
+
rescue
|
38
|
+
@payload = { "version" => VERSION_0 }
|
39
|
+
end
|
40
|
+
|
41
|
+
def version
|
42
|
+
@version ||= begin
|
43
|
+
execute
|
44
|
+
payload["version"] ? payload["version"].to_s : VERSION_0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/elastic_apm/config.rb
CHANGED
@@ -24,14 +24,17 @@ require 'elastic_apm/config/options'
|
|
24
24
|
require 'elastic_apm/config/round_float'
|
25
25
|
require 'elastic_apm/config/regexp_list'
|
26
26
|
require 'elastic_apm/config/wildcard_pattern_list'
|
27
|
+
require 'elastic_apm/deprecations'
|
28
|
+
require 'elastic_apm/config/server_info'
|
27
29
|
|
28
30
|
module ElasticAPM
|
29
31
|
# @api private
|
30
32
|
class Config
|
31
33
|
extend Options
|
34
|
+
extend Deprecations
|
32
35
|
|
33
36
|
SANITIZE_FIELD_NAMES_DEFAULT =
|
34
|
-
%w[password passwd pwd secret *key *token* *session* *credit* *card*
|
37
|
+
%w[password passwd pwd secret *key *token* *session* *credit* *card* *auth* set-cookie].freeze
|
35
38
|
|
36
39
|
# rubocop:disable Layout/LineLength, Layout/ExtraSpacing
|
37
40
|
option :config_file, type: :string, default: 'config/elastic_apm.yml'
|
@@ -70,7 +73,7 @@ module ElasticAPM
|
|
70
73
|
option :ignore_url_patterns, type: :list, default: [], converter: RegexpList.new
|
71
74
|
option :instrument, type: :bool, default: true
|
72
75
|
option :instrumented_rake_tasks, type: :list, default: []
|
73
|
-
option :
|
76
|
+
option :log_ecs_reformatting, type: :string, default: 'off'
|
74
77
|
option :log_level, type: :int, default: Logger::INFO, converter: LogLevelMap.new
|
75
78
|
option :log_path, type: :string
|
76
79
|
option :metrics_interval, type: :int, default: '30s', converter: Duration.new
|
@@ -98,6 +101,16 @@ module ElasticAPM
|
|
98
101
|
option :use_elastic_traceparent_header, type: :bool, default: true
|
99
102
|
option :verify_server_cert, type: :bool, default: true
|
100
103
|
|
104
|
+
def log_ecs_formatting
|
105
|
+
log_ecs_reformatting
|
106
|
+
end
|
107
|
+
|
108
|
+
def log_ecs_formatting=(value)
|
109
|
+
@options[:log_ecs_reformatting].set(value)
|
110
|
+
end
|
111
|
+
|
112
|
+
deprecate :log_ecs_formatting, :log_ecs_reformatting
|
113
|
+
|
101
114
|
# rubocop:enable Layout/LineLength, Layout/ExtraSpacing
|
102
115
|
def initialize(options = {})
|
103
116
|
@options = load_schema
|
@@ -116,7 +129,9 @@ module ElasticAPM
|
|
116
129
|
|
117
130
|
yield self if block_given?
|
118
131
|
|
119
|
-
self.logger
|
132
|
+
if self.logger.nil? || self.log_path
|
133
|
+
self.logger = build_logger
|
134
|
+
end
|
120
135
|
|
121
136
|
@__view_paths ||= []
|
122
137
|
@__root_path ||= Dir.pwd
|
@@ -144,6 +159,7 @@ module ElasticAPM
|
|
144
159
|
mongo
|
145
160
|
net_http
|
146
161
|
rake
|
162
|
+
racecar
|
147
163
|
redis
|
148
164
|
resque
|
149
165
|
s3
|
@@ -229,6 +245,10 @@ module ElasticAPM
|
|
229
245
|
super.split.first + '>'
|
230
246
|
end
|
231
247
|
|
248
|
+
def version
|
249
|
+
@version ||= ServerInfo.new(self).version
|
250
|
+
end
|
251
|
+
|
232
252
|
private
|
233
253
|
|
234
254
|
def load_config_file
|
@@ -247,7 +267,7 @@ module ElasticAPM
|
|
247
267
|
end
|
248
268
|
|
249
269
|
def build_logger
|
250
|
-
if self.
|
270
|
+
if self.log_ecs_reformatting == 'override'
|
251
271
|
begin
|
252
272
|
return build_ecs_logger
|
253
273
|
rescue LoadError
|
@@ -294,6 +314,7 @@ module ElasticAPM
|
|
294
314
|
self.framework_name ||= 'Ruby on Rails'
|
295
315
|
self.framework_version ||= ::Rails::VERSION::STRING
|
296
316
|
self.logger ||= ::Rails.logger
|
317
|
+
self.log_level ||= ::Rails.logger.log_level
|
297
318
|
|
298
319
|
self.__root_path = ::Rails.root.to_s
|
299
320
|
self.__view_paths = app.config.paths['app/views'].existent +
|
data/lib/elastic_apm/error.rb
CHANGED
@@ -33,7 +33,7 @@ module ElasticAPM
|
|
33
33
|
end
|
34
34
|
|
35
35
|
attr_accessor :id, :culprit, :exception, :log, :transaction_id,
|
36
|
-
:transaction, :context, :parent_id, :trace_id
|
36
|
+
:transaction_name, :transaction, :context, :parent_id, :trace_id
|
37
37
|
attr_reader :timestamp
|
38
38
|
|
39
39
|
def inspect
|
@@ -41,6 +41,7 @@ module ElasticAPM
|
|
41
41
|
" culprit:#{culprit}" \
|
42
42
|
" timestamp:#{timestamp}" \
|
43
43
|
" transaction_id:#{transaction_id}" \
|
44
|
+
" transaction_name:#{transaction_name}" \
|
44
45
|
" trace_id:#{trace_id}" \
|
45
46
|
" exception:#{exception.inspect}" \
|
46
47
|
'>'
|
@@ -124,7 +124,7 @@ module ElasticAPM
|
|
124
124
|
sample_rate = trace_context.tracestate.sample_rate
|
125
125
|
else
|
126
126
|
sampled = random_sample?(config)
|
127
|
-
sample_rate = config.transaction_sample_rate
|
127
|
+
sample_rate = sampled ? config.transaction_sample_rate : 0
|
128
128
|
end
|
129
129
|
|
130
130
|
transaction =
|
@@ -150,7 +150,9 @@ module ElasticAPM
|
|
150
150
|
|
151
151
|
transaction.done result
|
152
152
|
|
153
|
-
|
153
|
+
if transaction.sampled? || @config.version < Config::ServerInfo::VERSION_8_0
|
154
|
+
enqueue.call transaction
|
155
|
+
end
|
154
156
|
|
155
157
|
update_transaction_metrics(transaction)
|
156
158
|
|
@@ -33,14 +33,15 @@ module ElasticAPM
|
|
33
33
|
|
34
34
|
attr_reader :cgroup_path
|
35
35
|
|
36
|
-
def read!
|
36
|
+
def read!(hostname)
|
37
37
|
read_from_cgroup!
|
38
|
+
self.kubernetes_pod_name = hostname if kubernetes_pod_uid
|
38
39
|
read_from_env!
|
39
40
|
self
|
40
41
|
end
|
41
42
|
|
42
|
-
def self.read!
|
43
|
-
new.read!
|
43
|
+
def self.read!(hostname)
|
44
|
+
new.read!(hostname)
|
44
45
|
end
|
45
46
|
|
46
47
|
def container
|
@@ -29,7 +29,7 @@ module ElasticAPM
|
|
29
29
|
@architecture = gem_platform.cpu
|
30
30
|
@platform = gem_platform.os
|
31
31
|
|
32
|
-
container_info = ContainerInfo.read!
|
32
|
+
container_info = ContainerInfo.read!(@detected_hostname)
|
33
33
|
@container = container_info.container
|
34
34
|
@kubernetes = container_info.kubernetes
|
35
35
|
end
|
data/lib/elastic_apm/metrics.rb
CHANGED
@@ -36,8 +36,6 @@ module ElasticAPM
|
|
36
36
|
class Registry
|
37
37
|
include Logging
|
38
38
|
|
39
|
-
TIMEOUT_INTERVAL = 5 # seconds
|
40
|
-
|
41
39
|
def initialize(config, &block)
|
42
40
|
@config = config
|
43
41
|
@callback = block
|
@@ -76,8 +74,7 @@ module ElasticAPM
|
|
76
74
|
|
77
75
|
@timer_task = Concurrent::TimerTask.execute(
|
78
76
|
run_now: true,
|
79
|
-
execution_interval: config.metrics_interval
|
80
|
-
timeout_interval: TIMEOUT_INTERVAL
|
77
|
+
execution_interval: config.metrics_interval
|
81
78
|
) do
|
82
79
|
begin
|
83
80
|
debug 'Collecting metrics'
|
@@ -0,0 +1,32 @@
|
|
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 ElasticAPM
|
21
|
+
class Span
|
22
|
+
class Context
|
23
|
+
# @api private
|
24
|
+
class Links < Array
|
25
|
+
# @api private
|
26
|
+
class Link < Struct.new(:trace_id, :span_id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,55 @@
|
|
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 ElasticAPM
|
21
|
+
class Span
|
22
|
+
class Context
|
23
|
+
# @api private
|
24
|
+
class Service
|
25
|
+
include Fields
|
26
|
+
|
27
|
+
field :target
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
class Target
|
31
|
+
include Fields
|
32
|
+
|
33
|
+
field :name, default: ''
|
34
|
+
field :type, default: ''
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(target: nil, **attrs)
|
38
|
+
super(**attrs)
|
39
|
+
|
40
|
+
self.target = build_target(target)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def build_target(target = nil)
|
46
|
+
return Target.new unless target
|
47
|
+
return target if target.is_a?(Target)
|
48
|
+
|
49
|
+
Target.new(**target)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -27,7 +27,9 @@ module ElasticAPM
|
|
27
27
|
http: nil,
|
28
28
|
labels: {},
|
29
29
|
sync: nil,
|
30
|
-
message: nil
|
30
|
+
message: nil,
|
31
|
+
service: nil,
|
32
|
+
links: nil
|
31
33
|
)
|
32
34
|
@sync = sync
|
33
35
|
@db = db && Db.new(**db)
|
@@ -43,6 +45,16 @@ module ElasticAPM
|
|
43
45
|
when Hash then Message.new(**message)
|
44
46
|
end
|
45
47
|
@labels = labels
|
48
|
+
@service =
|
49
|
+
case service
|
50
|
+
when Service then service
|
51
|
+
when Hash then Service.new(**service)
|
52
|
+
end
|
53
|
+
@links =
|
54
|
+
case links
|
55
|
+
when Links then links
|
56
|
+
when Array then Links.new(links)
|
57
|
+
end
|
46
58
|
end
|
47
59
|
|
48
60
|
attr_reader(
|
@@ -50,10 +62,11 @@ module ElasticAPM
|
|
50
62
|
:http,
|
51
63
|
:labels,
|
52
64
|
:sync,
|
53
|
-
:message
|
65
|
+
:message,
|
66
|
+
:links
|
54
67
|
)
|
55
68
|
|
56
|
-
attr_accessor :destination
|
69
|
+
attr_accessor :destination, :service
|
57
70
|
end
|
58
71
|
end
|
59
72
|
end
|
@@ -62,3 +75,6 @@ require 'elastic_apm/span/context/db'
|
|
62
75
|
require 'elastic_apm/span/context/http'
|
63
76
|
require 'elastic_apm/span/context/destination'
|
64
77
|
require 'elastic_apm/span/context/message'
|
78
|
+
require 'elastic_apm/span/context/service'
|
79
|
+
require 'elastic_apm/span/context/links'
|
80
|
+
|
data/lib/elastic_apm/span.rb
CHANGED
@@ -145,6 +145,9 @@ module ElasticAPM
|
|
145
145
|
service: service,
|
146
146
|
cloud: cloud
|
147
147
|
)
|
148
|
+
context.service = Span::Context::Service.new(
|
149
|
+
target: Span::Context::Service::Target.new(name: context.destination.service.name, type: context.destination.service.type )
|
150
|
+
)
|
148
151
|
end
|
149
152
|
|
150
153
|
def inspect
|
@@ -37,7 +37,7 @@ module ElasticAPM
|
|
37
37
|
type ||= Span::DEFAULT_TYPE
|
38
38
|
|
39
39
|
klass.prepend(Module.new do
|
40
|
-
define_method(method) do |*args, &block|
|
40
|
+
ruby2_keywords(define_method(method) do |*args, &block|
|
41
41
|
unless ElasticAPM.current_transaction
|
42
42
|
return super(*args, &block)
|
43
43
|
end
|
@@ -45,7 +45,7 @@ module ElasticAPM
|
|
45
45
|
ElasticAPM.with_span name.to_s, type.to_s do
|
46
46
|
super(*args, &block)
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end)
|
49
49
|
end)
|
50
50
|
end
|
51
51
|
end
|
@@ -79,7 +79,11 @@ module ElasticAPM
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def install
|
82
|
-
::
|
82
|
+
if defined?(::Elastic::Transport::Client)
|
83
|
+
::Elastic::Transport::Client.prepend(Ext)
|
84
|
+
elsif defined?(::Elasticsearch::Transport::Client)
|
85
|
+
::Elasticsearch::Transport::Client.prepend(Ext)
|
86
|
+
end
|
83
87
|
end
|
84
88
|
end
|
85
89
|
|
@@ -88,5 +92,11 @@ module ElasticAPM
|
|
88
92
|
'elasticsearch-transport',
|
89
93
|
ElasticsearchSpy.new
|
90
94
|
)
|
95
|
+
|
96
|
+
register(
|
97
|
+
'Elastic::Transport::Client',
|
98
|
+
'elastic-transport',
|
99
|
+
ElasticsearchSpy.new
|
100
|
+
)
|
91
101
|
end
|
92
102
|
end
|
@@ -37,14 +37,8 @@ module ElasticAPM
|
|
37
37
|
|
38
38
|
EVENT_KEY = :__elastic_instrumenter_mongo_events_key
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
Thread.current[EVENT_KEY] ||= {}
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def initialize
|
47
|
-
@collection = Collection.new
|
40
|
+
def events
|
41
|
+
Thread.current[EVENT_KEY] ||= []
|
48
42
|
end
|
49
43
|
|
50
44
|
def started(event)
|
@@ -78,7 +72,7 @@ module ElasticAPM
|
|
78
72
|
# and the collection name is at the key `collection`
|
79
73
|
collection =
|
80
74
|
if event.command[event.command_name] == 1 ||
|
81
|
-
|
75
|
+
event.command[event.command_name].is_a?(BSON::Int64)
|
82
76
|
event.command[:collection]
|
83
77
|
else
|
84
78
|
event.command[event.command_name]
|
@@ -97,14 +91,13 @@ module ElasticAPM
|
|
97
91
|
context: build_context(event)
|
98
92
|
)
|
99
93
|
|
100
|
-
|
94
|
+
events << span
|
101
95
|
end
|
102
96
|
|
103
97
|
def pop_event(event)
|
104
|
-
span = @collection.events.delete(event.operation_id)
|
105
98
|
return unless (curr = ElasticAPM.current_span)
|
106
99
|
|
107
|
-
curr ==
|
100
|
+
curr == events[-1] && ElasticAPM.end_span(events.pop)
|
108
101
|
end
|
109
102
|
|
110
103
|
def build_context(event)
|
@@ -0,0 +1,77 @@
|
|
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
|
+
begin
|
19
|
+
require 'active_support/notifications'
|
20
|
+
require 'active_support/subscriber'
|
21
|
+
|
22
|
+
# frozen_string_literal: true
|
23
|
+
module ElasticAPM
|
24
|
+
# @api private
|
25
|
+
module Spies
|
26
|
+
# @api private
|
27
|
+
class RacecarSpy
|
28
|
+
TYPE = 'kafka'
|
29
|
+
SUBTYPE = 'racecar'
|
30
|
+
|
31
|
+
# @api private
|
32
|
+
class ConsumerSubscriber < ActiveSupport::Subscriber
|
33
|
+
def start_process_message(event)
|
34
|
+
start_process_transaction(event: event, kind: 'process_message')
|
35
|
+
end
|
36
|
+
def process_message(_event)
|
37
|
+
ElasticAPM.end_transaction
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_process_batch(event)
|
41
|
+
start_process_transaction(event: event, kind: 'process_batch')
|
42
|
+
end
|
43
|
+
def process_batch(_event)
|
44
|
+
ElasticAPM.end_transaction
|
45
|
+
end
|
46
|
+
|
47
|
+
private # only public methods will be subscribed
|
48
|
+
|
49
|
+
def start_process_transaction(event:, kind:)
|
50
|
+
ElasticAPM.start_transaction(kind, TYPE)
|
51
|
+
ElasticAPM.current_transaction.context.set_service(framework_name: 'racecar', framework_version: Racecar::VERSION)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ProducerSubscriber < ActiveSupport::Subscriber
|
56
|
+
def start_deliver_message(event)
|
57
|
+
ElasticAPM.start_transaction('deliver_message',TYPE)
|
58
|
+
ElasticAPM.current_transaction.context.set_service(framework_name: 'racecar', framework_version: Racecar::VERSION)
|
59
|
+
end
|
60
|
+
|
61
|
+
def deliver_message(_event)
|
62
|
+
ElasticAPM.end_transaction
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def install
|
67
|
+
ConsumerSubscriber.attach_to(:racecar)
|
68
|
+
ProducerSubscriber.attach_to(:racecar)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
register 'Racecar', 'racecar', RacecarSpy.new
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
rescue LoadError
|
76
|
+
# no active support available
|
77
|
+
end
|
@@ -44,8 +44,17 @@ module ElasticAPM
|
|
44
44
|
name =
|
45
45
|
ElasticAPM::Spies::SequelSpy.summarizer.summarize sql
|
46
46
|
|
47
|
+
db_name = ''
|
48
|
+
# postgresql shows current database
|
49
|
+
db_name = connection&.db.to_s if connection.respond_to?(:db)
|
50
|
+
# sqlite may expose a filename
|
51
|
+
db_name = connection&.filename.to_s if db_name == '' && connection.respond_to?(:filename)
|
52
|
+
# fall back to adapter class name
|
53
|
+
db_name = connection.class.to_s if db_name == ''
|
54
|
+
|
47
55
|
context = ElasticAPM::Span::Context.new(
|
48
56
|
db: { statement: sql, type: 'sql', user: opts[:user] },
|
57
|
+
service: {target: {type: subtype, name: db_name }},
|
49
58
|
destination: { service: { resource: subtype } }
|
50
59
|
)
|
51
60
|
|
@@ -35,7 +35,6 @@ module ElasticAPM
|
|
35
35
|
include Logging
|
36
36
|
|
37
37
|
WATCHER_EXECUTION_INTERVAL = 5
|
38
|
-
WATCHER_TIMEOUT_INTERVAL = 4
|
39
38
|
WORKER_JOIN_TIMEOUT = 5
|
40
39
|
|
41
40
|
def initialize(config)
|
@@ -112,8 +111,7 @@ module ElasticAPM
|
|
112
111
|
|
113
112
|
def create_watcher
|
114
113
|
@watcher = Concurrent::TimerTask.execute(
|
115
|
-
execution_interval: WATCHER_EXECUTION_INTERVAL
|
116
|
-
timeout_interval: WATCHER_TIMEOUT_INTERVAL
|
114
|
+
execution_interval: WATCHER_EXECUTION_INTERVAL
|
117
115
|
) { ensure_worker_count }
|
118
116
|
end
|
119
117
|
|