elastic-apm 2.6.1 → 2.7.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/.rubocop.yml +9 -0
- data/CHANGELOG.md +18 -1
- data/Jenkinsfile +3 -7
- data/README.md +1 -1
- data/docs/api.asciidoc +6 -0
- data/docs/configuration.asciidoc +16 -4
- data/docs/getting-started-rack.asciidoc +1 -1
- data/docs/getting-started-rails.asciidoc +1 -1
- data/docs/index.asciidoc +2 -0
- data/docs/release-notes.asciidoc +4 -0
- data/lib/elastic_apm/agent.rb +8 -3
- data/lib/elastic_apm/config.rb +4 -1
- data/lib/elastic_apm/error_builder.rb +2 -0
- data/lib/elastic_apm/instrumenter.rb +3 -1
- data/lib/elastic_apm/metadata/system_info.rb +2 -2
- data/lib/elastic_apm/metadata/system_info/container_info.rb +27 -23
- data/lib/elastic_apm/metrics.rb +13 -2
- data/lib/elastic_apm/railtie.rb +8 -3
- data/lib/elastic_apm/spies/faraday.rb +9 -1
- data/lib/elastic_apm/transport/base.rb +108 -31
- data/lib/elastic_apm/transport/connection.rb +77 -153
- data/lib/elastic_apm/transport/connection/http.rb +116 -0
- data/lib/elastic_apm/transport/connection/proxy_pipe.rb +68 -0
- data/lib/elastic_apm/transport/filters/secrets_filter.rb +1 -0
- data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +2 -1
- data/lib/elastic_apm/transport/worker.rb +14 -19
- data/lib/elastic_apm/util.rb +4 -2
- data/lib/elastic_apm/util/throttle.rb +35 -0
- data/lib/elastic_apm/version.rb +1 -1
- metadata +6 -2
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'http'
|
4
|
+
require 'concurrent'
|
5
|
+
require 'zlib'
|
6
|
+
|
7
|
+
require 'elastic_apm/transport/connection/proxy_pipe'
|
8
|
+
|
9
|
+
module ElasticAPM
|
10
|
+
module Transport
|
11
|
+
class Connection
|
12
|
+
# @api private
|
13
|
+
class Http
|
14
|
+
include Logging
|
15
|
+
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
@closed = Concurrent::AtomicBoolean.new
|
19
|
+
|
20
|
+
@rd, @wr = ProxyPipe.pipe(compress: @config.http_compression?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def open(url, headers: {}, ssl_context: nil)
|
24
|
+
@request = open_request_in_thread(url, headers, ssl_context)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.open(config, url, headers: {}, ssl_context: nil)
|
28
|
+
new(config).tap do |http|
|
29
|
+
http.open(url, headers: headers, ssl_context: ssl_context)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def write(str)
|
34
|
+
@wr.write(str)
|
35
|
+
@wr.bytes_sent
|
36
|
+
end
|
37
|
+
|
38
|
+
def close(reason)
|
39
|
+
return if closed?
|
40
|
+
|
41
|
+
debug '%s: Closing request with reason %s', thread_str, reason
|
42
|
+
@closed.make_true
|
43
|
+
|
44
|
+
@wr&.close(reason)
|
45
|
+
return if @request.nil? || @request&.join(5)
|
46
|
+
|
47
|
+
error(
|
48
|
+
'%s: APM Server not responding in time, terminating request',
|
49
|
+
thread_str
|
50
|
+
)
|
51
|
+
@request.kill
|
52
|
+
end
|
53
|
+
|
54
|
+
def closed?
|
55
|
+
@closed.true?
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
format(
|
60
|
+
'%s closed: %s>',
|
61
|
+
super.split.first,
|
62
|
+
closed?
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def thread_str
|
69
|
+
format('[THREAD:%s]', Thread.current.object_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
# rubocop:disable Metrics/LineLength
|
73
|
+
def open_request_in_thread(url, headers, ssl_context)
|
74
|
+
client = build_client(headers)
|
75
|
+
|
76
|
+
debug '%s: Opening new request', thread_str
|
77
|
+
Thread.new do
|
78
|
+
begin
|
79
|
+
post(client, url, ssl_context)
|
80
|
+
rescue Exception => e
|
81
|
+
error "Couldn't establish connection to APM Server:\n%p", e.inspect
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
# rubocop:enable Metrics/LineLength
|
86
|
+
|
87
|
+
def build_client(headers)
|
88
|
+
client = HTTP.headers(headers)
|
89
|
+
return client unless @config.proxy_address && @config.proxy_port
|
90
|
+
|
91
|
+
client.via(
|
92
|
+
@config.proxy_address,
|
93
|
+
@config.proxy_port,
|
94
|
+
@config.proxy_username,
|
95
|
+
@config.proxy_password,
|
96
|
+
@config.proxy_headers
|
97
|
+
)
|
98
|
+
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
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent'
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
module ElasticAPM
|
7
|
+
module Transport
|
8
|
+
class Connection
|
9
|
+
# @api private
|
10
|
+
class ProxyPipe
|
11
|
+
def initialize(enc = nil, compress: true)
|
12
|
+
@read, wr = IO.pipe(enc)
|
13
|
+
@write = Write.new(wr, compress: compress)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :read, :write
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
class Write
|
20
|
+
include Logging
|
21
|
+
|
22
|
+
def initialize(io, compress: true)
|
23
|
+
@io = io
|
24
|
+
@compress = compress
|
25
|
+
@bytes_sent = Concurrent::AtomicFixnum.new(0)
|
26
|
+
@config = ElasticAPM.agent&.config # this is silly, fix Logging
|
27
|
+
|
28
|
+
return unless compress
|
29
|
+
enable_compression!
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :io
|
33
|
+
|
34
|
+
def enable_compression!
|
35
|
+
io.binmode
|
36
|
+
@io = Zlib::GzipWriter.new(io)
|
37
|
+
end
|
38
|
+
|
39
|
+
def close(reason = nil)
|
40
|
+
debug("Closing writer with reason #{reason}")
|
41
|
+
io.close
|
42
|
+
end
|
43
|
+
|
44
|
+
def closed?
|
45
|
+
io.closed?
|
46
|
+
end
|
47
|
+
|
48
|
+
def write(str)
|
49
|
+
io.puts(str).tap do
|
50
|
+
@bytes_sent.update do |curr|
|
51
|
+
@compress ? io.tell : curr + str.bytesize
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def bytes_sent
|
57
|
+
@bytes_sent.value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.pipe(*args)
|
62
|
+
pipe = new(*args)
|
63
|
+
[pipe.read, pipe.write]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -29,6 +29,7 @@ module ElasticAPM
|
|
29
29
|
|
30
30
|
def call(payload)
|
31
31
|
strip_from! payload.dig(:transaction, :context, :request, :headers)
|
32
|
+
strip_from! payload.dig(:transaction, :context, :request, :env)
|
32
33
|
strip_from! payload.dig(:transaction, :context, :response, :headers)
|
33
34
|
strip_from! payload.dig(:error, :context, :request, :headers)
|
34
35
|
strip_from! payload.dig(:error, :context, :response, :headers)
|
@@ -55,7 +55,8 @@ module ElasticAPM
|
|
55
55
|
{
|
56
56
|
hostname: keyword_field(system.hostname),
|
57
57
|
architecture: keyword_field(system.architecture),
|
58
|
-
platform: keyword_field(system.platform)
|
58
|
+
platform: keyword_field(system.platform),
|
59
|
+
kubernetes: keyword_object(system.kubernetes)
|
59
60
|
}
|
60
61
|
end
|
61
62
|
end
|
@@ -22,8 +22,6 @@ module ElasticAPM
|
|
22
22
|
@config = config
|
23
23
|
@queue = queue
|
24
24
|
|
25
|
-
@stopping = false
|
26
|
-
|
27
25
|
@serializers = serializers
|
28
26
|
@filters = filters
|
29
27
|
|
@@ -33,29 +31,17 @@ module ElasticAPM
|
|
33
31
|
|
34
32
|
attr_reader :queue, :filters, :name, :connection, :serializers
|
35
33
|
|
36
|
-
def stop
|
37
|
-
@stopping = true
|
38
|
-
end
|
39
|
-
|
40
|
-
def stopping?
|
41
|
-
@stopping
|
42
|
-
end
|
43
|
-
|
44
34
|
# rubocop:disable Metrics/MethodLength
|
45
35
|
def work_forever
|
46
36
|
while (msg = queue.pop)
|
47
37
|
case msg
|
48
38
|
when StopMessage
|
49
|
-
|
39
|
+
debug 'Stopping worker -- %s', self
|
40
|
+
connection.flush(:halt)
|
41
|
+
break
|
50
42
|
else
|
51
43
|
process msg
|
52
44
|
end
|
53
|
-
|
54
|
-
next unless stopping?
|
55
|
-
|
56
|
-
debug 'Stopping worker -- %s', self
|
57
|
-
@connection.flush
|
58
|
-
break
|
59
45
|
end
|
60
46
|
rescue Exception => e
|
61
47
|
warn 'Worker died with exception: %s', e.inspect
|
@@ -63,12 +49,21 @@ module ElasticAPM
|
|
63
49
|
end
|
64
50
|
# rubocop:enable Metrics/MethodLength
|
65
51
|
|
52
|
+
def process(resource)
|
53
|
+
return unless (json = serialize_and_filter(resource))
|
54
|
+
connection.write(json)
|
55
|
+
end
|
56
|
+
|
66
57
|
private
|
67
58
|
|
68
|
-
def
|
59
|
+
def serialize_and_filter(resource)
|
69
60
|
serialized = serializers.serialize(resource)
|
70
61
|
@filters.apply!(serialized)
|
71
|
-
|
62
|
+
JSON.fast_generate(serialized)
|
63
|
+
rescue Exception
|
64
|
+
error format('Failed converting event to JSON: %s', resource.inspect)
|
65
|
+
error serialized.inspect
|
66
|
+
nil
|
72
67
|
end
|
73
68
|
end
|
74
69
|
end
|
data/lib/elastic_apm/util.rb
CHANGED
@@ -21,8 +21,10 @@ module ElasticAPM
|
|
21
21
|
str.hex.to_s(2).rjust(str.size * 4, '0')
|
22
22
|
end
|
23
23
|
|
24
|
-
def self.reverse_merge!(first,
|
25
|
-
|
24
|
+
def self.reverse_merge!(first, *others)
|
25
|
+
others.reduce(first) do |curr, other|
|
26
|
+
curr.merge!(other) { |_, _, new| new }
|
27
|
+
end
|
26
28
|
end
|
27
29
|
|
28
30
|
def self.truncate(value, max_length: 1024)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
module Util
|
5
|
+
# @api private
|
6
|
+
|
7
|
+
# Usage example:
|
8
|
+
# Throttle.new(5) { thing to only do once per 5 secs }
|
9
|
+
class Throttle
|
10
|
+
def initialize(buffer_secs, &block)
|
11
|
+
@buffer_secs = buffer_secs
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
if @last_call && seconds_since_last_call < @buffer_secs
|
17
|
+
return @last_result
|
18
|
+
end
|
19
|
+
|
20
|
+
@last_call = now
|
21
|
+
@last_result = @block.call
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def now
|
27
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
28
|
+
end
|
29
|
+
|
30
|
+
def seconds_since_last_call
|
31
|
+
now - @last_call
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/elastic_apm/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastic-apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- docs/introduction.asciidoc
|
80
80
|
- docs/metrics.asciidoc
|
81
81
|
- docs/opentracing.asciidoc
|
82
|
+
- docs/release-notes.asciidoc
|
82
83
|
- docs/supported-technologies.asciidoc
|
83
84
|
- elastic-apm.gemspec
|
84
85
|
- lib/elastic-apm.rb
|
@@ -146,6 +147,8 @@ files:
|
|
146
147
|
- lib/elastic_apm/transaction.rb
|
147
148
|
- lib/elastic_apm/transport/base.rb
|
148
149
|
- lib/elastic_apm/transport/connection.rb
|
150
|
+
- lib/elastic_apm/transport/connection/http.rb
|
151
|
+
- lib/elastic_apm/transport/connection/proxy_pipe.rb
|
149
152
|
- lib/elastic_apm/transport/filters.rb
|
150
153
|
- lib/elastic_apm/transport/filters/secrets_filter.rb
|
151
154
|
- lib/elastic_apm/transport/serializers.rb
|
@@ -160,6 +163,7 @@ files:
|
|
160
163
|
- lib/elastic_apm/util/inflector.rb
|
161
164
|
- lib/elastic_apm/util/lru_cache.rb
|
162
165
|
- lib/elastic_apm/util/prefixed_logger.rb
|
166
|
+
- lib/elastic_apm/util/throttle.rb
|
163
167
|
- lib/elastic_apm/version.rb
|
164
168
|
- vendor/.gitkeep
|
165
169
|
homepage: https://github.com/elastic/apm-agent-ruby
|