atatus 1.7.0 → 2.0.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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile +49 -13
  4. data/LICENSE +1 -1
  5. data/atatus.gemspec +3 -3
  6. data/lib/atatus/agent.rb +10 -7
  7. data/lib/atatus/central_config.rb +19 -8
  8. data/lib/atatus/collector/layer.rb +1 -1
  9. data/lib/atatus/{sql_summarizer.rb → config/log_level_map.rb} +22 -28
  10. data/lib/atatus/config/options.rb +2 -1
  11. data/lib/atatus/config/regexp_list.rb +1 -1
  12. data/lib/atatus/config/round_float.rb +31 -0
  13. data/lib/atatus/config/server_info.rb +50 -0
  14. data/lib/atatus/config/wildcard_pattern_list.rb +3 -1
  15. data/lib/atatus/config.rb +91 -70
  16. data/lib/atatus/context/request/socket.rb +1 -2
  17. data/lib/atatus/context/response.rb +1 -3
  18. data/lib/atatus/context.rb +3 -10
  19. data/lib/atatus/context_builder.rb +3 -3
  20. data/lib/atatus/error.rb +2 -1
  21. data/lib/atatus/error_builder.rb +1 -1
  22. data/lib/atatus/fields.rb +98 -0
  23. data/lib/atatus/graphql.rb +2 -0
  24. data/lib/atatus/grpc.rb +5 -7
  25. data/lib/atatus/instrumenter.rb +29 -25
  26. data/lib/atatus/metadata/cloud_info.rb +156 -0
  27. data/lib/atatus/metadata/service_info.rb +3 -3
  28. data/lib/atatus/metadata/system_info/container_info.rb +20 -8
  29. data/lib/atatus/metadata/system_info.rb +20 -5
  30. data/lib/atatus/metadata.rb +3 -1
  31. data/lib/atatus/metrics/cpu_mem_set.rb +10 -38
  32. data/lib/atatus/metrics/jvm_set.rb +88 -0
  33. data/lib/atatus/metrics/metric.rb +2 -0
  34. data/lib/atatus/metrics.rb +33 -16
  35. data/lib/atatus/middleware.rb +8 -3
  36. data/lib/atatus/naively_hashable.rb +1 -0
  37. data/lib/atatus/normalizers/rails/active_record.rb +25 -7
  38. data/lib/atatus/normalizers.rb +2 -2
  39. data/lib/atatus/opentracing.rb +5 -3
  40. data/lib/atatus/rails.rb +1 -1
  41. data/lib/atatus/span/context/db.rb +1 -1
  42. data/lib/atatus/span/context/destination.rb +58 -32
  43. data/lib/atatus/span/context/http.rb +2 -0
  44. data/lib/atatus/span/context/links.rb +32 -0
  45. data/lib/atatus/{sql.rb → span/context/message.rb} +16 -12
  46. data/lib/atatus/span/context/service.rb +55 -0
  47. data/lib/atatus/span/context.rb +28 -3
  48. data/lib/atatus/span.rb +35 -5
  49. data/lib/atatus/span_helpers.rb +12 -23
  50. data/lib/atatus/spies/action_dispatch.rb +10 -13
  51. data/lib/atatus/spies/azure_storage_table.rb +148 -0
  52. data/lib/atatus/spies/delayed_job.rb +19 -13
  53. data/lib/atatus/spies/dynamo_db.rb +56 -15
  54. data/lib/atatus/spies/elasticsearch.rb +54 -39
  55. data/lib/atatus/spies/faraday.rb +92 -58
  56. data/lib/atatus/spies/http.rb +33 -37
  57. data/lib/atatus/spies/json.rb +5 -9
  58. data/lib/atatus/spies/mongo.rb +26 -19
  59. data/lib/atatus/spies/net_http.rb +53 -51
  60. data/lib/atatus/spies/racecar.rb +77 -0
  61. data/lib/atatus/spies/rake.rb +27 -27
  62. data/lib/atatus/spies/redis.rb +11 -12
  63. data/lib/atatus/spies/resque.rb +18 -23
  64. data/lib/atatus/spies/s3.rb +132 -0
  65. data/lib/atatus/spies/sequel.rb +11 -2
  66. data/lib/atatus/spies/shoryuken.rb +4 -6
  67. data/lib/atatus/spies/sidekiq.rb +23 -31
  68. data/lib/atatus/spies/sinatra.rb +20 -28
  69. data/lib/atatus/spies/sneakers.rb +2 -0
  70. data/lib/atatus/spies/sns.rb +126 -0
  71. data/lib/atatus/spies/sqs.rb +231 -0
  72. data/lib/atatus/spies/sucker_punch.rb +20 -22
  73. data/lib/atatus/spies/tilt.rb +10 -13
  74. data/lib/atatus/spies.rb +20 -0
  75. data/lib/atatus/sql/signature.rb +4 -2
  76. data/lib/atatus/sql/tokenizer.rb +23 -7
  77. data/lib/atatus/stacktrace/frame.rb +1 -0
  78. data/lib/atatus/stacktrace_builder.rb +12 -16
  79. data/lib/atatus/subscriber.rb +1 -0
  80. data/lib/atatus/trace_context/traceparent.rb +5 -8
  81. data/lib/atatus/trace_context/tracestate.rb +16 -14
  82. data/lib/atatus/trace_context.rb +6 -16
  83. data/lib/atatus/transaction.rb +17 -4
  84. data/lib/atatus/transport/base.rb +1 -3
  85. data/lib/atatus/transport/connection/http.rb +11 -3
  86. data/lib/atatus/transport/connection/proxy_pipe.rb +1 -2
  87. data/lib/atatus/transport/connection.rb +3 -2
  88. data/lib/atatus/transport/filters/hash_sanitizer.rb +16 -34
  89. data/lib/atatus/transport/filters/secrets_filter.rb +35 -12
  90. data/lib/atatus/transport/serializers/context_serializer.rb +1 -2
  91. data/lib/atatus/transport/serializers/metadata_serializer.rb +54 -8
  92. data/lib/atatus/transport/serializers/metricset_serializer.rb +2 -2
  93. data/lib/atatus/transport/serializers/span_serializer.rb +55 -9
  94. data/lib/atatus/transport/serializers/transaction_serializer.rb +1 -0
  95. data/lib/atatus/transport/serializers.rb +9 -6
  96. data/lib/atatus/transport/user_agent.rb +16 -9
  97. data/lib/atatus/transport/worker.rb +2 -1
  98. data/lib/atatus/util/deep_dup.rb +65 -0
  99. data/lib/atatus/util/precision_validator.rb +46 -0
  100. data/lib/atatus/util.rb +2 -0
  101. data/lib/atatus/version.rb +1 -1
  102. data/lib/atatus.rb +32 -5
  103. metadata +40 -11
@@ -69,7 +69,7 @@ module Atatus
69
69
  when '[' then scan_quoted_indentifier(']')
70
70
  when '(' then LPAREN
71
71
  when ')' then RPAREN
72
- when '/' then scan_bracketed_comment
72
+ when '/' then scan_bracketed_or_cql_comment
73
73
  when '-' then scan_simple_comment
74
74
  when "'" then scan_string_literal
75
75
  when ALPHA then scan_keyword_or_identifier(possible_keyword: true)
@@ -110,7 +110,7 @@ module Atatus
110
110
  next next_char
111
111
  end
112
112
 
113
- next next_char if peek =~ ALPHA
113
+ next next_char if ALPHA.match?(peek)
114
114
 
115
115
  break
116
116
  end
@@ -130,7 +130,7 @@ module Atatus
130
130
  end
131
131
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
132
132
 
133
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
133
+ # rubocop:disable Metrics/CyclomaticComplexity
134
134
  def scan_dollar_sign
135
135
  while (peek = peek_char)
136
136
  case peek
@@ -165,7 +165,7 @@ module Atatus
165
165
 
166
166
  OTHER
167
167
  end
168
- # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
168
+ # rubocop:enable Metrics/CyclomaticComplexity
169
169
 
170
170
  def scan_quoted_indentifier(delimiter)
171
171
  while (char = next_char)
@@ -185,10 +185,16 @@ module Atatus
185
185
  IDENT
186
186
  end
187
187
 
188
+ def scan_bracketed_or_cql_comment
189
+ case peek_char
190
+ when '*' then scan_bracketed_comment
191
+ when '/' then scan_cql_comment
192
+ else OTHER
193
+ end
194
+ end
195
+
188
196
  # rubocop:disable Metrics/CyclomaticComplexity
189
197
  def scan_bracketed_comment
190
- return OTHER unless peek_char == '*'
191
-
192
198
  nesting = 1
193
199
 
194
200
  while (char = next_char)
@@ -207,6 +213,16 @@ module Atatus
207
213
  end
208
214
  # rubocop:enable Metrics/CyclomaticComplexity
209
215
 
216
+ def scan_cql_comment
217
+ return OTHER unless peek_char == '/'
218
+
219
+ while (char = next_char)
220
+ break if char == "\n"
221
+ end
222
+
223
+ COMMENT
224
+ end
225
+
210
226
  def scan_simple_comment
211
227
  return OTHER unless peek_char == '-'
212
228
 
@@ -251,7 +267,7 @@ module Atatus
251
267
  when 'e', 'E'
252
268
  return NUMBER if exponent
253
269
  next_char
254
- next_char if peek_char =~ /[+-]/
270
+ next_char if /[+-]/.match?(peek_char)
255
271
  else break
256
272
  end
257
273
  end
@@ -38,6 +38,7 @@ module Atatus
38
38
  :module,
39
39
  :colno
40
40
  )
41
+
41
42
  def build_context(context_line_count)
42
43
  return unless abs_path && context_line_count > 0
43
44
 
@@ -23,7 +23,7 @@ require 'atatus/util/lru_cache'
23
23
  module Atatus
24
24
  # @api private
25
25
  class StacktraceBuilder
26
- JAVA_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
26
+ JAVA_FORMAT = /^(.+)\.([^.]+)\(([^:]+):(\d+)\)$/.freeze
27
27
  RUBY_FORMAT = /^(.+?):(\d+)(?::in `(.+?)')?$/.freeze
28
28
 
29
29
  RUBY_VERS_REGEX = %r{ruby(/gems)?[-/](\d+\.)+\d}.freeze
@@ -38,7 +38,9 @@ module Atatus
38
38
 
39
39
  def initialize(config)
40
40
  @config = config
41
- @cache = Util::LruCache.new(2048, &method(:build_frame))
41
+ @cache = Util::LruCache.new(2048) do |cache, frame|
42
+ build_frame(cache, frame)
43
+ end
42
44
  end
43
45
 
44
46
  attr_reader :config
@@ -59,7 +61,7 @@ module Atatus
59
61
 
60
62
  frame = Stacktrace::Frame.new
61
63
  frame.abs_path = abs_path
62
- frame.filename = strip_load_path(config, abs_path)
64
+ frame.filename = strip_load_path(abs_path)
63
65
  frame.function = function
64
66
  frame.lineno = lineno.to_i
65
67
  frame.library_frame = library_frame?(config, abs_path)
@@ -86,14 +88,13 @@ module Atatus
86
88
  [file, number, method, module_name]
87
89
  end
88
90
 
89
- # rubocop:disable Metrics/CyclomaticComplexity
90
91
  def library_frame?(config, abs_path)
91
92
  return false unless abs_path
92
93
 
93
94
  return true if abs_path.start_with?(GEMS_PATH)
94
95
 
95
96
  if abs_path.start_with?(config.__root_path)
96
- return true if abs_path.start_with?(config.__root_path + '/vendor')
97
+ return true if abs_path.start_with?("#{config.__root_path}/vendor")
97
98
  return false
98
99
  end
99
100
 
@@ -102,20 +103,15 @@ module Atatus
102
103
 
103
104
  false
104
105
  end
105
- # rubocop:enable Metrics/CyclomaticComplexity
106
106
 
107
- def strip_load_path(config, path)
107
+ def strip_load_path(path)
108
108
  return nil if path.nil?
109
109
 
110
- if path.start_with?(config.__root_path)
111
- prefix = config.__root_path
112
- else
113
- prefix =
114
- $LOAD_PATH
115
- .map(&:to_s)
116
- .select { |s| path.start_with?(s) }
117
- .max_by(&:length)
118
- end
110
+ prefix =
111
+ $LOAD_PATH
112
+ .map(&:to_s)
113
+ .select { |s| path.start_with?(s) }
114
+ .max_by(&:length)
119
115
 
120
116
  prefix ? path[prefix.chomp(File::SEPARATOR).length + 1..-1] : path
121
117
  end
@@ -45,6 +45,7 @@ module Atatus
45
45
  # AS::Notifications API
46
46
 
47
47
  Notification = Struct.new(:id, :span)
48
+
48
49
  def start(name, id, payload)
49
50
  return unless (transaction = @agent.current_transaction)
50
51
 
@@ -22,27 +22,24 @@ module Atatus
22
22
  # @api private
23
23
  class Traceparent
24
24
  VERSION = '00'
25
- HEX_REGEX = /[^[:xdigit:]]/.freeze
25
+ NON_HEX_REGEX = /[^[:xdigit:]]/.freeze
26
26
 
27
27
  TRACE_ID_LENGTH = 16
28
28
  ID_LENGTH = 8
29
29
 
30
- # rubocop:disable Metrics/ParameterLists
31
30
  def initialize(
32
31
  version: VERSION,
33
32
  trace_id: nil,
34
- span_id: nil,
33
+ parent_id: nil,
35
34
  id: nil,
36
35
  recorded: true
37
36
  )
38
37
  @version = version
39
38
  @trace_id = trace_id || hex(TRACE_ID_LENGTH)
40
- # TODO: rename span_id kw arg to parent_id with next major version bump
41
- @parent_id = span_id
39
+ @parent_id = parent_id
42
40
  @id = id || hex(ID_LENGTH)
43
41
  @recorded = recorded
44
42
  end
45
- # rubocop:enable Metrics/ParameterLists
46
43
 
47
44
  attr_accessor :version, :id, :trace_id, :parent_id, :recorded
48
45
 
@@ -58,8 +55,8 @@ module Atatus
58
55
  values[-1] = Util.hex_to_bits(values[-1])
59
56
  end
60
57
 
61
- raise_invalid(header) if HEX_REGEX =~ t.trace_id
62
- raise_invalid(header) if HEX_REGEX =~ t.parent_id
58
+ raise_invalid(header) if NON_HEX_REGEX.match?(t.trace_id)
59
+ raise_invalid(header) if NON_HEX_REGEX.match?(t.parent_id)
63
60
  end
64
61
  end
65
62
 
@@ -17,6 +17,8 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
+ require 'atatus/util/precision_validator'
21
+
20
22
  module Atatus
21
23
  class TraceContext
22
24
  # @api private
@@ -35,12 +37,13 @@ module Atatus
35
37
  end
36
38
  end
37
39
 
40
+ # @api private
38
41
  class EsEntry
39
42
  ASSIGN = ':'
40
43
  SPLIT = ';'
41
44
 
42
- SHORT_TO_LONG = { 's' => 'sample_rate' }
43
- LONG_TO_SHORT = { 'sample_rate' => 's' }
45
+ SHORT_TO_LONG = { 's' => 'sample_rate' }.freeze
46
+ LONG_TO_SHORT = { 'sample_rate' => 's' }.freeze
44
47
 
45
48
  def initialize(values = nil)
46
49
  parse(values)
@@ -63,13 +66,9 @@ module Atatus
63
66
  end
64
67
 
65
68
  def sample_rate=(val)
66
- float = Float(val).round(3)
67
-
68
- return nil unless (0.0..1.0).include?(float)
69
-
70
- @sample_rate = float
71
- rescue ArgumentError => e
72
- nil
69
+ @sample_rate = Util::PrecisionValidator.validate(
70
+ val, precision: 4, minimum: 0.0001
71
+ )
73
72
  end
74
73
 
75
74
  def to_s
@@ -85,7 +84,7 @@ module Atatus
85
84
 
86
85
  values.split(SPLIT).map do |kv|
87
86
  k, v = kv.split(ASSIGN)
88
- next unless SHORT_TO_LONG.keys.include?(k)
87
+ next unless SHORT_TO_LONG.key?(k)
89
88
  send("#{SHORT_TO_LONG[k]}=", v)
90
89
  end
91
90
  end
@@ -93,6 +92,8 @@ module Atatus
93
92
 
94
93
  extend Forwardable
95
94
 
95
+ ENTRY_SPLIT_REGEX = /\s*[\n,]+\s*/
96
+
96
97
  def initialize(entries: {}, sample_rate: nil)
97
98
  @entries = entries
98
99
 
@@ -108,7 +109,7 @@ module Atatus
108
109
  split_by_nl_and_comma(header)
109
110
  .each_with_object({}) do |entry, hsh|
110
111
  k, v = entry.split('=')
111
-
112
+ next unless k && v && !k.empty? && !v.empty?
112
113
  hsh[k] =
113
114
  case k
114
115
  when 'es' then EsEntry.new(v)
@@ -138,9 +139,10 @@ module Atatus
138
139
  def split_by_nl_and_comma(str)
139
140
  # HTTP allows multiple headers with the same name, eg. multiple
140
141
  # Set-Cookie headers per response.
141
- # Rack handles this by joining the headers under the same key, separated
142
- # by newlines, see https://www.rubydoc.info/github/rack/rack/file/SPEC
143
- String(str).split("\n").map { |s| s.split(',') }.flatten
142
+ # Rack handles this by joining the headers under the same key,
143
+ # separated by newlines.
144
+ # See https://www.rubydoc.info/github/rack/rack/file/SPEC
145
+ String(str).split(ENTRY_SPLIT_REGEX).flatten
144
146
  end
145
147
  end
146
148
  end
@@ -29,10 +29,9 @@ module Atatus
29
29
 
30
30
  def initialize(
31
31
  traceparent: nil,
32
- tracestate: nil,
33
- **legacy_traceparent_attrs
32
+ tracestate: nil
34
33
  )
35
- @traceparent = traceparent || Traceparent.new(**legacy_traceparent_attrs)
34
+ @traceparent = traceparent || Traceparent.new
36
35
  @tracestate = tracestate || Tracestate.new
37
36
  end
38
37
 
@@ -42,22 +41,18 @@ module Atatus
42
41
  :version, :trace_id, :id, :parent_id, :ensure_parent_id, :recorded?
43
42
 
44
43
  class << self
45
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
46
- def parse(legacy_header = nil, env: nil, metadata: nil)
47
- unless legacy_header || env || metadata
44
+ def parse(env: nil, metadata: nil)
45
+ unless env || metadata
48
46
  raise ArgumentError, 'TraceContext expects env:, metadata: ' \
49
47
  'or single argument header string'
50
48
  end
51
49
 
52
- if legacy_header
53
- legacy_parse_from_header(legacy_header)
54
- elsif env
50
+ if env
55
51
  trace_context_from_env(env)
56
52
  elsif metadata
57
53
  trace_context_from_metadata(metadata)
58
54
  end
59
55
  end
60
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
61
56
 
62
57
  private
63
58
 
@@ -90,11 +85,6 @@ module Atatus
90
85
 
91
86
  new(traceparent: parent, tracestate: state)
92
87
  end
93
-
94
- def legacy_parse_from_header(header)
95
- parent = Traceparent.parse(header)
96
- new(traceparent: parent)
97
- end
98
88
  end
99
89
 
100
90
  def child
@@ -106,7 +96,7 @@ module Atatus
106
96
  def apply_headers
107
97
  yield 'Traceparent', traceparent.to_header
108
98
 
109
- if tracestate
99
+ if tracestate && !tracestate.to_header.empty?
110
100
  yield 'Tracestate', tracestate.to_header
111
101
  end
112
102
 
@@ -20,6 +20,17 @@
20
20
  module Atatus
21
21
  # @api private
22
22
  class Transaction
23
+ # @api private
24
+ class Outcome
25
+ FAILURE = "failure"
26
+ SUCCESS = "success"
27
+ UNKNOWN = "unknown"
28
+
29
+ def self.from_http_status(code)
30
+ code.to_i >= 500 ? FAILURE : SUCCESS
31
+ end
32
+ end
33
+
23
34
  extend Forwardable
24
35
  include ChildDurations::Methods
25
36
 
@@ -33,10 +44,10 @@ module Atatus
33
44
  def initialize(
34
45
  name = nil,
35
46
  type = nil,
47
+ config:,
36
48
  sampled: true,
37
49
  sample_rate: 1,
38
50
  context: nil,
39
- config:,
40
51
  trace_context: nil
41
52
  )
42
53
  @name = name
@@ -63,7 +74,9 @@ module Atatus
63
74
  unless (@trace_context = trace_context)
64
75
  @trace_context = TraceContext.new(
65
76
  traceparent: TraceContext::Traceparent.new(recorded: sampled),
66
- tracestate: TraceContext::Tracestate.new(sample_rate: sampled ? sample_rate : 0)
77
+ tracestate: TraceContext::Tracestate.new(
78
+ sample_rate: sampled ? sample_rate : 0
79
+ )
67
80
  )
68
81
  end
69
82
 
@@ -74,7 +87,7 @@ module Atatus
74
87
  end
75
88
  # rubocop:enable Metrics/ParameterLists
76
89
 
77
- attr_accessor :name, :type, :result, :spans, :ruby_time
90
+ attr_accessor :name, :type, :result, :outcome, :spans, :ruby_time
78
91
 
79
92
  attr_reader(
80
93
  :breakdown_metrics,
@@ -90,7 +103,7 @@ module Atatus
90
103
  :started_spans,
91
104
  :timestamp,
92
105
  :trace_context,
93
- :transaction_max_spans
106
+ :transaction_max_spans
94
107
  )
95
108
 
96
109
  alias :collect_metrics? :collect_metrics
@@ -35,7 +35,6 @@ module Atatus
35
35
  include Logging
36
36
 
37
37
  WATCHER_EXECUTION_INTERVAL = 5
38
- WATCHER_TIMEOUT_INTERVAL = 4
39
38
  WORKER_JOIN_TIMEOUT = 5
40
39
 
41
40
  def initialize(config)
@@ -112,8 +111,7 @@ module Atatus
112
111
 
113
112
  def create_watcher
114
113
  @watcher = Concurrent::TimerTask.execute(
115
- execution_interval: WATCHER_EXECUTION_INTERVAL,
116
- timeout_interval: WATCHER_TIMEOUT_INTERVAL
114
+ execution_interval: WATCHER_EXECUTION_INTERVAL
117
115
  ) { ensure_worker_count }
118
116
  end
119
117
 
@@ -74,8 +74,16 @@ module Atatus
74
74
  debug '%s: Closing request with reason %s', thread_str, reason
75
75
  @closed.make_true
76
76
 
77
- @wr&.close(reason)
78
- return if @request.nil? || @request&.join(5)
77
+ @wr&.close
78
+
79
+ if @request&.join(5)
80
+ @rd&.close
81
+ return
82
+ end
83
+
84
+ @rd&.close
85
+
86
+ return if @request.nil?
79
87
 
80
88
  error(
81
89
  '%s: APM Server not responding in time, terminating request',
@@ -85,7 +93,7 @@ module Atatus
85
93
  end
86
94
 
87
95
  def closed?
88
- @closed.true?
96
+ @rd.closed? && @closed.true?
89
97
  end
90
98
 
91
99
  def inspect
@@ -62,8 +62,7 @@ module Atatus
62
62
  @io = Zlib::GzipWriter.new(io)
63
63
  end
64
64
 
65
- def close(reason = nil)
66
- debug("Closing writer with reason #{reason}")
65
+ def close
67
66
  io.close
68
67
  end
69
68
 
@@ -42,11 +42,12 @@ module Atatus
42
42
  Metadata.new(config)
43
43
  )
44
44
  )
45
- @url = config.server_url + '/intake/v2/events'
45
+ @url = "#{config.server_url}/intake/v2/events"
46
46
  @mutex = Mutex.new
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
 
@@ -104,7 +105,7 @@ module Atatus
104
105
  @close_task&.cancel
105
106
  @close_task =
106
107
  Concurrent::ScheduledTask.execute(@config.api_request_time) do
107
- flush(:timeout)
108
+ flush(:scheduled_flush)
108
109
  end
109
110
  end
110
111
  end
@@ -17,59 +17,41 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
+ require 'atatus/util/deep_dup'
21
+
20
22
  module Atatus
21
23
  module Transport
22
24
  module Filters
25
+ # @api private
23
26
  class HashSanitizer
24
27
  FILTERED = '[FILTERED]'
25
28
 
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
36
-
37
- VALUE_FILTERS = [
38
- # (probably) credit card number
39
- /^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/
40
- ].freeze
29
+ def initialize(key_patterns:)
30
+ @key_patterns = key_patterns
31
+ end
41
32
 
42
- attr_accessor :key_filters
33
+ attr_accessor :key_patterns
43
34
 
44
- def initialize
45
- @key_filters = KEY_FILTERS
35
+ def strip_from(obj)
36
+ strip_from!(Util::DeepDup.dup(obj))
46
37
  end
47
38
 
48
- def strip_from!(obj, key_filters = KEY_FILTERS)
49
- return unless obj&.is_a?(Hash)
50
-
51
- obj.each do |k, v|
52
- if filter_key?(k)
53
- next obj[k] = FILTERED
54
- end
39
+ def strip_from!(obj)
40
+ return unless obj.is_a?(Hash)
55
41
 
42
+ obj.each_pair do |k, v|
56
43
  case v
57
44
  when Hash
58
45
  strip_from!(v)
59
- when String
60
- if filter_value?(v)
61
- obj[k] = FILTERED
62
- end
46
+ else
47
+ next unless filter_key?(k)
48
+ obj[k] = FILTERED
63
49
  end
64
50
  end
65
51
  end
66
52
 
67
53
  def filter_key?(key)
68
- @key_filters.any? { |regex| regex.match(key) }
69
- end
70
-
71
- def filter_value?(value)
72
- VALUE_FILTERS.any? { |regex| regex.match(value) }
54
+ @key_patterns.any? { |regex| regex.match(key) }
73
55
  end
74
56
  end
75
57
  end
@@ -26,21 +26,44 @@ module Atatus
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 +
32
+ config.sanitize_field_names
33
+ )
32
34
  end
33
35
 
34
36
  def call(payload)
35
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :headers)
36
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :env)
37
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :cookies)
38
- @sanitizer.strip_from! payload.dig(:transaction, :context, :response, :headers)
39
- @sanitizer.strip_from! payload.dig(:error, :context, :request, :headers)
40
- @sanitizer.strip_from! payload.dig(:error, :context, :request, :cookies)
41
- @sanitizer.strip_from! payload.dig(:error, :context, :response, :headers)
42
- @sanitizer.strip_from! payload.dig(:transaction, :context, :request, :body)
43
-
37
+ @sanitizer.strip_from!(
38
+ payload.dig(:transaction, :context, :request, :body)
39
+ )
40
+ @sanitizer.strip_from!(
41
+ payload.dig(:transaction, :context, :request, :cookies)
42
+ )
43
+ @sanitizer.strip_from!(
44
+ payload.dig(:transaction, :context, :request, :env)
45
+ )
46
+ @sanitizer.strip_from!(
47
+ payload.dig(:transaction, :context, :request, :headers)
48
+ )
49
+ @sanitizer.strip_from!(
50
+ payload.dig(:transaction, :context, :response, :headers)
51
+ )
52
+ @sanitizer.strip_from!(
53
+ payload.dig(:error, :context, :request, :body)
54
+ )
55
+ @sanitizer.strip_from!(
56
+ payload.dig(:error, :context, :request, :cookies)
57
+ )
58
+ @sanitizer.strip_from!(
59
+ payload.dig(:error, :context, :request, :env)
60
+ )
61
+ @sanitizer.strip_from!(
62
+ payload.dig(:error, :context, :request, :headers)
63
+ )
64
+ @sanitizer.strip_from!(
65
+ payload.dig(:error, :context, :response, :headers)
66
+ )
44
67
  payload
45
68
  end
46
69
  end
@@ -77,8 +77,7 @@ module Atatus
77
77
  return unless socket
78
78
 
79
79
  {
80
- remote_addr: socket.remote_addr,
81
- encrypted: socket.encrypted
80
+ remote_addr: socket.remote_addr
82
81
  }
83
82
  end
84
83