elastic-apm 3.15.1 → 4.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 +13 -0
- data/.ci/.jenkins_ruby.yml +0 -1
- data/.ci/Jenkinsfile +1 -0
- data/.github/dependabot.yml +16 -0
- data/.rubocop.yml +0 -7
- data/CHANGELOG.asciidoc +77 -4
- data/Gemfile +4 -1
- data/README.md +12 -0
- data/SECURITY.md +7 -0
- data/bench/report.rb +1 -1
- data/bin/run-bdd +17 -0
- data/bin/run-tests +1 -1
- data/docker-compose.yml +1 -1
- data/docs/configuration.asciidoc +62 -147
- data/docs/release-notes.asciidoc +1 -0
- data/docs/upgrading.asciidoc +0 -27
- data/lib/elastic_apm.rb +12 -1
- data/lib/elastic_apm/agent.rb +7 -3
- data/lib/elastic_apm/central_config.rb +8 -7
- data/lib/elastic_apm/config.rb +2 -88
- data/lib/elastic_apm/config/regexp_list.rb +1 -1
- data/lib/elastic_apm/config/wildcard_pattern_list.rb +1 -1
- data/lib/elastic_apm/context/response.rb +1 -3
- data/lib/elastic_apm/fields.rb +88 -0
- data/lib/elastic_apm/grpc.rb +2 -4
- data/lib/elastic_apm/instrumenter.rb +1 -1
- data/lib/elastic_apm/metadata/cloud_info.rb +32 -5
- data/lib/elastic_apm/metadata/system_info.rb +14 -4
- data/lib/elastic_apm/metrics/cpu_mem_set.rb +1 -1
- data/lib/elastic_apm/normalizers.rb +2 -2
- data/lib/elastic_apm/normalizers/rails/active_record.rb +3 -3
- data/lib/elastic_apm/opentracing.rb +3 -2
- data/lib/elastic_apm/span.rb +26 -1
- data/lib/elastic_apm/span/context.rb +2 -1
- data/lib/elastic_apm/span/context/destination.rb +53 -40
- data/lib/elastic_apm/span_helpers.rb +6 -8
- data/lib/elastic_apm/spies.rb +20 -0
- data/lib/elastic_apm/spies/action_dispatch.rb +10 -9
- data/lib/elastic_apm/spies/azure_storage_table.rb +148 -0
- data/lib/elastic_apm/spies/dynamo_db.rb +12 -12
- data/lib/elastic_apm/spies/elasticsearch.rb +32 -29
- data/lib/elastic_apm/spies/faraday.rb +83 -63
- data/lib/elastic_apm/spies/http.rb +33 -34
- data/lib/elastic_apm/spies/mongo.rb +5 -3
- data/lib/elastic_apm/spies/net_http.rb +59 -56
- data/lib/elastic_apm/spies/rake.rb +28 -26
- data/lib/elastic_apm/spies/redis.rb +11 -10
- data/lib/elastic_apm/spies/resque.rb +18 -21
- data/lib/elastic_apm/spies/s3.rb +14 -15
- data/lib/elastic_apm/spies/sequel.rb +42 -48
- data/lib/elastic_apm/spies/sidekiq.rb +13 -15
- data/lib/elastic_apm/spies/sinatra.rb +20 -21
- data/lib/elastic_apm/spies/sns.rb +39 -44
- data/lib/elastic_apm/spies/sqs.rb +21 -31
- data/lib/elastic_apm/spies/tilt.rb +10 -9
- data/lib/elastic_apm/sql/tokenizer.rb +21 -5
- data/lib/elastic_apm/stacktrace_builder.rb +3 -1
- data/lib/elastic_apm/subscriber.rb +1 -0
- data/lib/elastic_apm/trace_context.rb +5 -13
- data/lib/elastic_apm/trace_context/traceparent.rb +5 -6
- data/lib/elastic_apm/transport/connection.rb +1 -1
- data/lib/elastic_apm/transport/connection/http.rb +4 -2
- data/lib/elastic_apm/transport/connection/proxy_pipe.rb +1 -2
- data/lib/elastic_apm/transport/filters/hash_sanitizer.rb +5 -23
- data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +3 -2
- data/lib/elastic_apm/transport/serializers/metricset_serializer.rb +2 -2
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +12 -12
- data/lib/elastic_apm/transport/user_agent.rb +3 -2
- data/lib/elastic_apm/transport/worker.rb +1 -1
- data/lib/elastic_apm/util/deep_dup.rb +1 -1
- data/lib/elastic_apm/version.rb +1 -1
- metadata +12 -9
- data/lib/elastic_apm/sql.rb +0 -36
- data/lib/elastic_apm/sql_summarizer.rb +0 -53
@@ -50,28 +50,21 @@ module ElasticAPM
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def self.span_context(queue_name, region)
|
53
|
-
cloud = ElasticAPM::Span::Context::Destination::Cloud.new(region: region)
|
54
|
-
|
55
53
|
ElasticAPM::Span::Context.new(
|
56
|
-
message: {
|
57
|
-
queue_name: queue_name
|
58
|
-
},
|
54
|
+
message: { queue_name: queue_name },
|
59
55
|
destination: {
|
60
|
-
resource:
|
61
|
-
|
62
|
-
name: SUBTYPE,
|
63
|
-
cloud: cloud
|
56
|
+
service: { resource: "#{SUBTYPE}/#{queue_name}" },
|
57
|
+
cloud: { region: region }
|
64
58
|
}
|
65
59
|
)
|
66
60
|
end
|
67
61
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
62
|
+
# @api private
|
63
|
+
module Ext
|
64
|
+
def self.prepended(mod)
|
72
65
|
def send_message(params = {}, options = {})
|
73
66
|
unless (transaction = ElasticAPM.current_transaction)
|
74
|
-
return
|
67
|
+
return super(params, options)
|
75
68
|
end
|
76
69
|
|
77
70
|
queue_name = ElasticAPM::Spies::SQSSpy.queue_name(params)
|
@@ -98,16 +91,14 @@ module ElasticAPM
|
|
98
91
|
end
|
99
92
|
|
100
93
|
ElasticAPM::Spies::SQSSpy.without_net_http do
|
101
|
-
|
94
|
+
super(params, options)
|
102
95
|
end
|
103
96
|
end
|
104
97
|
end
|
105
98
|
|
106
|
-
alias :send_message_batch_without_apm :send_message_batch
|
107
|
-
|
108
99
|
def send_message_batch(params = {}, options = {})
|
109
100
|
unless (transaction = ElasticAPM.current_transaction)
|
110
|
-
return
|
101
|
+
return super(params, options)
|
111
102
|
end
|
112
103
|
|
113
104
|
queue_name = ElasticAPM::Spies::SQSSpy.queue_name(params)
|
@@ -127,6 +118,7 @@ module ElasticAPM
|
|
127
118
|
context: context
|
128
119
|
) do |span|
|
129
120
|
trace_context = span&.trace_context || transaction.trace_context
|
121
|
+
|
130
122
|
trace_context.apply_headers do |key, value|
|
131
123
|
params[:entries].each do |message|
|
132
124
|
message[:message_attributes] ||= {}
|
@@ -137,16 +129,14 @@ module ElasticAPM
|
|
137
129
|
end
|
138
130
|
|
139
131
|
ElasticAPM::Spies::SQSSpy.without_net_http do
|
140
|
-
|
132
|
+
super(params, options)
|
141
133
|
end
|
142
134
|
end
|
143
135
|
end
|
144
136
|
|
145
|
-
alias :receive_message_without_apm :receive_message
|
146
|
-
|
147
137
|
def receive_message(params = {}, options = {})
|
148
138
|
unless ElasticAPM.current_transaction
|
149
|
-
return
|
139
|
+
return super(params, options)
|
150
140
|
end
|
151
141
|
|
152
142
|
queue_name = ElasticAPM::Spies::SQSSpy.queue_name(params)
|
@@ -166,16 +156,14 @@ module ElasticAPM
|
|
166
156
|
context: context
|
167
157
|
) do
|
168
158
|
ElasticAPM::Spies::SQSSpy.without_net_http do
|
169
|
-
|
159
|
+
super(params, options)
|
170
160
|
end
|
171
161
|
end
|
172
162
|
end
|
173
163
|
|
174
|
-
alias :delete_message_without_apm :delete_message
|
175
|
-
|
176
164
|
def delete_message(params = {}, options = {})
|
177
165
|
unless ElasticAPM.current_transaction
|
178
|
-
return
|
166
|
+
return super(params, options)
|
179
167
|
end
|
180
168
|
|
181
169
|
queue_name = ElasticAPM::Spies::SQSSpy.queue_name(params)
|
@@ -194,16 +182,14 @@ module ElasticAPM
|
|
194
182
|
context: context
|
195
183
|
) do
|
196
184
|
ElasticAPM::Spies::SQSSpy.without_net_http do
|
197
|
-
|
185
|
+
super(params, options)
|
198
186
|
end
|
199
187
|
end
|
200
188
|
end
|
201
189
|
|
202
|
-
alias :delete_message_batch_without_apm :delete_message_batch
|
203
|
-
|
204
190
|
def delete_message_batch(params = {}, options = {})
|
205
191
|
unless ElasticAPM.current_transaction
|
206
|
-
return
|
192
|
+
return super(params, options)
|
207
193
|
end
|
208
194
|
|
209
195
|
queue_name = ElasticAPM::Spies::SQSSpy.queue_name(params)
|
@@ -223,12 +209,16 @@ module ElasticAPM
|
|
223
209
|
context: context
|
224
210
|
) do
|
225
211
|
ElasticAPM::Spies::SQSSpy.without_net_http do
|
226
|
-
|
212
|
+
super(params, options)
|
227
213
|
end
|
228
214
|
end
|
229
215
|
end
|
230
216
|
end
|
231
217
|
end
|
218
|
+
|
219
|
+
def install
|
220
|
+
::Aws::SQS::Client.prepend(Ext)
|
221
|
+
end
|
232
222
|
end
|
233
223
|
|
234
224
|
register(
|
@@ -24,19 +24,20 @@ module ElasticAPM
|
|
24
24
|
class TiltSpy
|
25
25
|
TYPE = 'template.tilt'
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def render(*args, &block)
|
32
|
-
name = options[:__elastic_apm_template_name] || 'Unknown template'
|
27
|
+
# @api private
|
28
|
+
module Ext
|
29
|
+
def render(*args, &block)
|
30
|
+
name = options[:__elastic_apm_template_name] || 'Unknown template'
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
32
|
+
ElasticAPM.with_span name, TYPE do
|
33
|
+
super(*args, &block)
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
37
|
+
|
38
|
+
def install
|
39
|
+
::Tilt::Template.prepend(Ext)
|
40
|
+
end
|
40
41
|
end
|
41
42
|
|
42
43
|
register 'Tilt::Template', 'tilt/template', TiltSpy.new
|
@@ -69,7 +69,7 @@ module ElasticAPM
|
|
69
69
|
when '[' then scan_quoted_indentifier(']')
|
70
70
|
when '(' then LPAREN
|
71
71
|
when ')' then RPAREN
|
72
|
-
when '/' then
|
72
|
+
when '/' then scan_bracketed_or_cql_comment
|
73
73
|
when '-' then scan_simple_comment
|
74
74
|
when "'" then scan_string_literal
|
75
75
|
when ALPHA then scan_keyword_or_identifier(possible_keyword: true)
|
@@ -110,7 +110,7 @@ module ElasticAPM
|
|
110
110
|
next next_char
|
111
111
|
end
|
112
112
|
|
113
|
-
next next_char if peek
|
113
|
+
next next_char if ALPHA.match?(peek)
|
114
114
|
|
115
115
|
break
|
116
116
|
end
|
@@ -185,10 +185,16 @@ module ElasticAPM
|
|
185
185
|
IDENT
|
186
186
|
end
|
187
187
|
|
188
|
+
def scan_bracketed_or_cql_comment
|
189
|
+
case peek_char
|
190
|
+
when '*' then scan_bracketed_comment
|
191
|
+
when '/' then scan_cql_comment
|
192
|
+
else OTHER
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
188
196
|
# rubocop:disable Metrics/CyclomaticComplexity
|
189
197
|
def scan_bracketed_comment
|
190
|
-
return OTHER unless peek_char == '*'
|
191
|
-
|
192
198
|
nesting = 1
|
193
199
|
|
194
200
|
while (char = next_char)
|
@@ -207,6 +213,16 @@ module ElasticAPM
|
|
207
213
|
end
|
208
214
|
# rubocop:enable Metrics/CyclomaticComplexity
|
209
215
|
|
216
|
+
def scan_cql_comment
|
217
|
+
return OTHER unless peek_char == '/'
|
218
|
+
|
219
|
+
while (char = next_char)
|
220
|
+
break if char == "\n"
|
221
|
+
end
|
222
|
+
|
223
|
+
COMMENT
|
224
|
+
end
|
225
|
+
|
210
226
|
def scan_simple_comment
|
211
227
|
return OTHER unless peek_char == '-'
|
212
228
|
|
@@ -251,7 +267,7 @@ module ElasticAPM
|
|
251
267
|
when 'e', 'E'
|
252
268
|
return NUMBER if exponent
|
253
269
|
next_char
|
254
|
-
next_char if
|
270
|
+
next_char if /[+-]/.match?(peek_char)
|
255
271
|
else break
|
256
272
|
end
|
257
273
|
end
|
@@ -29,10 +29,9 @@ module ElasticAPM
|
|
29
29
|
|
30
30
|
def initialize(
|
31
31
|
traceparent: nil,
|
32
|
-
tracestate: nil
|
33
|
-
**legacy_traceparent_attrs
|
32
|
+
tracestate: nil
|
34
33
|
)
|
35
|
-
@traceparent = traceparent || Traceparent.new
|
34
|
+
@traceparent = traceparent || Traceparent.new
|
36
35
|
@tracestate = tracestate || Tracestate.new
|
37
36
|
end
|
38
37
|
|
@@ -42,15 +41,13 @@ module ElasticAPM
|
|
42
41
|
:version, :trace_id, :id, :parent_id, :ensure_parent_id, :recorded?
|
43
42
|
|
44
43
|
class << self
|
45
|
-
def parse(
|
46
|
-
unless
|
44
|
+
def parse(env: nil, metadata: nil)
|
45
|
+
unless env || metadata
|
47
46
|
raise ArgumentError, 'TraceContext expects env:, metadata: ' \
|
48
47
|
'or single argument header string'
|
49
48
|
end
|
50
49
|
|
51
|
-
if
|
52
|
-
legacy_parse_from_header(legacy_header)
|
53
|
-
elsif env
|
50
|
+
if env
|
54
51
|
trace_context_from_env(env)
|
55
52
|
elsif metadata
|
56
53
|
trace_context_from_metadata(metadata)
|
@@ -88,11 +85,6 @@ module ElasticAPM
|
|
88
85
|
|
89
86
|
new(traceparent: parent, tracestate: state)
|
90
87
|
end
|
91
|
-
|
92
|
-
def legacy_parse_from_header(header)
|
93
|
-
parent = Traceparent.parse(header)
|
94
|
-
new(traceparent: parent)
|
95
|
-
end
|
96
88
|
end
|
97
89
|
|
98
90
|
def child
|
@@ -22,7 +22,7 @@ module ElasticAPM
|
|
22
22
|
# @api private
|
23
23
|
class Traceparent
|
24
24
|
VERSION = '00'
|
25
|
-
|
25
|
+
NON_HEX_REGEX = /[^[:xdigit:]]/.freeze
|
26
26
|
|
27
27
|
TRACE_ID_LENGTH = 16
|
28
28
|
ID_LENGTH = 8
|
@@ -30,14 +30,13 @@ module ElasticAPM
|
|
30
30
|
def initialize(
|
31
31
|
version: VERSION,
|
32
32
|
trace_id: nil,
|
33
|
-
|
33
|
+
parent_id: nil,
|
34
34
|
id: nil,
|
35
35
|
recorded: true
|
36
36
|
)
|
37
37
|
@version = version
|
38
38
|
@trace_id = trace_id || hex(TRACE_ID_LENGTH)
|
39
|
-
|
40
|
-
@parent_id = span_id
|
39
|
+
@parent_id = parent_id
|
41
40
|
@id = id || hex(ID_LENGTH)
|
42
41
|
@recorded = recorded
|
43
42
|
end
|
@@ -56,8 +55,8 @@ module ElasticAPM
|
|
56
55
|
values[-1] = Util.hex_to_bits(values[-1])
|
57
56
|
end
|
58
57
|
|
59
|
-
raise_invalid(header) if
|
60
|
-
raise_invalid(header) if
|
58
|
+
raise_invalid(header) if NON_HEX_REGEX.match?(t.trace_id)
|
59
|
+
raise_invalid(header) if NON_HEX_REGEX.match?(t.parent_id)
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
@@ -74,7 +74,7 @@ module ElasticAPM
|
|
74
74
|
debug '%s: Closing request with reason %s', thread_str, reason
|
75
75
|
@closed.make_true
|
76
76
|
|
77
|
-
@wr&.close
|
77
|
+
@wr&.close
|
78
78
|
return if @request.nil? || @request&.join(5)
|
79
79
|
|
80
80
|
error(
|
@@ -85,7 +85,7 @@ module ElasticAPM
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def closed?
|
88
|
-
@closed.true?
|
88
|
+
@rd.closed? && @closed.true?
|
89
89
|
end
|
90
90
|
|
91
91
|
def inspect
|
@@ -117,6 +117,8 @@ module ElasticAPM
|
|
117
117
|
error(
|
118
118
|
"Couldn't establish connection to APM Server:\n%p", e.inspect
|
119
119
|
)
|
120
|
+
ensure
|
121
|
+
@rd&.close
|
120
122
|
end
|
121
123
|
end
|
122
124
|
end
|
@@ -26,17 +26,8 @@ module ElasticAPM
|
|
26
26
|
class HashSanitizer
|
27
27
|
FILTERED = '[FILTERED]'
|
28
28
|
|
29
|
-
# DEPRECATED: Remove these additions in next major version
|
30
|
-
LEGACY_KEY_FILTERS = [/cookie/i, /auth/i].freeze
|
31
|
-
|
32
|
-
# DEPRECATED: Remove this check in next major version
|
33
|
-
VALUE_FILTERS = [
|
34
|
-
# (probably) credit card number
|
35
|
-
/^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/
|
36
|
-
].freeze
|
37
|
-
|
38
29
|
def initialize(key_patterns:)
|
39
|
-
@key_patterns = key_patterns
|
30
|
+
@key_patterns = key_patterns
|
40
31
|
end
|
41
32
|
|
42
33
|
attr_accessor :key_patterns
|
@@ -48,18 +39,13 @@ module ElasticAPM
|
|
48
39
|
def strip_from!(obj)
|
49
40
|
return unless obj.is_a?(Hash)
|
50
41
|
|
51
|
-
obj.
|
52
|
-
if filter_key?(k)
|
53
|
-
next obj[k] = FILTERED
|
54
|
-
end
|
55
|
-
|
42
|
+
obj.each_pair do |k, v|
|
56
43
|
case v
|
57
44
|
when Hash
|
58
45
|
strip_from!(v)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
46
|
+
else
|
47
|
+
next unless filter_key?(k)
|
48
|
+
obj[k] = FILTERED
|
63
49
|
end
|
64
50
|
end
|
65
51
|
end
|
@@ -67,10 +53,6 @@ module ElasticAPM
|
|
67
53
|
def filter_key?(key)
|
68
54
|
@key_patterns.any? { |regex| regex.match(key) }
|
69
55
|
end
|
70
|
-
|
71
|
-
def filter_value?(value)
|
72
|
-
VALUE_FILTERS.any? { |regex| regex.match(value) }
|
73
|
-
end
|
74
56
|
end
|
75
57
|
end
|
76
58
|
end
|
@@ -65,7 +65,7 @@ module ElasticAPM
|
|
65
65
|
}
|
66
66
|
|
67
67
|
if (node_name = service.node_name)
|
68
|
-
base[:node] = {
|
68
|
+
base[:node] = { configured_name: keyword_field(node_name) }
|
69
69
|
end
|
70
70
|
|
71
71
|
base
|
@@ -81,7 +81,8 @@ module ElasticAPM
|
|
81
81
|
|
82
82
|
def build_system(system)
|
83
83
|
{
|
84
|
-
|
84
|
+
detected_hostname: keyword_field(system.detected_hostname),
|
85
|
+
configured_hostname: keyword_field(system.configured_hostname),
|
85
86
|
architecture: keyword_field(system.architecture),
|
86
87
|
platform: keyword_field(system.platform),
|
87
88
|
kubernetes: keyword_object(system.kubernetes),
|