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
data/docs/api.asciidoc
CHANGED
@@ -193,9 +193,9 @@ Returns the built context.
|
|
193
193
|
|
194
194
|
[float]
|
195
195
|
[[rails-start]]
|
196
|
-
===
|
196
|
+
=== Rails
|
197
197
|
|
198
|
-
Start the agent and hook into Rails
|
198
|
+
Start the agent and hook into Rails manually. This is useful if you skip requiring
|
199
199
|
the gem and using the `Railtie`.
|
200
200
|
|
201
201
|
[source,ruby]
|
@@ -214,6 +214,17 @@ Start the agent and hook into Sinatra.
|
|
214
214
|
ElasticAPM::Sinatra.start(MySinatraApp, server_url: 'http://localhost:8200')
|
215
215
|
----
|
216
216
|
|
217
|
+
[float]
|
218
|
+
[[grape-start]]
|
219
|
+
=== Grape
|
220
|
+
|
221
|
+
Start the agent and hook into Grape.
|
222
|
+
|
223
|
+
[source,ruby]
|
224
|
+
----
|
225
|
+
ElasticAPM::Grape.start(MyGrapeApp, server_url: 'http://localhost:8200')
|
226
|
+
----
|
227
|
+
|
217
228
|
[float]
|
218
229
|
=== Errors
|
219
230
|
|
data/docs/configuration.asciidoc
CHANGED
@@ -66,6 +66,23 @@ ElasticAPM::Sinatra.start(
|
|
66
66
|
|
67
67
|
See <<getting-started-rack>>.
|
68
68
|
|
69
|
+
[float]
|
70
|
+
=== Grape and Rack
|
71
|
+
|
72
|
+
When using APM with Grape and Rack (without Rails), you can configure it when starting
|
73
|
+
the agent:
|
74
|
+
|
75
|
+
[source,ruby]
|
76
|
+
----
|
77
|
+
# config.ru or similar
|
78
|
+
ElasticAPM::Grape.start(
|
79
|
+
MyApp,
|
80
|
+
service_name: 'SomeOtherName'
|
81
|
+
)
|
82
|
+
----
|
83
|
+
|
84
|
+
See <<getting-started-rack>>.
|
85
|
+
|
69
86
|
[float]
|
70
87
|
=== Options
|
71
88
|
|
@@ -184,6 +201,19 @@ APM Server has its own limit of 30 seconds before it will close requests.
|
|
184
201
|
|
185
202
|
It has to be provided in *<<config-format-duration, duration format>>*.
|
186
203
|
|
204
|
+
[float]
|
205
|
+
[[config-breakdown-metrics]]
|
206
|
+
==== `breakdown-metrics`
|
207
|
+
|============
|
208
|
+
| Environment | `Config` key | Default
|
209
|
+
| `ELASTIC_APM_BREAKDOWN_METRICS` | `breakdown_metrics` | `true`
|
210
|
+
|============
|
211
|
+
|
212
|
+
Enable/disable the tracking and collection of breakdown metrics.
|
213
|
+
By setting this to `False`, tracking this metric is completely disabled, which can reduce the overhead of the agent.
|
214
|
+
|
215
|
+
NOTE: This feature requires APM Server and Kibana >= 7.3.
|
216
|
+
|
187
217
|
[float]
|
188
218
|
[[config-capture-body]]
|
189
219
|
==== `capture_body`
|
@@ -72,3 +72,27 @@ run MySinatraApp
|
|
72
72
|
at_exit { ElasticAPM.stop }
|
73
73
|
----
|
74
74
|
|
75
|
+
[float]
|
76
|
+
[[getting-started-grape]]
|
77
|
+
==== Grape example
|
78
|
+
|
79
|
+
[source,ruby]
|
80
|
+
----
|
81
|
+
# Example config.ru
|
82
|
+
|
83
|
+
require 'grape'
|
84
|
+
|
85
|
+
module Twitter
|
86
|
+
class API < Grape::API
|
87
|
+
use ElasticAPM::Middleware
|
88
|
+
|
89
|
+
# ...
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Start the agent and hook in your app
|
94
|
+
ElasticAPM::Grape.start(Twitter::API, config)
|
95
|
+
|
96
|
+
run Twitter::API
|
97
|
+
|
98
|
+
----
|
data/docs/release-notes.asciidoc
CHANGED
data/lib/elastic_apm.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'erb'
|
4
|
+
require 'http'
|
5
|
+
require 'json'
|
6
|
+
require 'yaml'
|
7
|
+
require 'zlib'
|
8
|
+
require 'logger'
|
9
|
+
require 'concurrent'
|
10
|
+
require 'forwardable'
|
11
|
+
require 'securerandom'
|
12
|
+
|
3
13
|
require 'elastic_apm/version'
|
4
14
|
require 'elastic_apm/internal_error'
|
5
15
|
require 'elastic_apm/logging'
|
@@ -13,8 +23,9 @@ require 'elastic_apm/util'
|
|
13
23
|
|
14
24
|
require 'elastic_apm/middleware'
|
15
25
|
|
16
|
-
require 'elastic_apm/
|
26
|
+
require 'elastic_apm/rails' if defined?(::Rails::Railtie)
|
17
27
|
require 'elastic_apm/sinatra' if defined?(::Sinatra)
|
28
|
+
require 'elastic_apm/grape' if defined?(::Grape)
|
18
29
|
|
19
30
|
# ElasticAPM
|
20
31
|
module ElasticAPM # rubocop:disable Metrics/ModuleLength
|
data/lib/elastic_apm/agent.rb
CHANGED
@@ -62,6 +62,7 @@ module ElasticAPM
|
|
62
62
|
!!@instance
|
63
63
|
end
|
64
64
|
|
65
|
+
# rubocop:disable Metrics/MethodLength
|
65
66
|
def initialize(config)
|
66
67
|
@stacktrace_builder = StacktraceBuilder.new(config)
|
67
68
|
@context_builder = ContextBuilder.new(config)
|
@@ -69,12 +70,14 @@ module ElasticAPM
|
|
69
70
|
|
70
71
|
@central_config = CentralConfig.new(config)
|
71
72
|
@transport = Transport::Base.new(config)
|
73
|
+
@metrics = Metrics.new(config) { |event| enqueue event }
|
72
74
|
@instrumenter = Instrumenter.new(
|
73
75
|
config,
|
76
|
+
metrics: metrics,
|
74
77
|
stacktrace_builder: stacktrace_builder
|
75
78
|
) { |event| enqueue event }
|
76
|
-
@metrics = Metrics.new(config) { |event| enqueue event }
|
77
79
|
end
|
80
|
+
# rubocop:enable Metrics/MethodLength
|
78
81
|
|
79
82
|
attr_reader(
|
80
83
|
:central_config,
|
@@ -91,8 +94,11 @@ module ElasticAPM
|
|
91
94
|
|
92
95
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
93
96
|
def start
|
94
|
-
unless config.disable_start_message
|
95
|
-
info
|
97
|
+
unless config.disable_start_message?
|
98
|
+
config.logger.info format(
|
99
|
+
'[%s] Starting agent, reporting to %s',
|
100
|
+
VERSION, config.server_url
|
101
|
+
)
|
96
102
|
end
|
97
103
|
|
98
104
|
central_config.start
|
@@ -231,6 +237,12 @@ module ElasticAPM
|
|
231
237
|
def add_filter(key, callback)
|
232
238
|
transport.add_filter(key, callback)
|
233
239
|
end
|
240
|
+
|
241
|
+
# misc
|
242
|
+
|
243
|
+
def inspect
|
244
|
+
super.split.first + '>'
|
245
|
+
end
|
234
246
|
end
|
235
247
|
# rubocop:enable Metrics/ClassLength
|
236
248
|
end
|
@@ -4,7 +4,7 @@ require 'elastic_apm/central_config/cache_control'
|
|
4
4
|
|
5
5
|
module ElasticAPM
|
6
6
|
# @api private
|
7
|
-
class CentralConfig
|
7
|
+
class CentralConfig # rubocop:disable Metrics/ClassLength
|
8
8
|
include Logging
|
9
9
|
|
10
10
|
# @api private
|
@@ -23,10 +23,8 @@ module ElasticAPM
|
|
23
23
|
def initialize(config)
|
24
24
|
@config = config
|
25
25
|
@modified_options = {}
|
26
|
-
@
|
27
|
-
|
28
|
-
'service.environment': config.environment
|
29
|
-
}.to_json
|
26
|
+
@http = Transport::Connection::Http.new(config)
|
27
|
+
@etag = 1
|
30
28
|
end
|
31
29
|
|
32
30
|
attr_reader :config
|
@@ -35,9 +33,17 @@ module ElasticAPM
|
|
35
33
|
def start
|
36
34
|
return unless config.central_config?
|
37
35
|
|
36
|
+
debug 'Starting CentralConfig'
|
37
|
+
|
38
38
|
fetch_and_apply_config
|
39
39
|
end
|
40
40
|
|
41
|
+
def stop
|
42
|
+
debug 'Stopping CentralConfig'
|
43
|
+
|
44
|
+
@scheduled_task&.cancel
|
45
|
+
end
|
46
|
+
|
41
47
|
def fetch_and_apply_config
|
42
48
|
@promise =
|
43
49
|
Concurrent::Promise
|
@@ -46,10 +52,6 @@ module ElasticAPM
|
|
46
52
|
.rescue(&method(:handle_error))
|
47
53
|
end
|
48
54
|
|
49
|
-
def stop
|
50
|
-
@scheduled_task&.cancel
|
51
|
-
end
|
52
|
-
|
53
55
|
# rubocop:disable Metrics/MethodLength
|
54
56
|
def fetch_config
|
55
57
|
resp = perform_request
|
@@ -90,15 +92,25 @@ module ElasticAPM
|
|
90
92
|
@config = config.dup.tap { |new_config| new_config.assign(new_options) }
|
91
93
|
end
|
92
94
|
|
93
|
-
# rubocop:disable Metrics/MethodLength
|
95
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
96
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
94
97
|
def handle_success(resp)
|
98
|
+
if (etag = resp.headers['Etag'])
|
99
|
+
@etag = etag
|
100
|
+
end
|
101
|
+
|
95
102
|
if resp.status == 304
|
96
103
|
info 'Received 304 Not Modified'
|
97
104
|
else
|
98
|
-
|
99
|
-
|
105
|
+
if resp.body && !resp.body.empty?
|
106
|
+
update = JSON.parse(resp.body.to_s)
|
107
|
+
assign(update)
|
108
|
+
end
|
100
109
|
|
101
|
-
|
110
|
+
if @modified_options.any?
|
111
|
+
info 'Updated config from Kibana'
|
112
|
+
debug 'Modified: %s', @modified_options.inspect
|
113
|
+
end
|
102
114
|
end
|
103
115
|
|
104
116
|
schedule_next_fetch(resp)
|
@@ -108,7 +120,8 @@ module ElasticAPM
|
|
108
120
|
error 'Failed to apply remote config, %s', e.inspect
|
109
121
|
debug { e.backtrace.join('\n') }
|
110
122
|
end
|
111
|
-
# rubocop:enable Metrics/
|
123
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
124
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
112
125
|
|
113
126
|
def handle_error(error)
|
114
127
|
debug(
|
@@ -122,11 +135,18 @@ module ElasticAPM
|
|
122
135
|
end
|
123
136
|
|
124
137
|
def perform_request
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
138
|
+
@http.get(server_url, headers: headers)
|
139
|
+
end
|
140
|
+
|
141
|
+
def server_url
|
142
|
+
@server_url ||=
|
143
|
+
config.server_url +
|
144
|
+
'/config/v1/agents' \
|
145
|
+
"?service.name=#{config.service_name}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def headers
|
149
|
+
{ 'Etag': @etag }
|
130
150
|
end
|
131
151
|
|
132
152
|
def schedule_next_fetch(resp)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module ChildDurations
|
6
|
+
# @api private
|
7
|
+
module Methods
|
8
|
+
def child_durations
|
9
|
+
@child_durations ||= Durations.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def child_started
|
13
|
+
child_durations.start
|
14
|
+
end
|
15
|
+
|
16
|
+
def child_stopped
|
17
|
+
child_durations.stop
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
class Durations
|
23
|
+
def initialize
|
24
|
+
@nesting_level = 0
|
25
|
+
@start = nil
|
26
|
+
@duration = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :duration
|
30
|
+
|
31
|
+
def start
|
32
|
+
@nesting_level += 1
|
33
|
+
@start = Util.micros if @nesting_level == 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
@nesting_level -= 1
|
38
|
+
@duration = (Util.micros - @start) if @nesting_level == 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/elastic_apm/config.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'logger'
|
4
|
-
require 'yaml'
|
5
|
-
require 'erb'
|
6
|
-
|
7
|
-
require 'elastic_apm/util/prefixed_logger'
|
8
|
-
|
9
3
|
require 'elastic_apm/config/options'
|
10
4
|
require 'elastic_apm/config/duration'
|
11
5
|
require 'elastic_apm/config/bytes'
|
@@ -28,6 +22,7 @@ module ElasticAPM
|
|
28
22
|
option :api_buffer_size, type: :int, default: 256
|
29
23
|
option :api_request_size, type: :bytes, default: '750kb', converter: Bytes.new
|
30
24
|
option :api_request_time, type: :float, default: '10s', converter: Duration.new
|
25
|
+
option :breakdown_metrics, type: :bool, default: true
|
31
26
|
option :capture_body, type: :string, default: 'off'
|
32
27
|
option :capture_headers, type: :bool, default: true
|
33
28
|
option :capture_env, type: :bool, default: true
|
@@ -79,8 +74,6 @@ module ElasticAPM
|
|
79
74
|
def initialize(options = {})
|
80
75
|
@options = load_schema
|
81
76
|
|
82
|
-
custom_logger = options.delete(:logger)
|
83
|
-
|
84
77
|
assign(options)
|
85
78
|
|
86
79
|
# Pick out config_file specifically as we need it now to load it,
|
@@ -95,10 +88,10 @@ module ElasticAPM
|
|
95
88
|
|
96
89
|
yield self if block_given?
|
97
90
|
|
98
|
-
|
91
|
+
self.logger ||= build_logger
|
99
92
|
|
100
|
-
@__view_paths
|
101
|
-
@__root_path
|
93
|
+
@__view_paths ||= []
|
94
|
+
@__root_path ||= Dir.pwd
|
102
95
|
end
|
103
96
|
# rubocop:enable Metrics/MethodLength
|
104
97
|
|
@@ -173,6 +166,29 @@ module ElasticAPM
|
|
173
166
|
@span_frames_min_duration_us ||= span_frames_min_duration * 1_000_000
|
174
167
|
end
|
175
168
|
|
169
|
+
# rubocop:disable Metrics/MethodLength
|
170
|
+
def ssl_context
|
171
|
+
return unless use_ssl?
|
172
|
+
|
173
|
+
@ssl_context ||=
|
174
|
+
OpenSSL::SSL::SSLContext.new.tap do |context|
|
175
|
+
if server_ca_cert
|
176
|
+
context.ca_file = server_ca_cert
|
177
|
+
else
|
178
|
+
context.cert_store =
|
179
|
+
OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
180
|
+
end
|
181
|
+
|
182
|
+
context.verify_mode =
|
183
|
+
if verify_server_cert
|
184
|
+
OpenSSL::SSL::VERIFY_PEER
|
185
|
+
else
|
186
|
+
OpenSSL::SSL::VERIFY_NONE
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
# rubocop:enable Metrics/MethodLength
|
191
|
+
|
176
192
|
def inspect
|
177
193
|
super.split.first + '>'
|
178
194
|
end
|
data/lib/elastic_apm/error.rb
CHANGED
@@ -18,5 +18,15 @@ module ElasticAPM
|
|
18
18
|
attr_accessor :id, :culprit, :exception, :log, :transaction_id,
|
19
19
|
:transaction, :context, :parent_id, :trace_id
|
20
20
|
attr_reader :timestamp
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"<ElasticAPM::Error id:#{id}" \
|
24
|
+
" culprit:#{culprit}" \
|
25
|
+
" timestamp:#{timestamp}" \
|
26
|
+
" transaction_id:#{transaction_id}" \
|
27
|
+
" trace_id:#{trace_id}" \
|
28
|
+
" exception:#{exception.inspect}" \
|
29
|
+
">"
|
30
|
+
end
|
21
31
|
end
|
22
32
|
end
|