elastic-apm 3.1.0 → 3.2.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 +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
|