elastic-apm 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
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,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'elastic_apm/metadata/service_info'
|
4
|
+
require 'elastic_apm/metadata/system_info'
|
5
|
+
require 'elastic_apm/metadata/process_info'
|
6
|
+
|
7
|
+
module ElasticAPM
|
8
|
+
# @api private
|
9
|
+
module Metadata
|
10
|
+
def self.build(config)
|
11
|
+
{
|
12
|
+
metadata: {
|
13
|
+
service: Metadata::ServiceInfo.build(config),
|
14
|
+
process: Metadata::ProcessInfo.build(config),
|
15
|
+
system: Metadata::SystemInfo.build(config)
|
16
|
+
}
|
17
|
+
}.to_json
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
module Metadata
|
5
|
+
# @api private
|
6
|
+
class ProcessInfo
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
pid = $PID || Process.pid
|
13
|
+
return unless pid
|
14
|
+
{
|
15
|
+
argv: ARGV,
|
16
|
+
pid: pid,
|
17
|
+
title: $PROGRAM_NAME
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build(config)
|
22
|
+
new(config).build
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
module Metadata
|
5
|
+
# @api private
|
6
|
+
class ServiceInfo
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
# rubocop:disable Metrics/MethodLength
|
12
|
+
def build
|
13
|
+
base = {
|
14
|
+
name: @config.service_name,
|
15
|
+
environment: @config.environment,
|
16
|
+
agent: {
|
17
|
+
name: 'ruby',
|
18
|
+
version: VERSION
|
19
|
+
},
|
20
|
+
framework: nil,
|
21
|
+
language: {
|
22
|
+
name: 'ruby',
|
23
|
+
version: RUBY_VERSION
|
24
|
+
},
|
25
|
+
runtime: runtime,
|
26
|
+
version: @config.service_version || Util.git_sha
|
27
|
+
}
|
28
|
+
|
29
|
+
if @config.framework_name
|
30
|
+
base[:framework] = {
|
31
|
+
name: @config.framework_name,
|
32
|
+
version: @config.framework_version
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
base
|
37
|
+
end
|
38
|
+
# rubocop:enable Metrics/MethodLength
|
39
|
+
|
40
|
+
def self.build(config)
|
41
|
+
new(config).build
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def runtime
|
47
|
+
case RUBY_ENGINE
|
48
|
+
when 'ruby'
|
49
|
+
{ name: RUBY_ENGINE, version: RUBY_VERSION || RUBY_ENGINE_VERSION }
|
50
|
+
when 'jruby'
|
51
|
+
{ name: RUBY_ENGINE, version: JRUBY_VERSION || RUBY_ENGINE_VERSION }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
module Metadata
|
5
|
+
# @api private
|
6
|
+
class SystemInfo
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
{
|
13
|
+
hostname: @config.hostname || `hostname`.chomp,
|
14
|
+
architecture: platform.cpu,
|
15
|
+
platform: platform.os
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.build(config)
|
20
|
+
new(config).build
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def platform
|
26
|
+
@platform ||= Gem::Platform.local
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,40 +1,47 @@
|
|
1
|
+
#
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
4
|
+
require 'elastic_apm/traceparent'
|
5
|
+
|
3
6
|
module ElasticAPM
|
4
7
|
# @api private
|
5
8
|
class Middleware
|
9
|
+
include Logging
|
10
|
+
|
6
11
|
def initialize(app)
|
7
12
|
@app = app
|
8
13
|
end
|
9
14
|
|
10
|
-
# rubocop:disable Metrics/
|
15
|
+
# rubocop:disable Metrics/MethodLength
|
11
16
|
def call(env)
|
12
17
|
begin
|
13
18
|
if running? && !path_ignored?(env)
|
14
|
-
transaction =
|
19
|
+
transaction = start_transaction(env)
|
15
20
|
end
|
16
21
|
|
17
22
|
resp = @app.call env
|
18
|
-
|
19
|
-
status, headers, body = resp
|
20
|
-
submit_transaction(transaction, status, headers, body) if transaction
|
21
23
|
rescue InternalError
|
22
24
|
raise # Don't report ElasticAPM errors
|
23
25
|
rescue ::Exception => e
|
24
26
|
ElasticAPM.report(e, handled: false)
|
25
|
-
transaction.submit('HTTP 5xx', status: 500) if transaction
|
26
27
|
raise
|
27
28
|
ensure
|
28
|
-
|
29
|
+
if resp && transaction
|
30
|
+
status, headers, _body = resp
|
31
|
+
transaction.add_response(status, headers: headers)
|
32
|
+
end
|
33
|
+
|
34
|
+
ElasticAPM.end_transaction http_result(status)
|
29
35
|
end
|
30
36
|
|
31
37
|
resp
|
32
38
|
end
|
33
|
-
# rubocop:enable Metrics/
|
39
|
+
# rubocop:enable Metrics/MethodLength
|
40
|
+
|
41
|
+
private
|
34
42
|
|
35
|
-
def
|
36
|
-
|
37
|
-
transaction.submit(result, status: status, headers: headers)
|
43
|
+
def http_result(status)
|
44
|
+
status && "HTTP #{status.to_s[0]}xx"
|
38
45
|
end
|
39
46
|
|
40
47
|
def path_ignored?(env)
|
@@ -43,9 +50,18 @@ module ElasticAPM
|
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
46
|
-
def
|
47
|
-
ElasticAPM.
|
48
|
-
context: ElasticAPM.build_context(env)
|
53
|
+
def start_transaction(env)
|
54
|
+
ElasticAPM.start_transaction 'Rack', 'request',
|
55
|
+
context: ElasticAPM.build_context(env),
|
56
|
+
traceparent: traceparent(env)
|
57
|
+
end
|
58
|
+
|
59
|
+
def traceparent(env)
|
60
|
+
return unless (header = env['HTTP_ELASTIC_APM_TRACEPARENT'])
|
61
|
+
Traceparent.parse(header)
|
62
|
+
rescue Traceparent::InvalidTraceparentHeader
|
63
|
+
warn "Couldn't parse invalid traceparent header: #{header.inspect}"
|
64
|
+
nil
|
49
65
|
end
|
50
66
|
|
51
67
|
def running?
|
@@ -53,7 +69,7 @@ module ElasticAPM
|
|
53
69
|
end
|
54
70
|
|
55
71
|
def config
|
56
|
-
ElasticAPM.agent.config
|
72
|
+
@config ||= ElasticAPM.agent.config
|
57
73
|
end
|
58
74
|
end
|
59
75
|
end
|
@@ -6,7 +6,7 @@ module ElasticAPM
|
|
6
6
|
# @api private
|
7
7
|
class ProcessActionNormalizer < Normalizer
|
8
8
|
register 'process_action.action_controller'
|
9
|
-
TYPE = 'app.controller.action'
|
9
|
+
TYPE = 'app.controller.action'
|
10
10
|
|
11
11
|
def normalize(transaction, _name, payload)
|
12
12
|
transaction.name = endpoint(payload)
|
@@ -41,7 +41,7 @@ module ElasticAPM
|
|
41
41
|
# @api private
|
42
42
|
class RenderTemplateNormalizer < RenderNormalizer
|
43
43
|
register 'render_template.action_view'
|
44
|
-
TYPE = 'template.view'
|
44
|
+
TYPE = 'template.view'
|
45
45
|
|
46
46
|
def normalize(_transaction, _name, payload)
|
47
47
|
normalize_render(payload, TYPE)
|
@@ -51,7 +51,7 @@ module ElasticAPM
|
|
51
51
|
# @api private
|
52
52
|
class RenderPartialNormalizer < RenderNormalizer
|
53
53
|
register 'render_partial.action_view'
|
54
|
-
TYPE = 'template.view.partial'
|
54
|
+
TYPE = 'template.view.partial'
|
55
55
|
|
56
56
|
def normalize(_transaction, _name, payload)
|
57
57
|
normalize_render(payload, TYPE)
|
@@ -61,7 +61,7 @@ module ElasticAPM
|
|
61
61
|
# @api private
|
62
62
|
class RenderCollectionNormalizer < RenderNormalizer
|
63
63
|
register 'render_collection.action_view'
|
64
|
-
TYPE = 'template.view.collection'
|
64
|
+
TYPE = 'template.view.collection'
|
65
65
|
|
66
66
|
def normalize(_transaction, _name, payload)
|
67
67
|
normalize_render(payload, TYPE)
|
@@ -20,7 +20,8 @@ module ElasticAPM
|
|
20
20
|
return :skip if %w[SCHEMA CACHE].include?(payload[:name])
|
21
21
|
|
22
22
|
name = summarize(payload[:sql]) || payload[:name]
|
23
|
-
context =
|
23
|
+
context =
|
24
|
+
Span::Context.new(db: { statement: payload[:sql], type: 'sql' })
|
24
25
|
[name, @type, context]
|
25
26
|
end
|
26
27
|
|
data/lib/elastic_apm/railtie.rb
CHANGED
@@ -26,7 +26,7 @@ module ElasticAPM
|
|
26
26
|
app.middleware.insert 0, Middleware
|
27
27
|
end
|
28
28
|
rescue StandardError => e
|
29
|
-
Rails.logger.error "#{
|
29
|
+
Rails.logger.error "#{Logging::PREFIX}Failed to start: #{e.message}"
|
30
30
|
Rails.logger.debug e.backtrace.join("\n")
|
31
31
|
end
|
32
32
|
end
|
data/lib/elastic_apm/span.rb
CHANGED
@@ -7,61 +7,82 @@ require 'elastic_apm/span/context'
|
|
7
7
|
module ElasticAPM
|
8
8
|
# @api private
|
9
9
|
class Span
|
10
|
-
DEFAULT_TYPE = 'custom'
|
10
|
+
DEFAULT_TYPE = 'custom'
|
11
11
|
|
12
12
|
# rubocop:disable Metrics/ParameterLists
|
13
13
|
def initialize(
|
14
|
-
transaction,
|
15
|
-
id,
|
16
14
|
name,
|
17
15
|
type = nil,
|
16
|
+
transaction: nil,
|
18
17
|
parent: nil,
|
19
|
-
context: nil
|
18
|
+
context: nil,
|
19
|
+
stacktrace_builder: nil
|
20
20
|
)
|
21
|
-
@transaction = transaction
|
22
|
-
@id = id
|
23
21
|
@name = name
|
24
22
|
@type = type || DEFAULT_TYPE
|
25
|
-
@parent = parent
|
26
|
-
@context = context
|
27
23
|
|
28
|
-
@
|
29
|
-
|
24
|
+
@id = SecureRandom.hex(8)
|
25
|
+
|
26
|
+
self.transaction = transaction
|
27
|
+
self.parent = parent
|
28
|
+
|
29
|
+
@context = context
|
30
|
+
@stacktrace_builder = stacktrace_builder
|
30
31
|
end
|
31
32
|
# rubocop:enable Metrics/ParameterLists
|
32
33
|
|
33
|
-
attr_accessor :name, :type, :original_backtrace
|
34
|
-
attr_reader :id, :context, :stacktrace, :duration,
|
34
|
+
attr_accessor :name, :type, :original_backtrace, :parent
|
35
|
+
attr_reader :id, :context, :stacktrace, :duration,
|
36
|
+
:relative_start, :timestamp, :transaction_id, :trace_id
|
37
|
+
|
38
|
+
def transaction=(transaction)
|
39
|
+
@transaction_id = transaction&.id
|
40
|
+
@timestamp = transaction&.timestamp
|
41
|
+
@trace_id = transaction&.trace_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def parent_id
|
45
|
+
@parent&.id || transaction_id
|
46
|
+
end
|
47
|
+
|
48
|
+
# life cycle
|
35
49
|
|
36
50
|
def start
|
37
|
-
|
51
|
+
raise 'Transaction needed to start span' unless transaction_id
|
52
|
+
|
53
|
+
@relative_start = Util.micros - timestamp
|
38
54
|
|
39
55
|
self
|
40
56
|
end
|
41
57
|
|
58
|
+
def stop
|
59
|
+
@duration = Util.micros - timestamp - relative_start
|
60
|
+
end
|
61
|
+
|
42
62
|
def done
|
43
|
-
|
63
|
+
stop
|
44
64
|
|
45
|
-
if
|
46
|
-
|
47
|
-
@transaction.instrumenter.agent.stacktrace_builder.build(
|
48
|
-
original_backtrace, type: :span
|
49
|
-
)
|
65
|
+
if should_build_stacktrace?
|
66
|
+
build_stacktrace
|
50
67
|
end
|
51
68
|
|
52
|
-
self.original_backtrace = nil # release it
|
53
|
-
|
54
69
|
self
|
55
70
|
end
|
56
71
|
|
57
|
-
def
|
72
|
+
def stopped?
|
58
73
|
!!duration
|
59
74
|
end
|
60
75
|
|
76
|
+
def started?
|
77
|
+
!!relative_start
|
78
|
+
end
|
79
|
+
|
61
80
|
def running?
|
62
|
-
|
81
|
+
started? && !stopped?
|
63
82
|
end
|
64
83
|
|
84
|
+
# relations
|
85
|
+
|
65
86
|
def inspect
|
66
87
|
"<ElasticAPM::Span id:#{id}" \
|
67
88
|
" name:#{name.inspect}" \
|
@@ -71,14 +92,23 @@ module ElasticAPM
|
|
71
92
|
|
72
93
|
private
|
73
94
|
|
95
|
+
def should_build_stacktrace?
|
96
|
+
@stacktrace_builder && original_backtrace && long_enough_for_stacktrace?
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_stacktrace
|
100
|
+
@stacktrace = @stacktrace_builder.build(original_backtrace, type: :span)
|
101
|
+
self.original_backtrace = nil # release it
|
102
|
+
end
|
103
|
+
|
74
104
|
def long_enough_for_stacktrace?
|
75
|
-
min_duration =
|
105
|
+
min_duration =
|
106
|
+
@stacktrace_builder.config.span_frames_min_duration_us
|
76
107
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
108
|
+
return true if min_duration < 0
|
109
|
+
return false if min_duration == 0
|
110
|
+
|
111
|
+
duration >= min_duration
|
82
112
|
end
|
83
113
|
end
|
84
114
|
end
|
@@ -6,13 +6,39 @@ module ElasticAPM
|
|
6
6
|
class Context
|
7
7
|
include NaivelyHashable
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
9
|
+
def initialize(db: nil, http: nil)
|
10
|
+
@db = db && Db.new(db)
|
11
|
+
@http = http && Http.new(http)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :sync, :db, :http
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
class Db
|
18
|
+
include NaivelyHashable
|
19
|
+
|
20
|
+
def initialize(instance: nil, statement: nil, type: nil, user: nil)
|
21
|
+
@instance = instance
|
22
|
+
@statement = statement
|
23
|
+
@type = type
|
24
|
+
@user = user
|
12
25
|
end
|
26
|
+
|
27
|
+
attr_accessor :instance, :statement, :type, :user
|
13
28
|
end
|
14
29
|
|
15
|
-
|
30
|
+
# @api private
|
31
|
+
class Http
|
32
|
+
include NaivelyHashable
|
33
|
+
|
34
|
+
def initialize(url: nil, status_code: nil, method: nil)
|
35
|
+
@url = url
|
36
|
+
@status_code = status_code
|
37
|
+
@method = method
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :url, :status_code, :method
|
41
|
+
end
|
16
42
|
end
|
17
43
|
end
|
18
44
|
end
|