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
@@ -67,7 +67,7 @@ module ElasticAPM
|
|
67
67
|
|
68
68
|
# rubocop:disable Metrics/MethodLength
|
69
69
|
def finish(clock_end: Util.monotonic_micros, end_time: nil)
|
70
|
-
return unless (
|
70
|
+
return unless (agent = ElasticAPM.agent)
|
71
71
|
|
72
72
|
if end_time
|
73
73
|
warn '[ElasticAPM] DEPRECATED: Setting a custom end time as a ' \
|
@@ -79,12 +79,12 @@ module ElasticAPM
|
|
79
79
|
|
80
80
|
case elastic_span
|
81
81
|
when ElasticAPM::Transaction
|
82
|
-
instrumenter.current_transaction = nil
|
82
|
+
agent.instrumenter.current_transaction = nil
|
83
83
|
when ElasticAPM::Span
|
84
|
-
instrumenter.current_spans.delete(elastic_span)
|
84
|
+
agent.instrumenter.current_spans.delete(elastic_span)
|
85
85
|
end
|
86
86
|
|
87
|
-
|
87
|
+
agent.enqueue elastic_span
|
88
88
|
end
|
89
89
|
# rubocop:enable Metrics/MethodLength
|
90
90
|
|
data/lib/elastic_apm/rails.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'elastic_apm/railtie'
|
3
4
|
require 'elastic_apm/subscriber'
|
4
5
|
require 'elastic_apm/normalizers/rails'
|
5
6
|
|
@@ -8,6 +9,7 @@ module ElasticAPM
|
|
8
9
|
# It is recommended to use the Railtie instead.
|
9
10
|
module Rails
|
10
11
|
extend self
|
12
|
+
|
11
13
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
12
14
|
# rubocop:disable Metrics/CyclomaticComplexity
|
13
15
|
# Start the ElasticAPM agent and hook into Rails.
|
@@ -17,11 +19,13 @@ module ElasticAPM
|
|
17
19
|
# @return [true, nil] true if the agent was started, nil otherwise.
|
18
20
|
def start(config)
|
19
21
|
config = Config.new(config) unless config.is_a?(Config)
|
22
|
+
|
20
23
|
if (reason = should_skip?(config))
|
21
24
|
unless config.disable_start_message?
|
22
25
|
config.logger.info "Skipping because: #{reason}. " \
|
23
26
|
"Start manually with `ElasticAPM.start'"
|
24
27
|
end
|
28
|
+
|
25
29
|
return
|
26
30
|
end
|
27
31
|
|
@@ -35,10 +39,16 @@ module ElasticAPM
|
|
35
39
|
)
|
36
40
|
require 'elastic_apm/spies/action_dispatch'
|
37
41
|
end
|
42
|
+
|
38
43
|
ElasticAPM.running?
|
39
44
|
rescue StandardError => e
|
40
|
-
config.
|
41
|
-
|
45
|
+
if config.disable_start_message?
|
46
|
+
config.logger.error format('Failed to start: %s', e.message)
|
47
|
+
config.logger.debug "Backtrace:\n" + e.backtrace.join("\n")
|
48
|
+
else
|
49
|
+
puts format('Failed to start: %s', e.message)
|
50
|
+
puts "Backtrace:\n" + e.backtrace.join("\n")
|
51
|
+
end
|
42
52
|
end
|
43
53
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
44
54
|
# rubocop:enable Metrics/CyclomaticComplexity
|
data/lib/elastic_apm/railtie.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'elastic_apm/rails'
|
4
|
-
|
5
3
|
module ElasticAPM
|
6
4
|
# @api private
|
7
5
|
class Railtie < ::Rails::Railtie
|
@@ -13,9 +11,7 @@ module ElasticAPM
|
|
13
11
|
end
|
14
12
|
|
15
13
|
initializer 'elastic_apm.initialize' do |app|
|
16
|
-
config = Config.new(app.config.elastic_apm).tap do |c|
|
17
|
-
c.app = app
|
18
|
-
|
14
|
+
config = Config.new(app.config.elastic_apm.merge(app: app)).tap do |c|
|
19
15
|
# Prepend Rails.root to log_path if present
|
20
16
|
if c.log_path && !c.log_path.start_with?('/')
|
21
17
|
c.log_path = ::Rails.root.join(c.log_path)
|
data/lib/elastic_apm/sinatra.rb
CHANGED
@@ -9,7 +9,7 @@ module ElasticAPM
|
|
9
9
|
# @param app [Sinatra::Base] A Sinatra app.
|
10
10
|
# @param config [Config, Hash] An instance of Config or a Hash config.
|
11
11
|
# @return [true, nil] true if the agent was started, nil otherwise.
|
12
|
-
def start(app, config)
|
12
|
+
def start(app, config = {})
|
13
13
|
config = Config.new(config) unless config.is_a?(Config)
|
14
14
|
configure_app(app, config)
|
15
15
|
|
data/lib/elastic_apm/span.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'securerandom'
|
4
|
-
require 'forwardable'
|
5
|
-
|
6
3
|
require 'elastic_apm/span/context'
|
7
4
|
|
8
5
|
module ElasticAPM
|
9
6
|
# @api private
|
10
7
|
class Span
|
11
8
|
extend Forwardable
|
12
|
-
|
13
|
-
def_delegators :@trace_context, :trace_id, :parent_id, :id
|
9
|
+
include ChildDurations::Methods
|
14
10
|
|
15
11
|
DEFAULT_TYPE = 'custom'
|
16
12
|
|
17
13
|
# rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
18
14
|
def initialize(
|
19
15
|
name:,
|
20
|
-
|
16
|
+
transaction:,
|
21
17
|
trace_context:,
|
18
|
+
parent:,
|
22
19
|
type: nil,
|
23
20
|
subtype: nil,
|
24
21
|
action: nil,
|
@@ -35,14 +32,17 @@ module ElasticAPM
|
|
35
32
|
@action = action
|
36
33
|
end
|
37
34
|
|
38
|
-
@
|
39
|
-
@
|
35
|
+
@transaction = transaction
|
36
|
+
@parent = parent
|
37
|
+
@trace_context = trace_context || parent.trace_context.child
|
40
38
|
|
41
39
|
@context = context || Span::Context.new
|
42
40
|
@stacktrace_builder = stacktrace_builder
|
43
41
|
end
|
44
42
|
# rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
|
45
43
|
|
44
|
+
def_delegators :@trace_context, :trace_id, :parent_id, :id
|
45
|
+
|
46
46
|
attr_accessor(
|
47
47
|
:action,
|
48
48
|
:name,
|
@@ -54,9 +54,11 @@ module ElasticAPM
|
|
54
54
|
attr_reader(
|
55
55
|
:context,
|
56
56
|
:duration,
|
57
|
+
:parent,
|
58
|
+
:self_time,
|
57
59
|
:stacktrace,
|
58
60
|
:timestamp,
|
59
|
-
:
|
61
|
+
:transaction
|
60
62
|
)
|
61
63
|
|
62
64
|
# life cycle
|
@@ -64,11 +66,14 @@ module ElasticAPM
|
|
64
66
|
def start(clock_start = Util.monotonic_micros)
|
65
67
|
@timestamp = Util.micros
|
66
68
|
@clock_start = clock_start
|
69
|
+
@parent.child_started
|
67
70
|
self
|
68
71
|
end
|
69
72
|
|
70
73
|
def stop(clock_end = Util.monotonic_micros)
|
71
74
|
@duration ||= (clock_end - @clock_start)
|
75
|
+
@parent.child_stopped
|
76
|
+
@self_time = @duration - child_durations.duration
|
72
77
|
self
|
73
78
|
end
|
74
79
|
|
@@ -96,7 +101,7 @@ module ElasticAPM
|
|
96
101
|
# relations
|
97
102
|
|
98
103
|
def inspect
|
99
|
-
"<ElasticAPM::Span id:#{id}" \
|
104
|
+
"<ElasticAPM::Span id:#{trace_context&.id}" \
|
100
105
|
" name:#{name.inspect}" \
|
101
106
|
" type:#{type.inspect}" \
|
102
107
|
'>'
|
data/lib/elastic_apm/spies.rb
CHANGED
@@ -9,21 +9,23 @@ module ElasticAPM
|
|
9
9
|
TABLE_REGEX = %{["'`]?([A-Za-z0-9_]+)["'`]?}
|
10
10
|
|
11
11
|
REGEXES = {
|
12
|
-
/^BEGIN/
|
13
|
-
/^COMMIT/
|
14
|
-
/^SELECT .* FROM #{TABLE_REGEX}/
|
15
|
-
/^INSERT INTO #{TABLE_REGEX}/
|
16
|
-
/^UPDATE #{TABLE_REGEX}/
|
17
|
-
/^DELETE FROM #{TABLE_REGEX}/
|
12
|
+
/^BEGIN/iu => 'BEGIN',
|
13
|
+
/^COMMIT/iu => 'COMMIT',
|
14
|
+
/^SELECT .* FROM #{TABLE_REGEX}/iu => 'SELECT FROM ',
|
15
|
+
/^INSERT INTO #{TABLE_REGEX}/iu => 'INSERT INTO ',
|
16
|
+
/^UPDATE #{TABLE_REGEX}/iu => 'UPDATE ',
|
17
|
+
/^DELETE FROM #{TABLE_REGEX}/iu => 'DELETE FROM '
|
18
18
|
}.freeze
|
19
19
|
|
20
20
|
FORMAT = '%s%s'
|
21
|
+
UTF8 = 'UTF-8'
|
21
22
|
|
22
23
|
def self.cache
|
23
24
|
@cache ||= Util::LruCache.new
|
24
25
|
end
|
25
26
|
|
26
27
|
def summarize(sql)
|
28
|
+
sql = sql.encode(UTF8, invalid: :replace, undef: :replace)
|
27
29
|
self.class.cache[sql] ||=
|
28
30
|
REGEXES.find do |regex, sig|
|
29
31
|
if (match = sql[0...1000].match(regex))
|
@@ -54,7 +54,7 @@ module ElasticAPM
|
|
54
54
|
end
|
55
55
|
# rubocop:enable Metrics/MethodLength
|
56
56
|
|
57
|
-
def finish(
|
57
|
+
def finish(name, id, payload)
|
58
58
|
# debug "AS::Notification#finish:#{name}:#{id}"
|
59
59
|
return unless (transaction = @agent.current_transaction)
|
60
60
|
|
@@ -62,6 +62,9 @@ module ElasticAPM
|
|
62
62
|
next unless notification.id == id
|
63
63
|
|
64
64
|
if (span = notification.span)
|
65
|
+
if @agent.config.span_frames_min_duration?
|
66
|
+
span.original_backtrace ||= @normalizers.backtrace(name, payload)
|
67
|
+
end
|
65
68
|
@agent.end_span if span == @agent.current_span
|
66
69
|
end
|
67
70
|
return
|
@@ -1,19 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'securerandom'
|
4
|
-
require 'forwardable'
|
5
|
-
|
6
3
|
module ElasticAPM
|
7
4
|
# @api private
|
8
5
|
class Transaction
|
9
6
|
extend Forwardable
|
7
|
+
include ChildDurations::Methods
|
10
8
|
|
11
9
|
def_delegators :@trace_context,
|
12
10
|
:trace_id, :parent_id, :id, :ensure_parent_id
|
13
11
|
|
14
12
|
DEFAULT_TYPE = 'custom'
|
15
13
|
|
16
|
-
# rubocop:disable Metrics/
|
14
|
+
# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
17
15
|
def initialize(
|
18
16
|
name = nil,
|
19
17
|
type = nil,
|
@@ -40,12 +38,12 @@ module ElasticAPM
|
|
40
38
|
|
41
39
|
@notifications = [] # for AS::Notifications
|
42
40
|
end
|
43
|
-
# rubocop:enable Metrics/
|
41
|
+
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
44
42
|
|
45
43
|
attr_accessor :name, :type, :result
|
46
44
|
|
47
45
|
attr_reader :context, :duration, :started_spans, :dropped_spans,
|
48
|
-
:timestamp, :trace_context, :notifications, :config
|
46
|
+
:timestamp, :trace_context, :notifications, :self_time, :config
|
49
47
|
|
50
48
|
def sampled?
|
51
49
|
@sampled
|
@@ -66,6 +64,8 @@ module ElasticAPM
|
|
66
64
|
def stop(clock_end = Util.monotonic_micros)
|
67
65
|
raise 'Transaction not yet start' unless timestamp
|
68
66
|
@duration = clock_end - @clock_start
|
67
|
+
@self_time = @duration - child_durations.duration
|
68
|
+
|
69
69
|
self
|
70
70
|
end
|
71
71
|
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'elastic_apm/metadata'
|
4
|
+
require 'elastic_apm/transport/user_agent'
|
5
|
+
require 'elastic_apm/transport/headers'
|
4
6
|
require 'elastic_apm/transport/connection'
|
5
7
|
require 'elastic_apm/transport/worker'
|
6
8
|
require 'elastic_apm/transport/serializers'
|
7
9
|
require 'elastic_apm/transport/filters'
|
10
|
+
require 'elastic_apm/transport/connection/http'
|
11
|
+
|
8
12
|
require 'elastic_apm/util/throttle'
|
9
13
|
|
10
14
|
module ElasticAPM
|
@@ -39,6 +43,8 @@ module ElasticAPM
|
|
39
43
|
|
40
44
|
ensure_watcher_running
|
41
45
|
ensure_worker_count
|
46
|
+
|
47
|
+
@stopped.make_false unless @stopped.false?
|
42
48
|
end
|
43
49
|
|
44
50
|
def stop
|
@@ -54,6 +60,7 @@ module ElasticAPM
|
|
54
60
|
def submit(resource)
|
55
61
|
if @stopped.true?
|
56
62
|
warn '%s: Transport stopping, no new events accepted', pid_str
|
63
|
+
debug 'Dropping: %s', resource.inspect
|
57
64
|
return false
|
58
65
|
end
|
59
66
|
|
@@ -1,13 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'concurrent'
|
4
|
-
require 'zlib'
|
5
|
-
|
6
|
-
require 'elastic_apm/transport/connection/http'
|
7
|
-
|
8
3
|
module ElasticAPM
|
9
4
|
module Transport
|
10
|
-
# rubocop:disable Metrics/ClassLength
|
11
5
|
# @api private
|
12
6
|
class Connection
|
13
7
|
include Logging
|
@@ -24,20 +18,14 @@ module ElasticAPM
|
|
24
18
|
# with ongoing write requests to `http`, write and close
|
25
19
|
# requests have to be synchronized.
|
26
20
|
|
27
|
-
|
28
|
-
'Content-Type' => 'application/x-ndjson',
|
29
|
-
'Transfer-Encoding' => 'chunked'
|
30
|
-
}.freeze
|
31
|
-
GZIP_HEADERS = HEADERS.merge(
|
32
|
-
'Content-Encoding' => 'gzip'
|
33
|
-
).freeze
|
34
|
-
|
35
|
-
def initialize(config, metadata)
|
21
|
+
def initialize(config)
|
36
22
|
@config = config
|
37
|
-
@
|
38
|
-
|
23
|
+
@metadata = JSON.fast_generate(
|
24
|
+
Serializers::MetadataSerializer.new(config).build(
|
25
|
+
Metadata.new(config)
|
26
|
+
)
|
27
|
+
)
|
39
28
|
@url = config.server_url + '/intake/v2/events'
|
40
|
-
@ssl_context = build_ssl_context
|
41
29
|
@mutex = Mutex.new
|
42
30
|
end
|
43
31
|
|
@@ -81,9 +69,8 @@ module ElasticAPM
|
|
81
69
|
|
82
70
|
def inspect
|
83
71
|
format(
|
84
|
-
'
|
85
|
-
super.split.first,
|
86
|
-
http.closed?
|
72
|
+
'<%s url:%s closed:%s >',
|
73
|
+
super.split.first, url, http&.closed?
|
87
74
|
)
|
88
75
|
end
|
89
76
|
|
@@ -93,11 +80,9 @@ module ElasticAPM
|
|
93
80
|
schedule_closing if @config.api_request_time
|
94
81
|
|
95
82
|
@http =
|
96
|
-
Http.open(
|
97
|
-
@
|
98
|
-
|
99
|
-
ssl_context: @ssl_context
|
100
|
-
).tap { |http| http.write(@metadata) }
|
83
|
+
Http.open(@config, @url).tap do |http|
|
84
|
+
http.write(@metadata)
|
85
|
+
end
|
101
86
|
end
|
102
87
|
# rubocop:enable
|
103
88
|
|
@@ -108,49 +93,6 @@ module ElasticAPM
|
|
108
93
|
flush(:timeout)
|
109
94
|
end
|
110
95
|
end
|
111
|
-
|
112
|
-
def build_headers(metadata)
|
113
|
-
(
|
114
|
-
@config.http_compression? ? GZIP_HEADERS : HEADERS
|
115
|
-
).dup.tap do |headers|
|
116
|
-
headers['User-Agent'] = build_user_agent(metadata)
|
117
|
-
|
118
|
-
if (token = @config.secret_token)
|
119
|
-
headers['Authorization'] = "Bearer #{token}"
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def build_user_agent(metadata)
|
125
|
-
runtime = metadata.dig(:metadata, :service, :runtime)
|
126
|
-
|
127
|
-
[
|
128
|
-
"elastic-apm-ruby/#{VERSION}",
|
129
|
-
HTTP::Request::USER_AGENT,
|
130
|
-
[runtime[:name], runtime[:version]].join('/')
|
131
|
-
].join(' ')
|
132
|
-
end
|
133
|
-
|
134
|
-
def build_ssl_context # rubocop:disable Metrics/MethodLength
|
135
|
-
return unless @config.use_ssl?
|
136
|
-
|
137
|
-
OpenSSL::SSL::SSLContext.new.tap do |context|
|
138
|
-
if @config.server_ca_cert
|
139
|
-
context.ca_file = @config.server_ca_cert
|
140
|
-
else
|
141
|
-
context.cert_store =
|
142
|
-
OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
143
|
-
end
|
144
|
-
|
145
|
-
context.verify_mode =
|
146
|
-
if @config.verify_server_cert
|
147
|
-
OpenSSL::SSL::VERIFY_PEER
|
148
|
-
else
|
149
|
-
OpenSSL::SSL::VERIFY_NONE
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
96
|
end
|
154
|
-
# rubocop:enable Metrics/ClassLength
|
155
97
|
end
|
156
98
|
end
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'http'
|
4
|
-
require 'concurrent'
|
5
|
-
require 'zlib'
|
6
|
-
|
7
3
|
require 'elastic_apm/transport/connection/proxy_pipe'
|
8
4
|
|
9
5
|
module ElasticAPM
|
@@ -13,23 +9,43 @@ module ElasticAPM
|
|
13
9
|
class Http
|
14
10
|
include Logging
|
15
11
|
|
16
|
-
def initialize(config)
|
12
|
+
def initialize(config, headers: nil)
|
17
13
|
@config = config
|
18
|
-
@
|
19
|
-
|
20
|
-
@
|
14
|
+
@headers = headers || Headers.new(config)
|
15
|
+
@client = build_client
|
16
|
+
@closed = Concurrent::AtomicBoolean.new(true)
|
21
17
|
end
|
22
18
|
|
23
|
-
def open(url
|
24
|
-
@
|
19
|
+
def open(url)
|
20
|
+
@closed.make_false
|
21
|
+
@rd, @wr = ProxyPipe.pipe(compress: @config.http_compression?)
|
22
|
+
@request = open_request_in_thread(url)
|
25
23
|
end
|
26
24
|
|
27
|
-
def self.open(config, url
|
25
|
+
def self.open(config, url)
|
28
26
|
new(config).tap do |http|
|
29
|
-
http.open(url
|
27
|
+
http.open(url)
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
31
|
+
def post(url, body: nil, headers: nil)
|
32
|
+
request(:post, url, body: body, headers: headers)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get(url, headers: nil)
|
36
|
+
request(:get, url, headers: headers)
|
37
|
+
end
|
38
|
+
|
39
|
+
def request(method, url, body: nil, headers: nil)
|
40
|
+
@client.send(
|
41
|
+
method,
|
42
|
+
url,
|
43
|
+
body: body,
|
44
|
+
headers: (headers ? @headers.merge(headers) : @headers).to_h,
|
45
|
+
ssl_context: @config.ssl_context
|
46
|
+
).flush
|
47
|
+
end
|
48
|
+
|
33
49
|
def write(str)
|
34
50
|
@wr.write(str)
|
35
51
|
@wr.bytes_sent
|
@@ -69,23 +85,29 @@ module ElasticAPM
|
|
69
85
|
format('[THREAD:%s]', Thread.current.object_id)
|
70
86
|
end
|
71
87
|
|
72
|
-
# rubocop:disable Metrics/
|
73
|
-
def open_request_in_thread(url
|
74
|
-
client = build_client(headers)
|
75
|
-
|
88
|
+
# rubocop:disable Metrics/MethodLength
|
89
|
+
def open_request_in_thread(url)
|
76
90
|
debug '%s: Opening new request', thread_str
|
77
91
|
Thread.new do
|
78
92
|
begin
|
79
|
-
post(
|
93
|
+
resp = post(url, body: @rd, headers: @headers.chunked.to_h)
|
94
|
+
|
95
|
+
if resp&.status == 202
|
96
|
+
debug 'APM Server responded with status 202'
|
97
|
+
elsif resp
|
98
|
+
error "APM Server responded with an error:\n%p", resp.body.to_s
|
99
|
+
end
|
80
100
|
rescue Exception => e
|
81
|
-
error
|
101
|
+
error(
|
102
|
+
"Couldn't establish connection to APM Server:\n%p", e.inspect
|
103
|
+
)
|
82
104
|
end
|
83
105
|
end
|
84
106
|
end
|
85
|
-
# rubocop:enable Metrics/
|
107
|
+
# rubocop:enable Metrics/MethodLength
|
86
108
|
|
87
|
-
def build_client
|
88
|
-
client = HTTP.headers(headers)
|
109
|
+
def build_client
|
110
|
+
client = HTTP.headers(@headers)
|
89
111
|
return client unless @config.proxy_address && @config.proxy_port
|
90
112
|
|
91
113
|
client.via(
|
@@ -96,20 +118,6 @@ module ElasticAPM
|
|
96
118
|
@config.proxy_headers
|
97
119
|
)
|
98
120
|
end
|
99
|
-
|
100
|
-
def post(client, url, ssl_context)
|
101
|
-
resp = client.post(
|
102
|
-
url,
|
103
|
-
body: @rd,
|
104
|
-
ssl_context: ssl_context
|
105
|
-
).flush
|
106
|
-
|
107
|
-
if resp&.status == 202
|
108
|
-
debug 'APM Server responded with status 202'
|
109
|
-
elsif resp
|
110
|
-
error "APM Server responded with an error:\n%p", resp.body.to_s
|
111
|
-
end
|
112
|
-
end
|
113
121
|
end
|
114
122
|
end
|
115
123
|
end
|