elastic-apm 2.5.0 → 2.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2ef17d6e9c0be751b1eec5e6083560d5eed2c3fbeb044adf361563b1f83ca01
4
- data.tar.gz: b2ef8af13b2308b47149e9f9ac413825a5a23827f51af7a78c258848d99a6670
3
+ metadata.gz: 461871ffc956519fbd712017336bcc012f0c41d6b1696dc32a3117860b3b736d
4
+ data.tar.gz: 468207605feaa4d888fbf1bfcd665c8f7bb0953d0b5c7e1e92d4f266c85855f6
5
5
  SHA512:
6
- metadata.gz: ea7a58ffc1ed6eac693a32d9312f93e05ec47b047819b0420172a26de8a21bc7422a300fd6b405bbf24b8b40900a9ce6b7c97fc53502130eb641837120681420
7
- data.tar.gz: b453578df37793a7dfeb6b3383530c652ec477b28303eefe35bf1e7a5ce3ea21fadb82621070c4de6de6d1c3e4acd6bd2023b3d9ec366a688b19ca73c93880e1
6
+ metadata.gz: b22550a4a59b6311e55a86306ab9c5af705f65754e7f7f0afa7509565724f68c4ada5781c17354bc724da181acc2158c45f8447297dea1ead99bdc20f74094a9
7
+ data.tar.gz: 15b61ed7489a8468a56983c0e8a33418441695bcc28c08e477110204ba8b53e1a022ebfbd660720e8a3227004ac0adc1b8eeb34523cceba902f78129421baabe
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 2.6.0 (2019-03-19)
8
+
9
+ ### Deprecated
10
+
11
+ - `ElasticAPM.build_context` now takes two keyword arguments instead of a single, normal argument. [Docs](https://www.elastic.co/guide/en/apm/agent/ruby/2.x/api.html#api-agent-build-context).
12
+ - The option `capture_body` has a string value instead of boolean. [Docs](https://www.elastic.co/guide/en/apm/agent/ruby/2.x/configuration.html#config-capture-body).
13
+
14
+ Both APIs are backwards compatible with fallbacks and deprecation warnings, scheduled for removal in next major release.
15
+
16
+ ### Added
17
+
18
+ - Configuration options to use an HTTP proxy ([#352](https://github.com/elastic/apm-agent-ruby/pull/352))
19
+
20
+ ### Changed
21
+
22
+ - Errors get their own contexts, perhaps leading to slightly different (but more correct) results. ([#335](https://github.com/elastic/apm-agent-ruby/pull/335))
23
+ - The agent no longer starts automatically inside Rails' console ([#343](https://github.com/elastic/apm-agent-ruby/pull/343))
24
+
25
+ ### Fixed
26
+
27
+ - Fixed reading available memory on older Linux kernels ([#351](https://github.com/elastic/apm-agent-ruby/pull/351))
28
+ - Don't apply filters to original response headers ([#354](https://github.com/elastic/apm-agent-ruby/pull/354))
29
+
7
30
  ## 2.5.0 (2019-03-01)
8
31
 
9
32
  ### Added
@@ -85,8 +85,9 @@ $ spec/scripts/spec.sh ruby-2.6 rails-5.2
85
85
  To release a new version:
86
86
 
87
87
  1. Update `VERSION` in `lib/elastic_apm/version.rb` according to the changes (major, minor, patch).
88
- 2. Update `CHANGELOG.md` to reflect the new version -- change _Unreleased_ section to _Version (release date)_.
89
- 3. Run `rake release`. This will...
88
+ 2. Update `CHANGELOG.md` to reflect the new version change _Unreleased_ section to _Version (release date)_.
89
+ 3. Make a new commit with the changes above, with a message in the style of `vX.X.X`.
90
+ 4. Run `rake release`. This will...
90
91
  1. Tag the current commit as new version.
91
92
  2. Push the tag to GitHub.
92
93
  3. Build the gem and upload to Rubygems (local user needs to be signed in and authorized.)
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env groovy
2
- @Library('apm@v1.0.9') _
2
+ @Library('apm@current') _
3
3
 
4
4
  import co.elastic.matrix.*
5
5
  import groovy.transform.Field
@@ -25,6 +25,8 @@ pipeline {
25
25
  ansiColor('xterm')
26
26
  disableResume()
27
27
  durabilityHint('PERFORMANCE_OPTIMIZED')
28
+ rateLimitBuilds(throttle: [count: 60, durationName: 'hour', userBoost: true])
29
+ quietPeriod(10)
28
30
  }
29
31
  triggers {
30
32
  issueCommentTrigger('.*(?:jenkins\\W+)?run\\W+(?:the\\W+)?tests(?:\\W+please)?.*')
@@ -39,7 +41,7 @@ pipeline {
39
41
  Checkout the code and stash it, to use it on other stages.
40
42
  */
41
43
  stage('Checkout') {
42
- agent { label 'flyweight' }
44
+ agent { label 'master || immutable' }
43
45
  options { skipDefaultCheckout() }
44
46
  steps {
45
47
  deleteDir()
@@ -51,7 +53,7 @@ pipeline {
51
53
  Execute unit tests.
52
54
  */
53
55
  stage('Test') {
54
- agent { label 'flyweight' }
56
+ agent { label 'linux && immutable' }
55
57
  options { skipDefaultCheckout() }
56
58
  steps {
57
59
  deleteDir()
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # elastic-apm
2
2
  ## Elastic APM agent for ♦️Ruby
3
3
 
4
- [![Jenkins](https://img.shields.io/jenkins/s/https/apm-ci.elastic.co/job/elastic+apm-agent-ruby+master.svg)](https://apm-ci.elastic.co/job/elastic+apm-agent-ruby+master/) [![Gem](https://img.shields.io/gem/v/elastic-apm.svg)](https://rubygems.org/gems/elastic-apm) [![codecov](https://codecov.io/gh/elastic/apm-agent-ruby/branch/master/graph/badge.svg)](https://codecov.io/gh/elastic/apm-agent-ruby)
4
+ [![Jenkins](https://apm-ci.elastic.co/buildStatus/icon?job=apm-agent-ruby/apm-agent-ruby-mbp/master)](https://apm-ci.elastic.co/job/apm-agent-ruby/apm-agent-ruby-mbp/master) [![Gem](https://img.shields.io/gem/v/elastic-apm.svg)](https://rubygems.org/gems/elastic-apm) [![codecov](https://codecov.io/gh/elastic/apm-agent-ruby/branch/master/graph/badge.svg)](https://codecov.io/gh/elastic/apm-agent-ruby)
5
5
 
6
6
  The official Rubygem for [Elastic][] [APM][].
7
7
 
@@ -182,6 +182,7 @@ A context provides information about the current request, response, user and mor
182
182
  Arguments:
183
183
 
184
184
  * `rack_env`: An instance of Rack::Env
185
+ * `for_type`: Symbol representing type of event, eg. `:transaction` or `error`
185
186
 
186
187
  Returns the built context.
187
188
 
@@ -177,11 +177,21 @@ It has to be provided in *<<config-format-duration, duration format>>*.
177
177
  [[config-capture-body]]
178
178
  ==== `capture_body`
179
179
  |============
180
- | Environment | `Config` key | Default
181
- | `ELASTIC_APM_CAPTURE_BODY` | `capture_body` | `true`
180
+ | Environment | `Config` key | Default | Example |
181
+ | `ELASTIC_APM_CAPTURE_BODY` | `capture_body` | `"off"` | `"all"`
182
182
  |============
183
183
 
184
- Whether or not to attach the request body to transactions and errors.
184
+ For transactions that are HTTP requests,
185
+ the Ruby agent can optionally capture the request body (e.g. `POST` variables or JSON data).
186
+
187
+ Possible values: `"errors"`, `"transactions"`, `"all"`, `"off"`.
188
+
189
+ If the request has a body and this setting is disabled, the body will be shown as `[SKIPPED]`.
190
+
191
+ WARNING: request bodies often contain sensitive values like passwords, credit card numbers etc.
192
+ We try to strip sensitive looking data from form bodies but don't touch text bodies like JSON.
193
+ If your service handles data like this, we advise to only enable this feature with care.
194
+
185
195
 
186
196
  [float]
187
197
  [[config-capture-headers]]
@@ -442,6 +452,28 @@ This makes sure the agent doesn't block the main thread any more than necessary.
442
452
  If you have high load and get warnings about the buffer being full, increasing
443
453
  the worker pool size might help.
444
454
 
455
+ [float]
456
+ [[config-proxy-address]]
457
+ ==== `proxy_address`
458
+
459
+ [options="header"]
460
+ |============
461
+ | Environment | `Config` key | Default | Example
462
+ | N/A | `proxy_address` | `nil` | `"example.com"`
463
+ |============
464
+
465
+ An address to use as a proxy for the HTTP client.
466
+
467
+ Options available are:
468
+
469
+ - `proxy_address`
470
+ - `proxy_headers`
471
+ - `proxy_password`
472
+ - `proxy_port`
473
+ - `proxy_username`
474
+
475
+ See https://github.com/httprb/http/wiki/Proxy-Support[Http.rb's docs].
476
+
445
477
  [float]
446
478
  [[config-service-name]]
447
479
  ==== `service_name`
@@ -285,8 +285,17 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
285
285
  #
286
286
  # @param rack_env [Rack::Env] A Rack env
287
287
  # @return [Context] The built context
288
- def build_context(rack_env)
289
- agent&.build_context(rack_env)
288
+ def build_context(
289
+ deprecated_env = nil,
290
+ rack_env: nil,
291
+ for_type: :transaction
292
+ )
293
+ if !rack_env && (rack_env = deprecated_env)
294
+ warn "[ElasticAPM] [DEPRECATED] `build_context' expects two keyword" \
295
+ "arguments, `rack_env:' and `for_type:'"
296
+ end
297
+
298
+ agent&.build_context(rack_env: rack_env, for_type: for_type)
290
299
  end
291
300
 
292
301
  ### Errors
@@ -294,18 +303,25 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
294
303
  # Report and exception to APM
295
304
  #
296
305
  # @param exception [Exception] The exception
306
+ # @param context [Context] An optional [Context]
297
307
  # @param handled [Boolean] Whether the exception was rescued
298
308
  # @return [Error] The generated [Error]
299
- def report(exception, handled: true)
300
- agent&.report(exception, handled: handled)
309
+ def report(exception, context: nil, handled: true)
310
+ agent&.report(exception, context: context, handled: handled)
301
311
  end
302
312
 
303
313
  # Report a custom string error message to APM
304
314
  #
305
315
  # @param message [String] The message
316
+ # @param context [Context] An optional [Context]
306
317
  # @return [Error] The generated [Error]
307
- def report_message(message, **attrs)
308
- agent&.report_message(message, backtrace: caller, **attrs)
318
+ def report_message(message, context: nil, **attrs)
319
+ agent&.report_message(
320
+ message,
321
+ context: context,
322
+ backtrace: caller,
323
+ **attrs
324
+ )
309
325
  end
310
326
 
311
327
  ### Context
@@ -169,25 +169,27 @@ module ElasticAPM
169
169
  instrumenter.set_user(user)
170
170
  end
171
171
 
172
- def build_context(rack_env)
173
- @context_builder.build(rack_env)
172
+ def build_context(rack_env:, for_type:)
173
+ @context_builder.build(rack_env: rack_env, for_type: for_type)
174
174
  end
175
175
 
176
176
  # errors
177
177
 
178
- def report(exception, handled: true)
178
+ def report(exception, context: nil, handled: true)
179
179
  return if config.filter_exception_types.include?(exception.class.to_s)
180
180
 
181
181
  error = @error_builder.build_exception(
182
182
  exception,
183
+ context: context,
183
184
  handled: handled
184
185
  )
185
186
  enqueue error
186
187
  end
187
188
 
188
- def report_message(message, backtrace: nil, **attrs)
189
+ def report_message(message, context: nil, backtrace: nil, **attrs)
189
190
  error = @error_builder.build_log(
190
191
  message,
192
+ context: context,
191
193
  backtrace: backtrace,
192
194
  **attrs
193
195
  )
@@ -23,7 +23,7 @@ module ElasticAPM
23
23
  api_buffer_size: 256,
24
24
  api_request_size: '750kb',
25
25
  api_request_time: '10s',
26
- capture_body: false,
26
+ capture_body: 'off',
27
27
  capture_headers: true,
28
28
  capture_env: true,
29
29
  current_user_email_method: :email,
@@ -64,7 +64,7 @@ module ElasticAPM
64
64
  'ELASTIC_APM_API_BUFFER_SIZE' => [:int, 'api_buffer_size'],
65
65
  'ELASTIC_APM_API_REQUEST_SIZE' => [:int, 'api_request_size'],
66
66
  'ELASTIC_APM_API_REQUEST_TIME' => 'api_request_time',
67
- 'ELASTIC_APM_CAPTURE_BODY' => [:bool, 'capture_body'],
67
+ 'ELASTIC_APM_CAPTURE_BODY' => 'capture_body',
68
68
  'ELASTIC_APM_CAPTURE_HEADERS' => [:bool, 'capture_headers'],
69
69
  'ELASTIC_APM_CAPTURE_ENV' => [:bool, 'capture_env'],
70
70
  'ELASTIC_APM_CUSTOM_KEY_FILTERS' => [:list, 'custom_key_filters'],
@@ -137,9 +137,8 @@ module ElasticAPM
137
137
  attr_accessor :api_buffer_size
138
138
  attr_accessor :api_request_size
139
139
  attr_accessor :api_request_time
140
- attr_accessor :capture_body
141
- attr_accessor :capture_headers
142
140
  attr_accessor :capture_env
141
+ attr_accessor :capture_headers
143
142
  attr_accessor :current_user_email_method
144
143
  attr_accessor :current_user_id_method
145
144
  attr_accessor :current_user_method
@@ -160,6 +159,11 @@ module ElasticAPM
160
159
  attr_accessor :logger
161
160
  attr_accessor :metrics_interval
162
161
  attr_accessor :pool_size
162
+ attr_accessor :proxy_address
163
+ attr_accessor :proxy_headers
164
+ attr_accessor :proxy_password
165
+ attr_accessor :proxy_port
166
+ attr_accessor :proxy_username
163
167
  attr_accessor :server_ca_cert
164
168
  attr_accessor :service_name
165
169
  attr_accessor :service_version
@@ -171,11 +175,14 @@ module ElasticAPM
171
175
  attr_accessor :transaction_sample_rate
172
176
  attr_accessor :verify_server_cert
173
177
 
178
+ attr_reader :capture_body
174
179
  attr_reader :custom_key_filters
175
180
  attr_reader :ignore_url_patterns
176
181
  attr_reader :span_frames_min_duration
177
182
  attr_reader :span_frames_min_duration_us
178
183
 
184
+ attr_writer :alert_logger
185
+
179
186
  attr_accessor :view_paths
180
187
  attr_accessor :root_path
181
188
 
@@ -296,6 +303,31 @@ module ElasticAPM
296
303
  metrics_interval != 0
297
304
  end
298
305
 
306
+ # rubocop:disable Metrics/MethodLength
307
+ def capture_body=(value)
308
+ if value =~ /(all|transactions|errors|off)/
309
+ @capture_body = value
310
+ return
311
+ end
312
+
313
+ case value
314
+ when true
315
+ alert_logger.warn "Boolean value for option `capture_body' has " \
316
+ "been deprecated. Setting to 'all'"
317
+ @capture_body = 'all'
318
+ when false
319
+ alert_logger.warn "Boolean value for option `capture_body' has " \
320
+ "been deprecated. Setting to 'off'"
321
+ @capture_body = 'off'
322
+ else
323
+ default = DEFAULTS[:capture_body]
324
+ alert_logger.warn "Unknown value `#{value}' for option "\
325
+ "`capture_body'. Defaulting to `#{default}'"
326
+ @capture_body = default
327
+ end
328
+ end
329
+ # rubocop:enable Metrics/MethodLength
330
+
299
331
  private
300
332
 
301
333
  def assign(options)
@@ -376,7 +408,7 @@ module ElasticAPM
376
408
  end
377
409
 
378
410
  def format_name(str)
379
- str.gsub('::', '_')
411
+ str && str.gsub('::', '_')
380
412
  end
381
413
 
382
414
  def normalize_durations
@@ -9,13 +9,25 @@ require 'elastic_apm/context/user'
9
9
  module ElasticAPM
10
10
  # @api private
11
11
  class Context
12
- attr_accessor :request, :response, :user
13
- attr_reader :custom, :tags
14
-
15
12
  def initialize(custom: {}, tags: {}, user: nil)
16
13
  @custom = custom
17
14
  @tags = tags
18
15
  @user = user || User.new
19
16
  end
17
+
18
+ attr_accessor :request
19
+ attr_accessor :response
20
+ attr_accessor :user
21
+ attr_reader :custom
22
+ attr_reader :tags
23
+
24
+ def empty?
25
+ return false if tags.any?
26
+ return false if custom.any?
27
+ return false if user.any?
28
+ return false if request || response
29
+
30
+ true
31
+ end
20
32
  end
21
33
  end
@@ -26,6 +26,10 @@ module ElasticAPM
26
26
  !id && !email && !username
27
27
  end
28
28
 
29
+ def any?
30
+ !empty?
31
+ end
32
+
29
33
  class << self
30
34
  private
31
35
 
@@ -12,16 +12,16 @@ module ElasticAPM
12
12
 
13
13
  attr_reader :config
14
14
 
15
- def build(rack_env)
16
- context = Context.new
17
- apply_to_request(context, rack_env)
18
- context
15
+ def build(rack_env:, for_type:)
16
+ Context.new.tap do |context|
17
+ apply_to_request(context, rack_env: rack_env, for_type: for_type)
18
+ end
19
19
  end
20
20
 
21
21
  private
22
22
 
23
23
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
24
- def apply_to_request(context, rack_env)
24
+ def apply_to_request(context, rack_env:, for_type:)
25
25
  req = rails_req?(rack_env) ? rack_env : Rack::Request.new(rack_env)
26
26
 
27
27
  context.request = Context::Request.new unless context.request
@@ -32,7 +32,7 @@ module ElasticAPM
32
32
  request.method = req.request_method
33
33
  request.url = Context::Request::Url.new(req)
34
34
 
35
- request.body = config.capture_body? ? get_body(req) : SKIPPED
35
+ request.body = should_capture_body?(for_type) ? get_body(req) : SKIPPED
36
36
 
37
37
  headers, env = get_headers_and_env(rack_env)
38
38
  request.headers = headers if config.capture_headers?
@@ -42,12 +42,20 @@ module ElasticAPM
42
42
  end
43
43
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
44
44
 
45
+ def should_capture_body?(for_type)
46
+ option = config.capture_body
47
+
48
+ return true if option == 'all'
49
+ return true if option == 'transactions' && for_type == :transaction
50
+ return true if option == 'errors' && for_type == :error
51
+
52
+ false
53
+ end
54
+
45
55
  def get_body(req)
46
56
  case req.media_type
47
- when 'application/x-www-form-urlencoded'
48
- req.POST
49
- when 'multipart/form-data'
50
- req.POST
57
+ when 'application/x-www-form-urlencoded', 'multipart/form-data'
58
+ req.POST.dup
51
59
  else
52
60
  body = req.body.read
53
61
  req.body.rewind
@@ -56,8 +64,7 @@ module ElasticAPM
56
64
  end
57
65
 
58
66
  def rails_req?(env)
59
- defined?(ActionDispatch::Request) &&
60
- env.is_a?(ActionDispatch::Request)
67
+ defined?(ActionDispatch::Request) && env.is_a?(ActionDispatch::Request)
61
68
  end
62
69
 
63
70
  def get_headers_and_env(rack_env)
@@ -8,17 +8,11 @@ require 'elastic_apm/error/log'
8
8
  module ElasticAPM
9
9
  # @api private
10
10
  class Error
11
- def initialize(culprit: nil)
11
+ def initialize(culprit: nil, context: nil)
12
12
  @id = SecureRandom.hex(16)
13
- @trace_id = nil
14
13
  @culprit = culprit
15
-
16
14
  @timestamp = Util.micros
17
- @context = Context.new
18
-
19
- @transaction_id = nil
20
- @transaction = nil
21
- @parent_id = nil
15
+ @context = context
22
16
  end
23
17
 
24
18
  attr_accessor :id, :culprit, :exception, :log, :transaction_id,
@@ -7,37 +7,28 @@ module ElasticAPM
7
7
  @agent = agent
8
8
  end
9
9
 
10
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
11
- def build_exception(exception, handled: true)
12
- error = Error.new
10
+ def build_exception(exception, context: nil, handled: true)
11
+ error = Error.new context: context || Context.new
13
12
  error.exception = Error::Exception.new(exception, handled: handled)
14
13
 
15
14
  if exception.backtrace
16
15
  add_stacktrace error, :exception, exception.backtrace
17
16
  end
18
17
 
19
- add_current_transaction_fields error
20
-
21
- if (transaction = ElasticAPM.current_transaction)
22
- error.context = transaction.context.dup
23
- error.trace_id = transaction.trace_id
24
- error.transaction_id = transaction.id
25
- error.parent_id = ElasticAPM.current_span&.id || transaction.id
26
- end
18
+ add_current_transaction_fields error, ElasticAPM.current_transaction
27
19
 
28
20
  error
29
21
  end
30
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
31
22
 
32
- def build_log(message, backtrace: nil, **attrs)
33
- error = Error.new
23
+ def build_log(message, context: nil, backtrace: nil, **attrs)
24
+ error = Error.new context: context || Context.new
34
25
  error.log = Error::Log.new(message, **attrs)
35
26
 
36
27
  if backtrace
37
28
  add_stacktrace error, :log, backtrace
38
29
  end
39
30
 
40
- add_current_transaction_fields error
31
+ add_current_transaction_fields error, ElasticAPM.current_transaction
41
32
 
42
33
  error
43
34
  end
@@ -59,10 +50,20 @@ module ElasticAPM
59
50
  error.culprit = stacktrace.frames.first.function
60
51
  end
61
52
 
62
- def add_current_transaction_fields(error)
63
- return unless (transaction = ElasticAPM.current_transaction)
53
+ # rubocop:disable Metrics/AbcSize
54
+ def add_current_transaction_fields(error, transaction)
55
+ return unless transaction
56
+
64
57
  error.transaction_id = transaction.id
65
58
  error.transaction = { sampled: transaction.sampled? }
59
+ error.trace_id = transaction.trace_id
60
+ error.parent_id = ElasticAPM.current_span&.id || transaction.id
61
+
62
+ return unless transaction.context
63
+
64
+ Util.reverse_merge!(error.context.tags, transaction.context.tags)
65
+ Util.reverse_merge!(error.context.custom, transaction.context.custom)
66
66
  end
67
+ # rubocop:enable Metrics/AbcSize
67
68
  end
68
69
  end
@@ -198,6 +198,8 @@ module ElasticAPM
198
198
  attr_reader :total, :available, :page_size
199
199
 
200
200
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
201
+ # rubocop:disable Metrics/PerceivedComplexity
202
+ # rubocop:disable Metrics/CyclomaticComplexity
201
203
  def read!
202
204
  # rubocop:disable Style/RescueModifier
203
205
  @page_size = `getconf PAGESIZE`.chomp.to_i rescue 4096
@@ -211,16 +213,25 @@ module ElasticAPM
211
213
  hsh[:total] = line.split[1].to_i * 1024
212
214
  elsif line.start_with?('MemAvailable:')
213
215
  hsh[:available] = line.split[1].to_i * 1024
216
+ elsif line.start_with?('MemFree:')
217
+ hsh[:free] = line.split[1].to_i * 1024
218
+ elsif line.start_with?('Buffers:')
219
+ hsh[:buffers] = line.split[1].to_i * 1024
220
+ elsif line.start_with?('Cached:')
221
+ hsh[:cached] = line.split[1].to_i * 1024
214
222
  end
215
223
 
216
- break hsh if hsh.length == 2
224
+ break hsh if hsh[:total] && hsh[:available]
217
225
  end
218
226
 
219
227
  @total = info[:total]
220
- @available = info[:available]
228
+ @available =
229
+ info[:available] || info[:free] + info[:buffers] + info[:cached]
221
230
 
222
231
  self
223
232
  end
233
+ # rubocop:enable Metrics/CyclomaticComplexity
234
+ # rubocop:enable Metrics/PerceivedComplexity
224
235
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
225
236
  end
226
237
  end
@@ -10,7 +10,7 @@ module ElasticAPM
10
10
  @app = app
11
11
  end
12
12
 
13
- # rubocop:disable Metrics/MethodLength
13
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
14
14
  def call(env)
15
15
  begin
16
16
  if running? && !path_ignored?(env)
@@ -21,12 +21,13 @@ module ElasticAPM
21
21
  rescue InternalError
22
22
  raise # Don't report ElasticAPM errors
23
23
  rescue ::Exception => e
24
- ElasticAPM.report(e, handled: false)
24
+ context = ElasticAPM.build_context(rack_env: env, for_type: :error)
25
+ ElasticAPM.report(e, context: context, handled: false)
25
26
  raise
26
27
  ensure
27
28
  if resp && transaction
28
29
  status, headers, _body = resp
29
- transaction.add_response(status, headers: headers)
30
+ transaction.add_response(status, headers: headers.dup)
30
31
  end
31
32
 
32
33
  ElasticAPM.end_transaction http_result(status)
@@ -34,7 +35,7 @@ module ElasticAPM
34
35
 
35
36
  resp
36
37
  end
37
- # rubocop:enable Metrics/MethodLength
38
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
38
39
 
39
40
  private
40
41
 
@@ -49,8 +50,10 @@ module ElasticAPM
49
50
  end
50
51
 
51
52
  def start_transaction(env)
53
+ context = ElasticAPM.build_context(rack_env: env, for_type: :transaction)
54
+
52
55
  ElasticAPM.start_transaction 'Rack', 'request',
53
- context: ElasticAPM.build_context(env),
56
+ context: context,
54
57
  trace_context: trace_context(env)
55
58
  end
56
59
 
@@ -17,22 +17,46 @@ module ElasticAPM
17
17
  end
18
18
  end
19
19
 
20
- begin
21
- agent = ElasticAPM.start config
22
-
23
- if agent
24
- agent.instrumenter.subscriber = ElasticAPM::Subscriber.new(agent)
25
-
26
- app.middleware.insert 0, Middleware
27
- end
28
- rescue StandardError => e
29
- config.alert_logger.error format('Failed to start: %s', e.message)
30
- config.alert_logger.debug "Backtrace:\n" + e.backtrace.join("\n")
20
+ if start(config)
21
+ app.middleware.insert 0, Middleware
31
22
  end
32
23
  end
33
24
 
34
25
  config.after_initialize do
35
26
  require 'elastic_apm/spies/action_dispatch'
36
27
  end
28
+
29
+ private
30
+
31
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
32
+ def start(config)
33
+ if (reason = should_skip?(config))
34
+ config.alert_logger.info "Skipping because: #{reason}. " \
35
+ "Start manually with `ElasticAPM.start'"
36
+ return
37
+ end
38
+
39
+ ElasticAPM.start(config).tap do |agent|
40
+ attach_subscriber(agent)
41
+ end
42
+ rescue StandardError => e
43
+ config.alert_logger.error format('Failed to start: %s', e.message)
44
+ config.alert_logger.debug "Backtrace:\n" + e.backtrace.join("\n")
45
+ end
46
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
47
+
48
+ def should_skip?(_config)
49
+ if Rails.const_defined? :Console
50
+ return 'Rails console'
51
+ end
52
+
53
+ nil
54
+ end
55
+
56
+ def attach_subscriber(agent)
57
+ return unless agent
58
+
59
+ agent.instrumenter.subscriber = ElasticAPM::Subscriber.new(agent)
60
+ end
37
61
  end
38
62
  end
@@ -10,7 +10,9 @@ module ElasticAPM
10
10
  alias render_exception_without_apm render_exception
11
11
 
12
12
  def render_exception(env, exception)
13
- ElasticAPM.report(exception)
13
+ context = ElasticAPM.build_context(rack_env: env, for_type: :error)
14
+ ElasticAPM.report(exception, context: context, handled: false)
15
+
14
16
  render_exception_without_apm env, exception
15
17
  end
16
18
  end
@@ -6,6 +6,8 @@ module ElasticAPM
6
6
  # @api private
7
7
  class FaradaySpy
8
8
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
9
+ # rubocop:disable Metrics/BlockLength, Metrics/PerceivedComplexity
10
+ # rubocop:disable Metrics/CyclomaticComplexity
9
11
  def install
10
12
  ::Faraday::Connection.class_eval do
11
13
  alias run_request_without_apm run_request
@@ -43,6 +45,8 @@ module ElasticAPM
43
45
  end
44
46
  end
45
47
  end
48
+ # rubocop:enable Metrics/CyclomaticComplexity
49
+ # rubocop:enable Metrics/BlockLength, Metrics/PerceivedComplexity
46
50
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
47
51
  end
48
52
 
@@ -28,7 +28,7 @@ module ElasticAPM
28
28
  }.freeze
29
29
  GZIP_HEADERS = HEADERS.merge('Content-Encoding' => 'gzip').freeze
30
30
 
31
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
31
+ # rubocop:disable Metrics/MethodLength
32
32
  def initialize(config, metadata)
33
33
  @config = config
34
34
  @metadata = metadata.to_json
@@ -42,16 +42,36 @@ module ElasticAPM
42
42
  headers['Authorization'] = "Bearer #{token}"
43
43
  end
44
44
 
45
- if config.use_ssl? && config.server_ca_cert
46
- @ssl_context = OpenSSL::SSL::SSLContext.new
47
- @ssl_context.ca_file = config.server_ca_cert
48
- end
49
-
50
45
  @client = HTTP.headers(headers).persistent(@url)
51
46
 
47
+ configure_proxy
48
+ configure_ssl
49
+
52
50
  @mutex = Mutex.new
53
51
  end
54
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
52
+ # rubocop:enable Metrics/MethodLength
53
+
54
+ def configure_proxy
55
+ unless @config.proxy_address && @config.proxy_port
56
+ return
57
+ end
58
+
59
+ @client = @client.via(
60
+ @config.proxy_address,
61
+ @config.proxy_port,
62
+ @config.proxy_username,
63
+ @config.proxy_password,
64
+ @config.proxy_headers
65
+ )
66
+ end
67
+
68
+ def configure_ssl
69
+ return unless @config.use_ssl? && @config.server_ca_cert
70
+
71
+ @ssl_context = OpenSSL::SSL::SSLContext.new.tap do |context|
72
+ context.ca_file = @config.server_ca_cert
73
+ end
74
+ end
55
75
 
56
76
  def write(str)
57
77
  return if @config.disable_send
@@ -6,6 +6,8 @@ module ElasticAPM
6
6
  # @api private
7
7
  class ContextSerializer < Serializer
8
8
  def build(context)
9
+ return nil if context.nil? || context.empty?
10
+
9
11
  {
10
12
  custom: context.custom,
11
13
  tags: keyword_object(context.tags),
@@ -9,7 +9,7 @@ module ElasticAPM
9
9
  @context_serializer ||= ContextSerializer.new(config)
10
10
  end
11
11
 
12
- # rubocop:disable Metrics/MethodLength
12
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
13
13
  def build(error)
14
14
  base = {
15
15
  id: error.id,
@@ -19,10 +19,13 @@ module ElasticAPM
19
19
  parent_id: error.parent_id,
20
20
 
21
21
  culprit: error.culprit,
22
- timestamp: error.timestamp,
23
- context: context_serializer.build(error.context)
22
+ timestamp: error.timestamp
24
23
  }
25
24
 
25
+ if (context = context_serializer.build(error.context))
26
+ base[:context] = context
27
+ end
28
+
26
29
  if (exception = error.exception)
27
30
  base[:exception] = build_exception exception
28
31
  end
@@ -33,7 +36,7 @@ module ElasticAPM
33
36
 
34
37
  { error: base }
35
38
  end
36
- # rubocop:enable Metrics/MethodLength
39
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
37
40
 
38
41
  private
39
42
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElasticAPM
4
- VERSION = '2.5.0'
4
+ VERSION = '2.6.0'
5
5
  end
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.5.0
4
+ version: 2.6.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-03-01 00:00:00.000000000 Z
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -182,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
182
  - !ruby/object:Gem::Version
183
183
  version: '0'
184
184
  requirements: []
185
- rubygems_version: 3.0.1
185
+ rubygems_version: 3.0.3
186
186
  signing_key:
187
187
  specification_version: 4
188
188
  summary: The official Elastic APM agent for Ruby