atatus 1.0.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +72 -22
  4. data/LICENSE +1 -1
  5. data/atatus.gemspec +2 -2
  6. data/lib/atatus.rb +76 -16
  7. data/lib/atatus/agent.rb +78 -29
  8. data/lib/atatus/central_config.rb +72 -27
  9. data/lib/atatus/central_config/cache_control.rb +18 -1
  10. data/lib/atatus/child_durations.rb +64 -0
  11. data/lib/atatus/collector/base.rb +115 -35
  12. data/lib/atatus/collector/builder.rb +104 -33
  13. data/lib/atatus/collector/hist.rb +54 -0
  14. data/lib/atatus/collector/layer.rb +3 -0
  15. data/lib/atatus/collector/transport.rb +44 -10
  16. data/lib/atatus/config.rb +130 -29
  17. data/lib/atatus/config/bytes.rb +17 -0
  18. data/lib/atatus/config/duration.rb +17 -0
  19. data/lib/atatus/config/options.rb +29 -9
  20. data/lib/atatus/config/regexp_list.rb +17 -0
  21. data/lib/atatus/config/wildcard_pattern_list.rb +64 -0
  22. data/lib/atatus/context.rb +32 -1
  23. data/lib/atatus/context/request.rb +17 -0
  24. data/lib/atatus/context/request/socket.rb +18 -1
  25. data/lib/atatus/context/request/url.rb +17 -0
  26. data/lib/atatus/context/response.rb +27 -2
  27. data/lib/atatus/context/user.rb +17 -0
  28. data/lib/atatus/context_builder.rb +19 -4
  29. data/lib/atatus/deprecations.rb +17 -0
  30. data/lib/atatus/error.rb +27 -0
  31. data/lib/atatus/error/exception.rb +24 -0
  32. data/lib/atatus/error/log.rb +17 -0
  33. data/lib/atatus/error_builder.rb +17 -2
  34. data/lib/atatus/grape.rb +62 -0
  35. data/lib/atatus/graphql.rb +91 -0
  36. data/lib/atatus/grpc.rb +99 -0
  37. data/lib/atatus/instrumenter.rb +135 -30
  38. data/lib/atatus/internal_error.rb +17 -0
  39. data/lib/atatus/logging.rb +17 -2
  40. data/lib/atatus/metadata.rb +17 -0
  41. data/lib/atatus/metadata/process_info.rb +17 -0
  42. data/lib/atatus/metadata/service_info.rb +21 -6
  43. data/lib/atatus/metadata/system_info.rb +22 -3
  44. data/lib/atatus/metadata/system_info/container_info.rb +49 -10
  45. data/lib/atatus/metadata/system_info/hw_info.rb +1 -1
  46. data/lib/atatus/metrics.rb +69 -27
  47. data/lib/atatus/metrics/breakdown_set.rb +31 -0
  48. data/lib/atatus/metrics/{cpu_mem.rb → cpu_mem_set.rb} +110 -63
  49. data/lib/atatus/metrics/metric.rb +140 -0
  50. data/lib/atatus/metrics/set.rb +123 -0
  51. data/lib/atatus/metrics/span_scoped_set.rb +56 -0
  52. data/lib/atatus/metrics/transaction_set.rb +26 -0
  53. data/lib/atatus/metrics/vm_set.rb +58 -0
  54. data/lib/atatus/metricset.rb +48 -4
  55. data/lib/atatus/middleware.rb +28 -8
  56. data/lib/atatus/naively_hashable.rb +17 -0
  57. data/lib/atatus/normalizers.rb +23 -9
  58. data/lib/atatus/normalizers/grape.rb +22 -0
  59. data/lib/atatus/normalizers/grape/endpoint_run.rb +65 -0
  60. data/lib/atatus/normalizers/rails.rb +27 -0
  61. data/lib/atatus/normalizers/rails/action_controller.rb +44 -0
  62. data/lib/atatus/normalizers/rails/action_mailer.rb +43 -0
  63. data/lib/atatus/normalizers/{action_view.rb → rails/action_view.rb} +17 -0
  64. data/lib/atatus/normalizers/rails/active_record.rb +80 -0
  65. data/lib/atatus/opentracing.rb +75 -42
  66. data/lib/atatus/rails.rb +29 -13
  67. data/lib/atatus/railtie.rb +19 -6
  68. data/lib/atatus/resque.rb +29 -0
  69. data/lib/atatus/sinatra.rb +53 -0
  70. data/lib/atatus/span.rb +48 -18
  71. data/lib/atatus/span/context.rb +43 -28
  72. data/lib/atatus/span/context/db.rb +43 -0
  73. data/lib/atatus/span/context/destination.rb +77 -0
  74. data/lib/atatus/span/context/http.rb +43 -0
  75. data/lib/atatus/span_helpers.rb +32 -6
  76. data/lib/atatus/spies.rb +33 -15
  77. data/lib/atatus/spies/action_dispatch.rb +27 -6
  78. data/lib/atatus/spies/delayed_job.rb +26 -5
  79. data/lib/atatus/spies/dynamo_db.rb +62 -0
  80. data/lib/atatus/spies/elasticsearch.rb +53 -7
  81. data/lib/atatus/spies/faraday.rb +54 -20
  82. data/lib/atatus/spies/http.rb +36 -6
  83. data/lib/atatus/spies/json.rb +18 -0
  84. data/lib/atatus/spies/mongo.rb +41 -10
  85. data/lib/atatus/spies/net_http.rb +52 -11
  86. data/lib/atatus/spies/rake.rb +42 -23
  87. data/lib/atatus/spies/redis.rb +17 -0
  88. data/lib/atatus/spies/resque.rb +57 -0
  89. data/lib/atatus/spies/sequel.rb +54 -17
  90. data/lib/atatus/spies/shoryuken.rb +69 -0
  91. data/lib/atatus/spies/sidekiq.rb +46 -25
  92. data/lib/atatus/spies/sinatra.rb +20 -4
  93. data/lib/atatus/spies/sneakers.rb +74 -0
  94. data/lib/atatus/spies/sucker_punch.rb +58 -0
  95. data/lib/atatus/spies/tilt.rb +20 -1
  96. data/lib/atatus/sql.rb +36 -0
  97. data/lib/atatus/sql/signature.rb +169 -0
  98. data/lib/atatus/sql/tokenizer.rb +264 -0
  99. data/lib/atatus/sql/tokens.rb +63 -0
  100. data/lib/atatus/sql_summarizer.rb +24 -6
  101. data/lib/atatus/stacktrace.rb +17 -0
  102. data/lib/atatus/stacktrace/frame.rb +17 -3
  103. data/lib/atatus/stacktrace_builder.rb +34 -10
  104. data/lib/atatus/subscriber.rb +23 -4
  105. data/lib/atatus/trace_context.rb +84 -51
  106. data/lib/atatus/trace_context/traceparent.rb +111 -0
  107. data/lib/atatus/trace_context/tracestate.rb +148 -0
  108. data/lib/atatus/transaction.rb +75 -19
  109. data/lib/atatus/transport/base.rb +44 -27
  110. data/lib/atatus/transport/connection.rb +28 -72
  111. data/lib/atatus/transport/connection/http.rb +58 -35
  112. data/lib/atatus/transport/connection/proxy_pipe.rb +24 -5
  113. data/lib/atatus/transport/filters.rb +18 -1
  114. data/lib/atatus/transport/filters/hash_sanitizer.rb +77 -0
  115. data/lib/atatus/transport/filters/secrets_filter.rb +30 -55
  116. data/lib/atatus/transport/headers.rb +83 -0
  117. data/lib/atatus/transport/serializers.rb +17 -5
  118. data/lib/atatus/transport/serializers/context_serializer.rb +30 -3
  119. data/lib/atatus/transport/serializers/error_serializer.rb +17 -2
  120. data/lib/atatus/transport/serializers/metadata_serializer.rb +44 -22
  121. data/lib/atatus/transport/serializers/metricset_serializer.rb +34 -6
  122. data/lib/atatus/transport/serializers/span_serializer.rb +47 -12
  123. data/lib/atatus/transport/serializers/transaction_serializer.rb +18 -2
  124. data/lib/atatus/transport/user_agent.rb +48 -0
  125. data/lib/atatus/transport/worker.rb +31 -7
  126. data/lib/atatus/util.rb +22 -1
  127. data/lib/atatus/util/inflector.rb +17 -0
  128. data/lib/atatus/util/lru_cache.rb +17 -0
  129. data/lib/atatus/util/throttle.rb +17 -0
  130. data/lib/atatus/version.rb +19 -1
  131. metadata +46 -26
  132. data/Rakefile +0 -19
  133. data/bench/.gitignore +0 -2
  134. data/bench/app.rb +0 -53
  135. data/bench/benchmark.rb +0 -36
  136. data/bench/report.rb +0 -55
  137. data/bench/rubyprof.rb +0 -39
  138. data/bench/stackprof.rb +0 -23
  139. data/bin/build_docs +0 -5
  140. data/bin/console +0 -15
  141. data/bin/setup +0 -8
  142. data/bin/with_framework +0 -7
  143. data/lib/atatus/metrics/vm.rb +0 -60
  144. data/lib/atatus/normalizers/action_controller.rb +0 -27
  145. data/lib/atatus/normalizers/action_mailer.rb +0 -26
  146. data/lib/atatus/normalizers/active_record.rb +0 -45
  147. data/lib/atatus/util/prefixed_logger.rb +0 -18
  148. data/vendor/.gitkeep +0 -0
@@ -3,8 +3,7 @@ require 'atatus/metadata'
3
3
  require 'yaml'
4
4
  module Atatus
5
5
  class Builder
6
- AGENT_NAME = 'Ruby'
7
-
6
+
8
7
  def initialize(config)
9
8
  @config = config
10
9
  @metadata = Metadata::SystemInfo.new(config)
@@ -53,6 +52,14 @@ module Atatus
53
52
  payload
54
53
  end
55
54
 
55
+ def txn_hist(start_time, end_time, data)
56
+ payload = common()
57
+ payload[:startTime] = start_time
58
+ payload[:endTime] = end_time
59
+ payload[:transactions] = build_txn_hist_obj(data)
60
+ payload
61
+ end
62
+
56
63
  def traces(start_time, end_time, data)
57
64
  payload = common()
58
65
  payload[:startTime] = start_time
@@ -131,16 +138,36 @@ module Atatus
131
138
  {}
132
139
  end
133
140
 
134
- def build_metric(name, value)
141
+ def build_metric(name, value, background: false)
135
142
  return unless name
136
143
  return unless value
137
144
 
138
- {
139
- name: name,
140
- type: value.type,
141
- kind: value.kind,
142
- durations: [value.count, Util.ms(value.min), Util.ms(value.max), Util.ms(value.total)]
143
- }
145
+ m = {
146
+ name: name,
147
+ type: value.type,
148
+ kind: value.kind,
149
+ durations: [value.count, Util.ms(value.total), Util.ms(value.min), Util.ms(value.max)],
150
+ }
151
+
152
+ if background == true
153
+ m[:background] = background
154
+ end
155
+
156
+ m
157
+ end
158
+
159
+ def build_hist_metric(name, value)
160
+ return unless name
161
+ return unless value
162
+
163
+ m = {
164
+ name: name,
165
+ type: value.type,
166
+ kind: value.kind,
167
+ histogram: value.hist,
168
+ }
169
+
170
+ m
144
171
  end
145
172
 
146
173
  def build_request(context)
@@ -168,7 +195,7 @@ module Atatus
168
195
 
169
196
  if !context.response.nil?
170
197
  if !context.response.status_code.nil?
171
- request[:statusCode] = context.response.status_code
198
+ request[:statusCode] = context.response.status_code.to_i
172
199
  end
173
200
  end
174
201
 
@@ -178,7 +205,7 @@ module Atatus
178
205
  def build_txns_obj(data)
179
206
  txns = []
180
207
  data.each do |t, v|
181
- txn = build_metric(t, v)
208
+ txn = build_metric(t, v, background: v.background)
182
209
  txn[:traces] = []
183
210
  v.spans.each do |l, u|
184
211
  txn[:traces] << build_metric(l, u)
@@ -189,6 +216,17 @@ module Atatus
189
216
  txns
190
217
  end
191
218
 
219
+ def build_txn_hist_obj(data)
220
+ txn_hist = []
221
+ data.each do |t, v|
222
+ hist = build_hist_metric(t, v)
223
+ if hist
224
+ txn_hist << hist
225
+ end
226
+ end
227
+ txn_hist
228
+ end
229
+
192
230
  def build_traces_obj(data)
193
231
  traces = []
194
232
  data.each do |txn|
@@ -233,11 +271,23 @@ module Atatus
233
271
  if
234
272
  !span.context.nil? &&
235
273
  !span.context.db.nil? &&
274
+ defined?(span.context.db.statement) &&
236
275
  !span.context.db.statement.nil?
237
276
  then
238
277
  entry[:dt] = {}
239
278
  entry[:dt][:query] = span.context.db.statement
240
279
  end
280
+ if
281
+ !span.context.nil? &&
282
+ !span.context.http.nil? &&
283
+ defined?(span.context.http.url) &&
284
+ !span.context.http.url.nil?
285
+ then
286
+ entry[:dt] = {}
287
+ entry[:dt][:url] = span.context.http.url
288
+ entry[:dt][:method] = span.context.http.method if defined?(span.context.http.method) && !span.context.http.method.nil?
289
+ entry[:dt][:status_code] = span.context.http.status_code.to_s if defined?(span.context.http.status_code) && !span.context.http.status_code.nil?
290
+ end
241
291
  trace[:entries] << entry
242
292
  func_index = trace[:funcs].index(span.name)
243
293
  if func_index.nil?
@@ -249,6 +299,27 @@ module Atatus
249
299
  end
250
300
  end
251
301
 
302
+ if
303
+ !txn.ruby_time.nil?
304
+ then
305
+ entry = {}
306
+ entry[:lv] = 1
307
+ entry[:so] = 0
308
+ entry[:du] = Util.ms(txn.ruby_time)
309
+ entry[:ly] = {}
310
+ entry[:ly][:name] = AGENT_NAME
311
+ entry[:ly][:type] = AGENT_NAME
312
+ entry[:ly][:kind] = AGENT_NAME
313
+ trace[:entries] << entry
314
+ func_index = trace[:funcs].index(AGENT_NAME)
315
+ if func_index.nil?
316
+ trace[:funcs] << AGENT_NAME
317
+ func_index = i
318
+ i = i + 1
319
+ end
320
+ entry[:i] = func_index
321
+ end
322
+
252
323
  traces << trace
253
324
  end
254
325
  traces
@@ -338,33 +409,33 @@ module Atatus
338
409
  frame = {}
339
410
  frame[:f] = f.filename
340
411
  frame[:m] = f.function
341
- frame[:ln] = f.lineno
412
+ frame[:ln] = f.lineno.to_i
342
413
  if f.library_frame == false
343
414
  frame[:inp] = true
344
- if !f.context_line.nil?
345
- frame[:code] = []
346
-
347
- if !f.pre_context.nil?
348
- psize = f.pre_context.size
349
- lineno = 0
350
- if f.lineno - psize >= 0
351
- lineno = f.lineno - psize
352
- end
353
- f.pre_context.each do |c|
354
- frame[:code].push([lineno.to_s, c])
355
- lineno += 1
356
- end
415
+ end
416
+ if !f.context_line.nil?
417
+ frame[:code] = []
418
+
419
+ if f.library_frame == false && !f.pre_context.nil?
420
+ psize = f.pre_context.size
421
+ lineno = 0
422
+ if f.lineno - psize >= 0
423
+ lineno = f.lineno - psize
357
424
  end
425
+ f.pre_context.each do |c|
426
+ frame[:code].push([lineno.to_s, c])
427
+ lineno += 1
428
+ end
429
+ end
358
430
 
359
- frame[:code].push([f.lineno.to_s, f.context_line])
431
+ frame[:code].push([f.lineno.to_s, f.context_line])
360
432
 
361
- if !f.post_context.nil?
362
- psize = f.post_context.size
363
- lineno = f.lineno + 1
364
- f.post_context.each do |c|
365
- frame[:code].push([lineno.to_s, c])
366
- lineno += 1
367
- end
433
+ if f.library_frame == false && !f.post_context.nil?
434
+ psize = f.post_context.size
435
+ lineno = f.lineno + 1
436
+ f.post_context.each do |c|
437
+ frame[:code].push([lineno.to_s, c])
438
+ lineno += 1
368
439
  end
369
440
  end
370
441
  end
@@ -0,0 +1,54 @@
1
+
2
+ module Atatus
3
+ module Collector
4
+ class TxnHist
5
+ def initialize(type, kind, duration)
6
+ @type = type
7
+ @kind = kind
8
+ @hist = {}
9
+ @hist[find_bin duration] = 1
10
+ end
11
+
12
+ attr_reader :type, :kind, :hist
13
+
14
+ def aggregate!(duration)
15
+ hbin = find_bin duration
16
+ if !@hist.key?(hbin)
17
+ @hist[hbin] = 1
18
+ else
19
+ @hist[hbin] += 1
20
+ end
21
+ end
22
+
23
+ private
24
+ def find_bin(duration)
25
+ seconds = 1000
26
+ hbin = 0
27
+
28
+ if duration < 0
29
+ hbin = 0
30
+ elsif duration < 2*seconds
31
+ hbin = round_bin(duration, 10)
32
+ elsif duration < 10*seconds
33
+ hbin = round_bin(duration, 25)
34
+ elsif duration < 20*seconds
35
+ hbin = round_bin(duration, 50)
36
+ elsif duration < 50*seconds
37
+ hbin = round_bin(duration, 100)
38
+ elsif duration < 80*seconds
39
+ hbin = round_bin(duration, 200)
40
+ elsif duration < 100*seconds
41
+ hbin = round_bin(duration, 250)
42
+ else
43
+ hbin = round_bin(duration, 1000)
44
+ end
45
+
46
+ hbin
47
+ end
48
+
49
+ def round_bin(duration, unit)
50
+ ((duration / unit.to_f).floor) * unit
51
+ end
52
+ end
53
+ end
54
+ end
@@ -48,6 +48,9 @@ module Atatus
48
48
  'graphql' => 'GraphQL',
49
49
  'elasticsearch' => 'Elasticsearch',
50
50
  'cassandra' => 'Cassandra',
51
+ 'sqlite'=> 'SQLite',
52
+ 'controller' => 'Controller',
53
+ 'view' => 'View',
51
54
  'http' => 'External Requests',
52
55
  'http2' => 'External Requests',
53
56
  'http_rb' => 'External Requests',
@@ -8,6 +8,7 @@ module Atatus
8
8
  include Logging
9
9
 
10
10
  TXN_ENDPOINT = '/track/apm/txn'.freeze
11
+ TXN_HIST_ENDPOINT = '/track/apm/txn/histogram'.freeze
11
12
  TRACE_ENDPOINT = '/track/apm/trace'.freeze
12
13
  HOSTINFO_ENDPOINT = "/track/apm/hostinfo".freeze
13
14
  ERROR_ENDPOINT = "/track/apm/error".freeze
@@ -18,15 +19,17 @@ module Atatus
18
19
  @config = config
19
20
 
20
21
  @notify_host = @config.notify_host
21
- @uri = URI(@notify_host)
22
- if not @uri.kind_of?(URI::HTTPS) and not @uri.kind_of?(URI::HTTP)
22
+ uri = URI(@notify_host)
23
+ if not uri.kind_of?(URI::HTTPS) and not uri.kind_of?(URI::HTTP)
23
24
  @notify_host = "https://apm-rx.atatus.com"
24
- @uri = URI(@notify_host)
25
25
  end
26
26
 
27
27
  @builder = Atatus::Builder.new(config)
28
28
  @headers = {}
29
29
  @headers['Content-Type'] = "application/json"
30
+
31
+ @blocked = false
32
+ @capture_percentiles = false
30
33
  end
31
34
 
32
35
  def hostinfo(start_time)
@@ -39,6 +42,13 @@ module Atatus
39
42
  post(TXN_ENDPOINT, payload)
40
43
  end
41
44
 
45
+ def txn_hist(start_time, end_time, data)
46
+ if @capture_percentiles == true
47
+ payload = @builder.txn_hist(start_time, end_time, data)
48
+ post(TXN_HIST_ENDPOINT, payload)
49
+ end
50
+ end
51
+
42
52
  def traces(start_time, end_time, data)
43
53
  payload = @builder.traces(start_time, end_time, data)
44
54
  post(TRACE_ENDPOINT, payload)
@@ -68,14 +78,18 @@ module Atatus
68
78
  end
69
79
 
70
80
  begin
71
- request = Net::HTTP::Post.new(endpoint, @headers)
81
+ uri = URI(@notify_host + endpoint)
82
+ uri.query = URI.encode_www_form({"license_key": @config.license_key, "agent_name": AGENT_NAME, "agent_version": VERSION})
83
+
84
+ request = Net::HTTP::Post.new(uri.request_uri, @headers)
72
85
  request.body = ::JSON.dump(data)
73
- http = Net::HTTP.new(@uri.host, @uri.port)
86
+ http = Net::HTTP.new(uri.host, uri.port)
74
87
  http.use_ssl = true
75
88
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
76
89
  response = http.start { |http| http.request(request) }
77
90
  rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
78
- puts "Atatus transport [#{@notify_host}#{endpoint}] failed with exception: #{e}"
91
+ error format('Atatus transport [%s%s] failed with exception: %s', @notify_host, endpoint, e.message)
92
+ return
79
93
  end
80
94
 
81
95
  if @blocked == true
@@ -84,10 +98,25 @@ module Atatus
84
98
 
85
99
  case response
86
100
  when Net::HTTPSuccess
87
- true
101
+ if endpoint == HOSTINFO_ENDPOINT
102
+ @capture_percentiles = false
103
+
104
+ if not response.body
105
+ return
106
+ end
107
+
108
+ resp = JSON.parse response.body
109
+ if resp
110
+ if resp.key?("capturePercentiles")
111
+ @capture_percentiles = resp["capturePercentiles"]
112
+ end
113
+ end
114
+ else
115
+ true
116
+ end
88
117
  when Net::HTTPBadRequest
89
118
  if not response.body
90
- error format('Atatus transport status 400, failed without content')
119
+ error format('Transport status 400, failed without content')
91
120
  return
92
121
  end
93
122
 
@@ -97,15 +126,20 @@ module Atatus
97
126
  @blocked = resp[:blocked]
98
127
  if @blocked == true
99
128
  if resp.key?(:errorMessage)
100
- error format('Atatus blocked from sending data as: %s', resp[:errorMessage])
129
+ error format('Blocked from sending data as: %s', resp[:errorMessage])
101
130
  return
102
131
  end
103
132
  end
104
133
  end
105
134
  end
106
135
 
107
- error format('Atatus transport status 400, failed with content: %s', response.message)
136
+ if !resp
137
+ error format('Transport status 400, failed with parsed content: %s', resp)
138
+ else
139
+ error format('Transport status 400, failed with content: %s', response.body)
140
+ end
108
141
  else
142
+ error format('Transport unexpected failure: [%s] [%s]', response.code, endpoint)
109
143
  end
110
144
  end
111
145
  end
data/lib/atatus/config.rb CHANGED
@@ -1,18 +1,29 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
- require 'yaml'
5
- require 'erb'
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.
6
17
 
7
- require 'atatus/util/prefixed_logger'
18
+ # frozen_string_literal: true
8
19
 
9
20
  require 'atatus/config/options'
10
21
  require 'atatus/config/duration'
11
22
  require 'atatus/config/bytes'
12
23
  require 'atatus/config/regexp_list'
24
+ require 'atatus/config/wildcard_pattern_list'
13
25
 
14
26
  module Atatus
15
- # rubocop:disable Metrics/ClassLength
16
27
  # @api private
17
28
  class Config
18
29
  extend Options
@@ -25,27 +36,30 @@ module Atatus
25
36
  option :notify_host, type: :string, default: 'https://apm-rx.atatus.com'
26
37
  option :trace_threshold, type: :int, default: 2000
27
38
  option :config_file, type: :string, default: 'config/atatus.yml'
28
- option :server_url, type: :string, default: ''
39
+ option :server_url, type: :url, default: ''
29
40
  option :secret_token, type: :string
41
+ option :api_key, type: :string
30
42
 
31
- option :active, type: :bool, default: true
32
43
  option :api_buffer_size, type: :int, default: 256
33
44
  option :api_request_size, type: :bytes, default: '750kb', converter: Bytes.new
34
45
  option :api_request_time, type: :float, default: '10s', converter: Duration.new
46
+ option :breakdown_metrics, type: :bool, default: true
35
47
  option :capture_body, type: :string, default: 'off'
36
48
  option :capture_headers, type: :bool, default: true
49
+ option :capture_elasticsearch_queries, type: :bool, default: false
37
50
  option :capture_env, type: :bool, default: true
38
51
  option :central_config, type: :bool, default: true
39
52
  option :current_user_email_method, type: :string, default: 'email'
40
53
  option :current_user_id_method, type: :string, default: 'id'
41
54
  option :current_user_username_method, type: :string, default: 'username'
42
55
  option :custom_key_filters, type: :list, default: [], converter: RegexpList.new
43
- option :default_tags, type: :dict, default: {}
44
56
  option :default_labels, type: :dict, default: {}
57
+ option :disable_metrics, type: :list, default: [], converter: WildcardPatternList.new
45
58
  option :disable_send, type: :bool, default: false
46
59
  option :disable_start_message, type: :bool, default: false
47
- option :disabled_instrumentations, type: :list, default: %w[json]
60
+ option :disable_instrumentations, type: :list, default: %w[json]
48
61
  option :disabled_spies, type: :list, default: []
62
+ option :enabled, type: :bool, default: true
49
63
  option :environment, type: :string, default: ENV['RAILS_ENV'] || ENV['RACK_ENV']
50
64
  option :framework_name, type: :string
51
65
  option :framework_version, type: :string
@@ -65,26 +79,29 @@ module Atatus
65
79
  option :proxy_password, type: :string
66
80
  option :proxy_port, type: :int
67
81
  option :proxy_username, type: :string
82
+ option :recording, type: :bool, default: true
83
+ option :sanitize_field_names, type: :list, default: [], converter: WildcardPatternList.new
68
84
  option :server_ca_cert, type: :string
69
85
  option :service_name, type: :string
86
+ option :service_node_name, type: :string
70
87
  option :service_version, type: :string
71
88
  option :source_lines_error_app_frames, type: :int, default: 5
72
89
  option :source_lines_error_library_frames, type: :int, default: 0
73
- option :source_lines_span_app_frames, type: :int, default: 5
90
+ option :source_lines_span_app_frames, type: :int, default: 0
74
91
  option :source_lines_span_library_frames, type: :int, default: 0
75
92
  option :span_frames_min_duration, type: :float, default: '5ms', converter: Duration.new(default_unit: 'ms')
76
93
  option :stack_trace_limit, type: :int, default: 999_999
94
+ option :transaction_ignore_urls, type: :list, default: [], converter: WildcardPatternList.new
77
95
  option :transaction_max_spans, type: :int, default: 500
78
96
  option :transaction_sample_rate, type: :float, default: 1.0
97
+ option :use_atatus_traceparent_header, type: :bool, default: true
98
+ option :use_legacy_sql_parser, type: :bool, default: false
79
99
  option :verify_server_cert, type: :bool, default: true
80
- # rubocop:enable Metrics/LineLength, Layout/ExtraSpacing
81
100
 
82
- # rubocop:disable Metrics/MethodLength
101
+ # rubocop:enable Metrics/LineLength, Layout/ExtraSpacing
83
102
  def initialize(options = {})
84
103
  @options = load_schema
85
104
 
86
- custom_logger = options.delete(:logger)
87
-
88
105
  assign(options)
89
106
 
90
107
  # Pick out config_file specifically as we need it now to load it,
@@ -99,12 +116,11 @@ module Atatus
99
116
 
100
117
  yield self if block_given?
101
118
 
102
- @logger = custom_logger || build_logger
119
+ self.logger ||= build_logger
103
120
 
104
- @__view_paths = []
105
- @__root_path = Dir.pwd
121
+ @__view_paths ||= []
122
+ @__root_path ||= Dir.pwd
106
123
  end
107
- # rubocop:enable Metrics/MethodLength
108
124
 
109
125
  attr_accessor :__view_paths, :__root_path
110
126
  attr_accessor :logger
@@ -116,28 +132,32 @@ module Atatus
116
132
  update.each { |key, value| send(:"#{key}=", value) }
117
133
  end
118
134
 
119
- # rubocop:disable Metrics/MethodLength
120
135
  def available_instrumentations
121
136
  %w[
137
+ action_dispatch
122
138
  delayed_job
139
+ dynamo_db
123
140
  elasticsearch
124
141
  faraday
125
142
  http
126
143
  json
127
144
  mongo
128
145
  net_http
146
+ rake
129
147
  redis
148
+ resque
130
149
  sequel
150
+ shoryuken
131
151
  sidekiq
132
152
  sinatra
153
+ sneakers
154
+ sucker_punch
133
155
  tilt
134
- rake
135
156
  ]
136
157
  end
137
- # rubocop:enable Metrics/MethodLength
138
158
 
139
159
  def enabled_instrumentations
140
- available_instrumentations - disabled_instrumentations
160
+ available_instrumentations - disable_instrumentations
141
161
  end
142
162
 
143
163
  def method_missing(name, *args)
@@ -145,6 +165,15 @@ module Atatus
145
165
  warn "The option `#{name}' has been removed."
146
166
  end
147
167
 
168
+ def replace_options(new_options)
169
+ return if new_options.nil? || new_options.empty?
170
+ options_copy = @options.dup
171
+ new_options.each do |key, value|
172
+ options_copy.fetch(key.to_sym).set(value)
173
+ end
174
+ @options = options_copy
175
+ end
176
+
148
177
  def app=(app)
149
178
  case app_type?(app)
150
179
  when :sinatra
@@ -177,10 +206,83 @@ module Atatus
177
206
  @span_frames_min_duration_us ||= span_frames_min_duration * 1_000_000
178
207
  end
179
208
 
209
+ def ssl_context
210
+ return unless use_ssl?
211
+
212
+ @ssl_context ||=
213
+ OpenSSL::SSL::SSLContext.new.tap do |context|
214
+ if server_ca_cert
215
+ context.ca_file = server_ca_cert
216
+ else
217
+ context.cert_store =
218
+ OpenSSL::X509::Store.new.tap(&:set_default_paths)
219
+ end
220
+
221
+ context.verify_mode =
222
+ if verify_server_cert
223
+ OpenSSL::SSL::VERIFY_PEER
224
+ else
225
+ OpenSSL::SSL::VERIFY_NONE
226
+ end
227
+ end
228
+ end
229
+
180
230
  def inspect
181
231
  super.split.first + '>'
182
232
  end
183
233
 
234
+ # Deprecations
235
+
236
+ def default_tags=(value)
237
+ warn '[DEPRECATED] The option default_tags has been renamed to ' \
238
+ 'default_labels.'
239
+ self.default_labels = value
240
+ end
241
+
242
+ def ignore_url_patterns=(value)
243
+ unless value == self.class.schema[:ignore_url_patterns][:default]
244
+ warn '[DEPRECATED] The option ignore_url_patterns is being removed. ' \
245
+ 'Consider using transaction_ignore_urls instead.'
246
+ end
247
+
248
+ set(:ignore_url_patterns, value)
249
+ end
250
+
251
+ def custom_key_filters=(value)
252
+ unless value == self.class.schema[:custom_key_filters][:default]
253
+ warn '[DEPRECATED] The option custom_key_filters is being removed. ' \
254
+ 'See sanitize_field_names for an alternative.'
255
+ end
256
+
257
+ set(:custom_key_filters, value)
258
+ end
259
+
260
+ def disabled_instrumentations
261
+ disable_instrumentations
262
+ end
263
+
264
+ def active
265
+ enabled
266
+ end
267
+ alias active? active
268
+
269
+ def disabled_instrumentations=(value)
270
+ warn '[DEPRECATED] The option disabled_instrumentations has been ' \
271
+ 'renamed to disable_instrumentations to align with other agents.'
272
+ self.disable_instrumentations = value
273
+ end
274
+
275
+ def use_experimental_sql_parser=(value)
276
+ warn '[DEPRECATED] The new SQL parser is now the default. To use the old one, '
277
+ 'use use_legacy_sql_parser and please report why you wish to do so.'
278
+ end
279
+
280
+ def active=(value)
281
+ warn '[DEPRECATED] The option active has been renamed to enabled ' \
282
+ 'to align with other agents and with the remote config.'
283
+ self.enabled = value
284
+ end
285
+
184
286
  private
185
287
 
186
288
  def load_config_file
@@ -219,18 +321,18 @@ module Atatus
219
321
  def set_sinatra(app)
220
322
  self.service_name = format_name(service_name || app.to_s)
221
323
  self.framework_name = framework_name || 'Sinatra'
222
- self.framework_version = framework_version || Sinatra::VERSION
324
+ self.framework_version = framework_version || ::Sinatra::VERSION
223
325
  self.__root_path = Dir.pwd
224
326
  end
225
327
 
226
- def set_rails(app) # rubocop:disable Metrics/AbcSize
328
+ def set_rails(app)
227
329
  self.service_name ||= format_name(service_name || rails_app_name(app))
228
330
  self.framework_name ||= 'Rails'
229
331
  self.framework_version ||= ::Rails::VERSION::STRING
230
332
  self.logger ||= ::Rails.logger
231
333
 
232
334
  self.__root_path = ::Rails.root.to_s
233
- self.__view_paths = app.config.paths['app/views'].existent
335
+ self.__view_paths = app.config.paths['app/views'].existent + [::Rails.root.to_s]
234
336
  end
235
337
 
236
338
  def rails_app_name(app)
@@ -242,8 +344,7 @@ module Atatus
242
344
  end
243
345
 
244
346
  def format_name(str)
245
- str && str.gsub('::', '_')
347
+ str&.gsub('::', '_')
246
348
  end
247
349
  end
248
- # rubocop:enable Metrics/ClassLength
249
350
  end