elastic-apm 3.8.0 → 3.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.asciidoc +72 -0
  3. data/Gemfile +2 -3
  4. data/docs/configuration.asciidoc +1 -0
  5. data/docs/debugging.asciidoc +14 -0
  6. data/docs/supported-technologies.asciidoc +2 -1
  7. data/lib/elastic_apm/config.rb +32 -5
  8. data/lib/elastic_apm/config/options.rb +2 -1
  9. data/lib/elastic_apm/config/round_float.rb +31 -0
  10. data/lib/elastic_apm/config/wildcard_pattern_list.rb +13 -1
  11. data/lib/elastic_apm/context_builder.rb +1 -1
  12. data/lib/elastic_apm/instrumenter.rb +10 -3
  13. data/lib/elastic_apm/metadata.rb +3 -1
  14. data/lib/elastic_apm/metadata/cloud_info.rb +128 -0
  15. data/lib/elastic_apm/metadata/system_info.rb +5 -3
  16. data/lib/elastic_apm/metadata/system_info/container_info.rb +28 -4
  17. data/lib/elastic_apm/middleware.rb +8 -2
  18. data/lib/elastic_apm/span.rb +7 -3
  19. data/lib/elastic_apm/spies/delayed_job.rb +4 -2
  20. data/lib/elastic_apm/spies/dynamo_db.rb +58 -0
  21. data/lib/elastic_apm/spies/elasticsearch.rb +11 -1
  22. data/lib/elastic_apm/trace_context.rb +1 -1
  23. data/lib/elastic_apm/trace_context/traceparent.rb +2 -4
  24. data/lib/elastic_apm/trace_context/tracestate.rb +112 -9
  25. data/lib/elastic_apm/transaction.rb +26 -5
  26. data/lib/elastic_apm/transport/connection.rb +1 -0
  27. data/lib/elastic_apm/transport/filters/hash_sanitizer.rb +9 -16
  28. data/lib/elastic_apm/transport/filters/secrets_filter.rb +8 -6
  29. data/lib/elastic_apm/transport/serializers.rb +8 -6
  30. data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +43 -3
  31. data/lib/elastic_apm/transport/serializers/span_serializer.rb +2 -1
  32. data/lib/elastic_apm/transport/serializers/transaction_serializer.rb +1 -0
  33. data/lib/elastic_apm/transport/user_agent.rb +3 -3
  34. data/lib/elastic_apm/transport/worker.rb +5 -0
  35. data/lib/elastic_apm/util.rb +2 -0
  36. data/lib/elastic_apm/util/precision_validator.rb +46 -0
  37. data/lib/elastic_apm/version.rb +1 -1
  38. metadata +6 -2
@@ -47,6 +47,7 @@ module ElasticAPM
47
47
  end
48
48
 
49
49
  attr_reader :http
50
+
50
51
  def write(str)
51
52
  return false if @config.disable_send
52
53
 
@@ -23,29 +23,22 @@ module ElasticAPM
23
23
  class HashSanitizer
24
24
  FILTERED = '[FILTERED]'
25
25
 
26
- KEY_FILTERS = [
27
- /passw(or)?d/i,
28
- /auth/i,
29
- /^pw$/,
30
- /secret/i,
31
- /token/i,
32
- /api[-._]?key/i,
33
- /session[-._]?id/i,
34
- /(set[-_])?cookie/i
35
- ].freeze
26
+ # DEPRECATED: Remove these additions in next major version
27
+ LEGACY_KEY_FILTERS = [/cookie/i, /auth/i].freeze
36
28
 
29
+ # DEPRECATED: Remove this check in next major version
37
30
  VALUE_FILTERS = [
38
31
  # (probably) credit card number
39
32
  /^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/
40
33
  ].freeze
41
34
 
42
- attr_accessor :key_filters
43
-
44
- def initialize
45
- @key_filters = KEY_FILTERS
35
+ def initialize(key_patterns:)
36
+ @key_patterns = key_patterns + LEGACY_KEY_FILTERS
46
37
  end
47
38
 
48
- def strip_from!(obj, key_filters = KEY_FILTERS)
39
+ attr_accessor :key_patterns
40
+
41
+ def strip_from!(obj)
49
42
  return unless obj&.is_a?(Hash)
50
43
 
51
44
  obj.each do |k, v|
@@ -65,7 +58,7 @@ module ElasticAPM
65
58
  end
66
59
 
67
60
  def filter_key?(key)
68
- @key_filters.any? { |regex| regex.match(key) }
61
+ @key_patterns.any? { |regex| regex.match(key) }
69
62
  end
70
63
 
71
64
  def filter_value?(value)
@@ -26,19 +26,21 @@ module ElasticAPM
26
26
  class SecretsFilter
27
27
  def initialize(config)
28
28
  @config = config
29
- @sanitizer = HashSanitizer.new
30
- @sanitizer.key_filters += config.custom_key_filters +
31
- config.sanitize_field_names
29
+ @sanitizer =
30
+ HashSanitizer.new(
31
+ key_patterns: config.custom_key_filters + config.sanitize_field_names
32
+ )
32
33
  end
33
34
 
34
35
  def call(payload)
35
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :headers)
36
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :env)
36
+ @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :body)
37
37
  @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :cookies)
38
+ @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :env)
39
+ @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :headers)
38
40
  @sanitizer.strip_from! payload.dig(:transaction, :context, :response, :headers)
41
+ @sanitizer.strip_from! payload.dig(:error, :context, :request, :cookies)
39
42
  @sanitizer.strip_from! payload.dig(:error, :context, :request, :headers)
40
43
  @sanitizer.strip_from! payload.dig(:error, :context, :response, :headers)
41
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :body)
42
44
 
43
45
  payload
44
46
  end
@@ -45,18 +45,20 @@ module ElasticAPM
45
45
  def keyword_object(hash)
46
46
  return unless hash
47
47
 
48
- hash.tap do |h|
49
- h.each { |k, v| hash[k] = keyword_field(v) }
48
+ hash.each do |k, v|
49
+ hash[k] =
50
+ case v
51
+ when Hash then keyword_object(v)
52
+ else keyword_field(v)
53
+ end
50
54
  end
51
55
  end
52
56
 
53
57
  def mixed_object(hash)
54
58
  return unless hash
55
59
 
56
- hash.tap do |h|
57
- h.each do |k, v|
58
- hash[k] = v.is_a?(String) ? keyword_field(v) : v
59
- end
60
+ hash.each do |k, v|
61
+ hash[k] = v.is_a?(String) ? keyword_field(v) : v
60
62
  end
61
63
  end
62
64
  end
@@ -23,14 +23,19 @@ module ElasticAPM
23
23
  # @api private
24
24
  class MetadataSerializer < Serializer
25
25
  def build(metadata)
26
- {
27
- metadata: {
26
+ base =
27
+ {
28
28
  service: build_service(metadata.service),
29
29
  process: build_process(metadata.process),
30
30
  system: build_system(metadata.system),
31
31
  labels: build_labels(metadata.labels)
32
32
  }
33
- }
33
+
34
+ if (metadata.cloud.provider)
35
+ base[:cloud] = build_cloud(metadata.cloud)
36
+ end
37
+
38
+ { metadata: base }
34
39
  end
35
40
 
36
41
  private
@@ -83,9 +88,44 @@ module ElasticAPM
83
88
  }
84
89
  end
85
90
 
91
+ def build_cloud(cloud)
92
+ strip_nulls!(
93
+ provider: cloud.provider,
94
+ account: {
95
+ id: keyword_field(cloud.account_id),
96
+ name: keyword_field(cloud.account_name),
97
+ },
98
+ availability_zone: keyword_field(cloud.availability_zone),
99
+ instance: {
100
+ id: keyword_field(cloud.instance_id),
101
+ name: keyword_field(cloud.instance_name),
102
+ },
103
+ machine: { type: keyword_field(cloud.machine_type) },
104
+ project: {
105
+ id: keyword_field(cloud.project_id),
106
+ name: keyword_field(cloud.project_name),
107
+ },
108
+ region: keyword_field(cloud.region)
109
+ )
110
+ end
111
+
86
112
  def build_labels(labels)
87
113
  keyword_object(labels)
88
114
  end
115
+
116
+ # A bug in APM Server 7.9 disallows null values in `cloud`
117
+ def strip_nulls!(hash)
118
+ hash.keys.each do |key|
119
+ case value = hash[key]
120
+ when Hash
121
+ strip_nulls!(value)
122
+ hash.delete(key) if value.empty?
123
+ when nil then hash.delete(key)
124
+ end
125
+ end
126
+
127
+ hash
128
+ end
89
129
  end
90
130
  end
91
131
  end
@@ -42,7 +42,8 @@ module ElasticAPM
42
42
  context: context_serializer.build(span.context),
43
43
  stacktrace: span.stacktrace.to_a,
44
44
  timestamp: span.timestamp,
45
- trace_id: span.trace_id
45
+ trace_id: span.trace_id,
46
+ sample_rate: span.sample_rate
46
47
  }
47
48
  }
48
49
  end
@@ -38,6 +38,7 @@ module ElasticAPM
38
38
  duration: ms(transaction.duration),
39
39
  timestamp: transaction.timestamp,
40
40
  sampled: transaction.sampled?,
41
+ sample_rate: transaction.sample_rate,
41
42
  context: context_serializer.build(transaction.context),
42
43
  span_count: {
43
44
  started: transaction.started_spans,
@@ -32,14 +32,14 @@ module ElasticAPM
32
32
  private
33
33
 
34
34
  def build(config)
35
- metadata = Metadata.new(config)
35
+ service = Metadata::ServiceInfo.new(config)
36
36
 
37
37
  [
38
38
  "elastic-apm-ruby/#{VERSION}",
39
39
  HTTP::Request::USER_AGENT,
40
40
  [
41
- metadata.service.runtime.name,
42
- metadata.service.runtime.version
41
+ service.runtime.name,
42
+ service.runtime.version
43
43
  ].join('/')
44
44
  ].join(' ')
45
45
  end
@@ -53,6 +53,7 @@ module ElasticAPM
53
53
  end
54
54
 
55
55
  attr_reader :queue, :filters, :name, :connection, :serializers
56
+
56
57
  def work_forever
57
58
  while (msg = queue.pop)
58
59
  case msg
@@ -77,6 +78,10 @@ module ElasticAPM
77
78
  private
78
79
 
79
80
  def serialize_and_filter(resource)
81
+ if resource.respond_to?(:prepare_for_serialization!)
82
+ resource.prepare_for_serialization!
83
+ end
84
+
80
85
  serialized = serializers.serialize(resource)
81
86
 
82
87
  # if a filter returns nil, it means skip the event
@@ -46,6 +46,8 @@ module ElasticAPM
46
46
 
47
47
  def self.truncate(value, max_length: 1024)
48
48
  return unless value
49
+
50
+ value = String(value)
49
51
  return value if value.length <= max_length
50
52
 
51
53
  value[0...(max_length - 1)] + '…'
@@ -0,0 +1,46 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module ElasticAPM
21
+ module Util
22
+ # @api private
23
+ # Rounds half away from zero.
24
+ # If `minimum` is provided, and the value rounds to 0 (but was not zero to
25
+ # begin with), use the minimum instead.
26
+ module PrecisionValidator
27
+ extend self
28
+
29
+ def validate(value, precision: 0, minimum: nil)
30
+ float = Float(value)
31
+ return nil unless (0.0..1.0).cover?(float)
32
+ return float if float == 0
33
+
34
+ multiplier = Float(10**precision)
35
+ rounded = (float * multiplier + 0.5).floor / multiplier
36
+ if rounded == 0 && minimum
37
+ minimum
38
+ else
39
+ rounded
40
+ end
41
+ rescue ArgumentError
42
+ nil
43
+ end
44
+ end
45
+ end
46
+ end
@@ -18,5 +18,5 @@
18
18
  # frozen_string_literal: true
19
19
 
20
20
  module ElasticAPM
21
- VERSION = '3.8.0'
21
+ VERSION = '3.11.1'
22
22
  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: 3.8.0
4
+ version: 3.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikkel Malmberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-18 00:00:00.000000000 Z
11
+ date: 2020-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -128,6 +128,7 @@ files:
128
128
  - lib/elastic_apm/config/duration.rb
129
129
  - lib/elastic_apm/config/options.rb
130
130
  - lib/elastic_apm/config/regexp_list.rb
131
+ - lib/elastic_apm/config/round_float.rb
131
132
  - lib/elastic_apm/config/wildcard_pattern_list.rb
132
133
  - lib/elastic_apm/context.rb
133
134
  - lib/elastic_apm/context/request.rb
@@ -148,6 +149,7 @@ files:
148
149
  - lib/elastic_apm/internal_error.rb
149
150
  - lib/elastic_apm/logging.rb
150
151
  - lib/elastic_apm/metadata.rb
152
+ - lib/elastic_apm/metadata/cloud_info.rb
151
153
  - lib/elastic_apm/metadata/process_info.rb
152
154
  - lib/elastic_apm/metadata/service_info.rb
153
155
  - lib/elastic_apm/metadata/system_info.rb
@@ -185,6 +187,7 @@ files:
185
187
  - lib/elastic_apm/spies.rb
186
188
  - lib/elastic_apm/spies/action_dispatch.rb
187
189
  - lib/elastic_apm/spies/delayed_job.rb
190
+ - lib/elastic_apm/spies/dynamo_db.rb
188
191
  - lib/elastic_apm/spies/elasticsearch.rb
189
192
  - lib/elastic_apm/spies/faraday.rb
190
193
  - lib/elastic_apm/spies/http.rb
@@ -234,6 +237,7 @@ files:
234
237
  - lib/elastic_apm/util.rb
235
238
  - lib/elastic_apm/util/inflector.rb
236
239
  - lib/elastic_apm/util/lru_cache.rb
240
+ - lib/elastic_apm/util/precision_validator.rb
237
241
  - lib/elastic_apm/util/throttle.rb
238
242
  - lib/elastic_apm/version.rb
239
243
  homepage: https://github.com/elastic/apm-agent-ruby