elastic-apm 1.1.0 → 2.0.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.
Potentially problematic release.
This version of elastic-apm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +45 -0
- data/Gemfile +17 -12
- data/bench/app.rb +1 -2
- data/bench/benchmark.rb +1 -1
- data/bench/stackprof.rb +1 -1
- data/docs/api.asciidoc +115 -76
- data/docs/configuration.asciidoc +232 -167
- data/docs/context.asciidoc +7 -3
- data/docs/custom-instrumentation.asciidoc +17 -28
- data/docs/index.asciidoc +13 -7
- data/docs/supported-technologies.asciidoc +65 -0
- data/elastic-apm.gemspec +3 -2
- data/lib/elastic_apm.rb +272 -121
- data/lib/elastic_apm/agent.rb +56 -107
- data/lib/elastic_apm/config.rb +130 -106
- data/lib/elastic_apm/config/duration.rb +25 -0
- data/lib/elastic_apm/config/size.rb +28 -0
- data/lib/elastic_apm/context_builder.rb +1 -0
- data/lib/elastic_apm/deprecations.rb +19 -0
- data/lib/elastic_apm/error.rb +5 -2
- data/lib/elastic_apm/error/exception.rb +1 -1
- data/lib/elastic_apm/error_builder.rb +5 -0
- data/lib/elastic_apm/instrumenter.rb +121 -53
- data/lib/elastic_apm/internal_error.rb +1 -0
- data/lib/elastic_apm/{log.rb → logging.rb} +16 -11
- data/lib/elastic_apm/metadata.rb +20 -0
- data/lib/elastic_apm/metadata/process_info.rb +26 -0
- data/lib/elastic_apm/metadata/service_info.rb +56 -0
- data/lib/elastic_apm/metadata/system_info.rb +30 -0
- data/lib/elastic_apm/middleware.rb +31 -15
- data/lib/elastic_apm/normalizers/action_controller.rb +1 -1
- data/lib/elastic_apm/normalizers/action_mailer.rb +1 -1
- data/lib/elastic_apm/normalizers/action_view.rb +3 -3
- data/lib/elastic_apm/normalizers/active_record.rb +2 -1
- data/lib/elastic_apm/railtie.rb +1 -1
- data/lib/elastic_apm/span.rb +59 -29
- data/lib/elastic_apm/span/context.rb +30 -4
- data/lib/elastic_apm/span_helpers.rb +1 -1
- data/lib/elastic_apm/spies/delayed_job.rb +7 -7
- data/lib/elastic_apm/spies/elasticsearch.rb +4 -4
- data/lib/elastic_apm/spies/http.rb +38 -0
- data/lib/elastic_apm/spies/mongo.rb +22 -11
- data/lib/elastic_apm/spies/net_http.rb +7 -4
- data/lib/elastic_apm/spies/rake.rb +5 -6
- data/lib/elastic_apm/spies/redis.rb +1 -1
- data/lib/elastic_apm/spies/sequel.rb +9 -7
- data/lib/elastic_apm/spies/sidekiq.rb +5 -5
- data/lib/elastic_apm/spies/tilt.rb +2 -2
- data/lib/elastic_apm/sql_summarizer.rb +3 -3
- data/lib/elastic_apm/stacktrace_builder.rb +6 -6
- data/lib/elastic_apm/subscriber.rb +3 -3
- data/lib/elastic_apm/traceparent.rb +62 -0
- data/lib/elastic_apm/transaction.rb +62 -93
- data/lib/elastic_apm/transport/base.rb +98 -0
- data/lib/elastic_apm/transport/connection.rb +175 -0
- data/lib/elastic_apm/transport/filters.rb +45 -0
- data/lib/elastic_apm/transport/filters/request_body_filter.rb +31 -0
- data/lib/elastic_apm/transport/filters/secrets_filter.rb +59 -0
- data/lib/elastic_apm/transport/serializers.rb +58 -0
- data/lib/elastic_apm/transport/serializers/error_serializer.rb +59 -0
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +30 -0
- data/lib/elastic_apm/transport/serializers/transaction_serializer.rb +33 -0
- data/lib/elastic_apm/transport/worker.rb +73 -0
- data/lib/elastic_apm/util.rb +11 -8
- data/lib/elastic_apm/version.rb +1 -1
- metadata +40 -21
- data/.travis.yml +0 -5
- data/docs/troubleshooting.asciidoc +0 -28
- data/lib/elastic_apm/filters.rb +0 -46
- data/lib/elastic_apm/filters/request_body_filter.rb +0 -33
- data/lib/elastic_apm/filters/secrets_filter.rb +0 -59
- data/lib/elastic_apm/http.rb +0 -139
- data/lib/elastic_apm/process_info.rb +0 -24
- data/lib/elastic_apm/serializers.rb +0 -28
- data/lib/elastic_apm/serializers/errors.rb +0 -61
- data/lib/elastic_apm/serializers/transactions.rb +0 -51
- data/lib/elastic_apm/service_info.rb +0 -54
- data/lib/elastic_apm/system_info.rb +0 -28
- data/lib/elastic_apm/util/dig.rb +0 -31
- data/lib/elastic_apm/util/inspector.rb +0 -61
- data/lib/elastic_apm/worker.rb +0 -106
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
class Config
|
5
|
+
# @api private
|
6
|
+
class Duration
|
7
|
+
MULTIPLIERS = { 'ms' => 0.001, 'm' => 60 }.freeze
|
8
|
+
REGEX = /^(-)?(\d+)(m|ms|s)?$/i.freeze
|
9
|
+
|
10
|
+
def initialize(seconds)
|
11
|
+
@seconds = seconds
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :seconds
|
15
|
+
|
16
|
+
def self.parse(str, default_unit:)
|
17
|
+
_, negative, amount, unit = REGEX.match(str).to_a
|
18
|
+
unit ||= default_unit
|
19
|
+
seconds = MULTIPLIERS.fetch(unit.downcase, 1) * amount.to_i
|
20
|
+
seconds = 0 - seconds if negative
|
21
|
+
new(seconds)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
class Config
|
5
|
+
# @api private
|
6
|
+
class Size
|
7
|
+
MULTIPLIERS = {
|
8
|
+
'kb' => 1024,
|
9
|
+
'mb' => 1024 * 1_000,
|
10
|
+
'gb' => 1024 * 100_000
|
11
|
+
}.freeze
|
12
|
+
REGEX = /^(\d+)(b|kb|mb|gb)?$/i.freeze
|
13
|
+
|
14
|
+
def initialize(bytes)
|
15
|
+
@bytes = bytes
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :bytes
|
19
|
+
|
20
|
+
def self.parse(str, default_unit:)
|
21
|
+
_, amount, unit = REGEX.match(str).to_a
|
22
|
+
unit ||= default_unit
|
23
|
+
bytes = MULTIPLIERS.fetch(unit.downcase, 1) * amount.to_i
|
24
|
+
new(bytes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Deprecations
|
6
|
+
def deprecate(name, replacement = nil)
|
7
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
8
|
+
alias :"#{name}__deprecated" :"#{name}"
|
9
|
+
|
10
|
+
def #{name}(*args, &block)
|
11
|
+
warn "[ElasticAPM] [DEPRECATED] `#{name}' is being removed. " \
|
12
|
+
"#{replacement && "See `#{replacement}'."}" \
|
13
|
+
"\nCalled from \#{caller.first}"
|
14
|
+
#{name}__deprecated(*args, &block)
|
15
|
+
end
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/elastic_apm/error.rb
CHANGED
@@ -9,16 +9,19 @@ module ElasticAPM
|
|
9
9
|
# @api private
|
10
10
|
class Error
|
11
11
|
def initialize(culprit: nil)
|
12
|
-
@id = SecureRandom.
|
12
|
+
@id = SecureRandom.hex(16)
|
13
|
+
@trace_id = nil
|
13
14
|
@culprit = culprit
|
14
15
|
|
15
16
|
@timestamp = Util.micros
|
16
17
|
@context = Context.new
|
17
18
|
|
18
19
|
@transaction_id = nil
|
20
|
+
@parent_id = nil
|
19
21
|
end
|
20
22
|
|
21
|
-
attr_accessor :id, :culprit, :exception, :log, :transaction_id, :context
|
23
|
+
attr_accessor :id, :culprit, :exception, :log, :transaction_id, :context,
|
24
|
+
:parent_id, :trace_id
|
22
25
|
attr_reader :timestamp
|
23
26
|
end
|
24
27
|
end
|
@@ -7,6 +7,7 @@ module ElasticAPM
|
|
7
7
|
@agent = agent
|
8
8
|
end
|
9
9
|
|
10
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
10
11
|
def build_exception(exception, handled: true)
|
11
12
|
error = Error.new
|
12
13
|
error.exception = Error::Exception.new(exception, handled: handled)
|
@@ -19,10 +20,14 @@ module ElasticAPM
|
|
19
20
|
|
20
21
|
if (transaction = ElasticAPM.current_transaction)
|
21
22
|
error.context = transaction.context.dup
|
23
|
+
error.trace_id = transaction.trace_id
|
24
|
+
error.transaction_id = transaction.id
|
25
|
+
error.parent_id = ElasticAPM.current_span&.id || transaction.id
|
22
26
|
end
|
23
27
|
|
24
28
|
error
|
25
29
|
end
|
30
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
26
31
|
|
27
32
|
def build_log(message, backtrace: nil, **attrs)
|
28
33
|
error = Error.new
|
@@ -4,41 +4,57 @@ require 'elastic_apm/span'
|
|
4
4
|
require 'elastic_apm/transaction'
|
5
5
|
|
6
6
|
module ElasticAPM
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
7
8
|
# @api private
|
8
9
|
class Instrumenter
|
9
|
-
include
|
10
|
+
include Logging
|
10
11
|
|
11
|
-
|
12
|
+
TRANSACTION_KEY = :__elastic_transaction_key
|
13
|
+
SPAN_KEY = :__elastic_span_key
|
12
14
|
|
13
15
|
# @api private
|
14
|
-
class
|
16
|
+
class Current
|
15
17
|
def initialize
|
16
|
-
self.
|
18
|
+
self.transaction = nil
|
19
|
+
self.span = nil
|
17
20
|
end
|
18
21
|
|
19
|
-
def
|
20
|
-
Thread.current[
|
22
|
+
def transaction
|
23
|
+
Thread.current[TRANSACTION_KEY]
|
21
24
|
end
|
22
25
|
|
23
|
-
def
|
24
|
-
Thread.current[
|
26
|
+
def transaction=(transaction)
|
27
|
+
Thread.current[TRANSACTION_KEY] = transaction
|
28
|
+
end
|
29
|
+
|
30
|
+
def span
|
31
|
+
Thread.current[SPAN_KEY]
|
32
|
+
end
|
33
|
+
|
34
|
+
def span=(span)
|
35
|
+
Thread.current[SPAN_KEY] = span
|
25
36
|
end
|
26
37
|
end
|
27
38
|
|
28
|
-
def initialize(
|
29
|
-
@
|
30
|
-
@
|
39
|
+
def initialize(config, &enqueue)
|
40
|
+
@config = config
|
41
|
+
@enqueue = enqueue
|
31
42
|
|
32
|
-
@
|
43
|
+
@current = Current.new
|
33
44
|
end
|
34
45
|
|
35
|
-
attr_reader :
|
46
|
+
attr_reader :config, :enqueue
|
36
47
|
|
37
48
|
def start
|
49
|
+
debug 'Starting instrumenter'
|
38
50
|
end
|
39
51
|
|
40
52
|
def stop
|
41
|
-
|
53
|
+
debug 'Stopping instrumenter'
|
54
|
+
|
55
|
+
self.current_transaction = nil
|
56
|
+
self.current_span = nil
|
57
|
+
|
42
58
|
@subscriber.unregister! if @subscriber
|
43
59
|
end
|
44
60
|
|
@@ -47,70 +63,118 @@ module ElasticAPM
|
|
47
63
|
@subscriber.register!
|
48
64
|
end
|
49
65
|
|
66
|
+
# transactions
|
67
|
+
|
50
68
|
def current_transaction
|
51
|
-
@
|
69
|
+
@current.transaction
|
52
70
|
end
|
53
71
|
|
54
72
|
def current_transaction=(transaction)
|
55
|
-
@
|
73
|
+
@current.transaction = transaction
|
56
74
|
end
|
57
75
|
|
58
76
|
# rubocop:disable Metrics/MethodLength
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
77
|
+
def start_transaction(
|
78
|
+
name = nil,
|
79
|
+
type = nil,
|
80
|
+
context: nil,
|
81
|
+
traceparent: nil
|
82
|
+
)
|
83
|
+
return nil unless config.instrument?
|
65
84
|
|
66
85
|
if (transaction = current_transaction)
|
67
|
-
|
68
|
-
|
86
|
+
raise ExistingTransactionError,
|
87
|
+
"Transactions may not be nested.\nAlready inside #{transaction}"
|
69
88
|
end
|
70
89
|
|
71
|
-
sampled =
|
90
|
+
sampled = traceparent ? traceparent.recorded? : random_sample?
|
72
91
|
|
73
92
|
transaction =
|
74
|
-
Transaction.new
|
93
|
+
Transaction.new(
|
94
|
+
name,
|
95
|
+
type,
|
96
|
+
context: context,
|
97
|
+
traceparent: traceparent,
|
98
|
+
sampled: sampled
|
99
|
+
)
|
100
|
+
|
101
|
+
transaction.start
|
75
102
|
|
76
103
|
self.current_transaction = transaction
|
77
|
-
|
104
|
+
end
|
105
|
+
# rubocop:enable Metrics/MethodLength
|
78
106
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
107
|
+
def end_transaction(result = nil)
|
108
|
+
return nil unless (transaction = current_transaction)
|
109
|
+
|
110
|
+
self.current_transaction = nil
|
111
|
+
|
112
|
+
transaction.done result
|
113
|
+
|
114
|
+
enqueue.call transaction
|
85
115
|
|
86
116
|
transaction
|
87
117
|
end
|
88
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
89
|
-
# rubocop:enable Metrics/MethodLength
|
90
118
|
|
91
|
-
|
92
|
-
|
119
|
+
# spans
|
120
|
+
|
121
|
+
def current_span
|
122
|
+
@current.span
|
93
123
|
end
|
94
124
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
125
|
+
def current_span=(span)
|
126
|
+
@current.span = span
|
127
|
+
end
|
128
|
+
|
129
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
130
|
+
def start_span(name, type = nil, backtrace: nil, context: nil)
|
131
|
+
return unless (transaction = current_transaction)
|
132
|
+
return unless transaction.sampled?
|
133
|
+
|
134
|
+
transaction.inc_started_spans!
|
135
|
+
|
136
|
+
if transaction.max_spans_reached?(config)
|
137
|
+
transaction.inc_dropped_spans!
|
99
138
|
return
|
100
139
|
end
|
101
140
|
|
102
|
-
|
141
|
+
span = Span.new(
|
103
142
|
name,
|
104
143
|
type,
|
105
|
-
|
106
|
-
|
107
|
-
|
144
|
+
transaction: transaction,
|
145
|
+
parent: current_span || transaction,
|
146
|
+
context: context
|
108
147
|
)
|
148
|
+
|
149
|
+
if backtrace && span_frames_min_duration?
|
150
|
+
span.original_backtrace = backtrace
|
151
|
+
end
|
152
|
+
|
153
|
+
self.current_span = span
|
154
|
+
|
155
|
+
span.start
|
156
|
+
end
|
157
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
158
|
+
|
159
|
+
def end_span
|
160
|
+
return unless (span = current_span)
|
161
|
+
|
162
|
+
span.done
|
163
|
+
|
164
|
+
self.current_span =
|
165
|
+
span.parent&.is_a?(Span) && span.parent || nil
|
166
|
+
|
167
|
+
enqueue.call span
|
168
|
+
|
169
|
+
span
|
109
170
|
end
|
110
|
-
|
171
|
+
|
172
|
+
# metadata
|
111
173
|
|
112
174
|
def set_tag(key, value)
|
113
175
|
return unless current_transaction
|
176
|
+
|
177
|
+
key = key.to_s.gsub(/[\."\*]/, '_').to_sym
|
114
178
|
current_transaction.context.tags[key] = value.to_s
|
115
179
|
end
|
116
180
|
|
@@ -124,17 +188,21 @@ module ElasticAPM
|
|
124
188
|
current_transaction.context.user = Context::User.new(config, user)
|
125
189
|
end
|
126
190
|
|
127
|
-
def submit_transaction(transaction)
|
128
|
-
agent.enqueue_transaction transaction
|
129
|
-
|
130
|
-
return unless config.debug_transactions
|
131
|
-
debug('Submitted transaction:') { Util.inspect_transaction transaction }
|
132
|
-
end
|
133
|
-
|
134
191
|
def inspect
|
135
192
|
'<ElasticAPM::Instrumenter ' \
|
136
193
|
"current_transaction=#{current_transaction.inspect}" \
|
137
194
|
'>'
|
138
195
|
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def random_sample?
|
200
|
+
rand <= config.transaction_sample_rate
|
201
|
+
end
|
202
|
+
|
203
|
+
def span_frames_min_duration?
|
204
|
+
config.span_frames_min_duration != 0
|
205
|
+
end
|
139
206
|
end
|
207
|
+
# rubocop:enable Metrics/ClassLength
|
140
208
|
end
|
@@ -1,9 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'logger'
|
4
|
+
|
3
5
|
module ElasticAPM
|
4
6
|
# @api private
|
5
|
-
module
|
6
|
-
PREFIX = '[ElasticAPM] '
|
7
|
+
module Logging
|
8
|
+
PREFIX = '[ElasticAPM] '
|
9
|
+
|
10
|
+
LEVELS = {
|
11
|
+
debug: Logger::DEBUG,
|
12
|
+
info: Logger::INFO,
|
13
|
+
warn: Logger::WARN,
|
14
|
+
error: Logger::ERROR,
|
15
|
+
fatal: Logger::FATAL
|
16
|
+
}.freeze
|
7
17
|
|
8
18
|
def debug(msg, *args, &block)
|
9
19
|
log(:debug, msg, *args, &block)
|
@@ -25,26 +35,21 @@ module ElasticAPM
|
|
25
35
|
log(:fatal, msg, *args, &block)
|
26
36
|
end
|
27
37
|
|
38
|
+
private
|
39
|
+
|
28
40
|
def log(lvl, msg, *args)
|
29
|
-
return unless logger
|
41
|
+
return unless (logger = @config&.logger)
|
42
|
+
return unless LEVELS[lvl] >= (@config&.log_level || 0)
|
30
43
|
|
31
44
|
formatted_msg = prepend_prefix(format(msg.to_s, *args))
|
32
45
|
|
33
46
|
return logger.send(lvl, formatted_msg) unless block_given?
|
34
47
|
|
35
|
-
# TODO: dont evaluate block if level is higher
|
36
48
|
logger.send(lvl, "#{formatted_msg}\n#{yield}")
|
37
49
|
end
|
38
50
|
|
39
|
-
private
|
40
|
-
|
41
51
|
def prepend_prefix(str)
|
42
52
|
"#{PREFIX}#{str}"
|
43
53
|
end
|
44
|
-
|
45
|
-
def logger
|
46
|
-
return false unless (config = instance_variable_get(:@config))
|
47
|
-
config.logger
|
48
|
-
end
|
49
54
|
end
|
50
55
|
end
|