atatus 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdb76c9559c230c2e772a5878d82486da076104089c39302722fccca8f0c22db
4
- data.tar.gz: 20233ccdea5269e3b3eb6c7c348091a161f875fbd1946554bdd314ee09f55ba2
3
+ metadata.gz: 3b14ce033d2727c9e1773987897f569026bfd7bb45ff3387ab7bed2d8e5dc912
4
+ data.tar.gz: 7d006a8ccc31f1cbb59d700eae5d7d83760c174e3dd8b0be7fc97e328feff8f0
5
5
  SHA512:
6
- metadata.gz: c0dfd9f4d6ecddad2036b1b289ec864ea0edbc5f0949bfd76639b741e5a6be6ca2da9840347b10950635a235df37c20c9464505675e022b10d5c9341dc2807c1
7
- data.tar.gz: 38d6f642f6f413e8c0ed989ba28d70bb9ce9643525fa28156ce8853e3781c1b3d3e9329d06d9ed0d8b7096a7d6799ad8817701012007a443f9a44a47ecf16136
6
+ metadata.gz: b8ee79aac253e143ea0867530643b800a226277dd644ca514a2aa07fbc656065f2a316eb3da46a5630e90ae2bb3041f984331453f475a6fa1a5afcccb349f1df
7
+ data.tar.gz: df8621294a91c15d6afec8ac6fc76aba8f40376deb989b213b7a6cc5c6d8e6b91fb40c517fcb227f8ddfb0cd1c5dfc1e6f14908aa655d7491df0f41a5fa17eea
data/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ 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
+ ## 1.7.0 (Fri, 15 Jul 2022)
8
+
9
+ - Added support for analytics.
10
+ - Fixed sequel instrumentation.
11
+
12
+
13
+ ## 1.6.2 (Mon, 31 Jan 2022)
14
+
15
+ - Fixed config environment.
16
+ - Supported ignore failure patterns, ignore exceptions and ignore transactions.
17
+
18
+
19
+ ## 1.6.1 (Wed, 29 Dec 2021)
20
+
21
+ - Fixed a specific case where span duration goes less than 0.
22
+
7
23
 
8
24
  ## 1.6.0 (Fri, 24 Dec 2021)
9
25
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- All components of this product are Copyright (c) 2021 Atatus. All rights reserved.
1
+ All components of this product are Copyright (c) 2022 Atatus. All rights reserved.
2
2
 
3
3
  Except as otherwise expressly provided in this Agreement,
4
4
  End User shall not (and shall not permit any third party to):
data/lib/atatus/agent.rb CHANGED
@@ -247,6 +247,14 @@ module Atatus
247
247
  instrumenter.set_user(user)
248
248
  end
249
249
 
250
+ def set_company(company)
251
+ instrumenter.set_company(company)
252
+ end
253
+
254
+ def set_response_body(response_body)
255
+ instrumenter.set_response_body(response_body)
256
+ end
257
+
250
258
  def build_context(rack_env:, for_type:)
251
259
  @context_builder.build(rack_env: rack_env, for_type: for_type)
252
260
  end
@@ -42,6 +42,12 @@ module Atatus
42
42
  @metrics_lock = Mutex.new
43
43
  @metrics_agg = []
44
44
 
45
+ @analytics = @config.analytics
46
+ @analytics_lock = Mutex.new
47
+ @analytics_agg = []
48
+
49
+ @hostinfo_response = {}
50
+ @hostinfo_response["analytics"] = true
45
51
  @transport = Atatus::BaseTransport.new(config)
46
52
  @collect_counter = 0
47
53
  @running = false
@@ -79,13 +85,38 @@ module Atatus
79
85
 
80
86
  def add_error(error)
81
87
  ensure_worker_running
82
-
83
- @errors_lock.synchronize do
84
- if @errors_aggs.length < 20
85
- @errors_aggs.push(error)
86
- else
87
- i = rand(20)
88
- @errors_aggs[i] = error
88
+ ignore_error = false
89
+ if
90
+ !error.exception.nil? &&
91
+ !error.exception.type.nil? &&
92
+ !error.exception.message.nil?
93
+ then
94
+ if @hostinfo_response.key?("ignoreExceptionPatterns")
95
+ @hostinfo_response['ignoreExceptionPatterns'].each do |k, v|
96
+ if error.exception.type.match(k)
97
+ exception_values = v
98
+ if exception_values.length == 0
99
+ ignore_error = true
100
+ else
101
+ exception_values.each do |value|
102
+ if error.exception.message.include?(value)
103
+ ignore_error = true
104
+ end
105
+ end
106
+ end
107
+ break
108
+ end
109
+ end
110
+ end
111
+ end
112
+ if ignore_error == false
113
+ @errors_lock.synchronize do
114
+ if @errors_aggs.length < 20
115
+ @errors_aggs.push(error)
116
+ else
117
+ i = rand(20)
118
+ @errors_aggs[i] = error
119
+ end
89
120
  end
90
121
  end
91
122
  end
@@ -128,6 +159,95 @@ module Atatus
128
159
  end
129
160
  end
130
161
 
162
+ def add_analytics(txn)
163
+ analytics_txn = {}
164
+ analytics_txn[:timestamp] = Util.ms(txn.timestamp).to_i
165
+ analytics_txn[:txnId] = ""
166
+ analytics_txn[:txnId] = txn.id if !txn.id.nil?
167
+ analytics_txn[:traceId] = ""
168
+ analytics_txn[:traceId] = txn.trace_id if !txn.trace_id.nil?
169
+ analytics_txn[:name] = txn.name
170
+ analytics_txn[:duration] = Util.ms(txn.duration)
171
+
172
+ if !txn.context.nil?
173
+ if !txn.context.request.nil?
174
+ r = txn.context.request
175
+
176
+ analytics_txn[:method] = r.method if !r.method.nil?
177
+
178
+ if !r.headers.nil?
179
+ analytics_txn[:requestHeaders] = r.headers
180
+ analytics_txn[:userAgent] = r.headers['User-Agent'] if r.headers.key?('User-Agent')
181
+ end
182
+
183
+ if !r.body.nil?
184
+ if !r.body.empty?
185
+ if r.body != "[SKIPPED]"
186
+ analytics_txn[:requestBody] = r.body.to_json
187
+ end
188
+ end
189
+ end
190
+
191
+ if !r.url.nil?
192
+ analytics_txn[:url] = r.url.full
193
+ end
194
+
195
+ if !r.socket.nil?
196
+ analytics_txn[:ip] = r.socket.remote_addr
197
+ end
198
+
199
+ end
200
+
201
+ if
202
+ defined?(txn.context.response_body) &&
203
+ !txn.context.response_body.nil?
204
+ then
205
+ analytics_txn[:responseBody] = txn.context.response_body
206
+ end
207
+
208
+ if !txn.context.response.nil?
209
+ if !txn.context.response.headers.nil?
210
+ analytics_txn[:responseHeaders] = txn.context.response.headers
211
+ end
212
+ if !txn.context.response.status_code.nil?
213
+ analytics_txn[:statusCode] = txn.context.response.status_code.to_i
214
+ end
215
+ end
216
+
217
+ if
218
+ defined?(txn.context.custom) &&
219
+ !txn.context.custom.nil? &&
220
+ !txn.context.custom.empty?
221
+ then
222
+ analytics_txn[:customData] = txn.context.custom
223
+ end
224
+
225
+ if
226
+ defined?(txn.context.user) &&
227
+ !txn.context.user.nil? &&
228
+ !txn.context.user.empty?
229
+ then
230
+ analytics_txn[:userId] = txn.context.user.id
231
+ analytics_txn[:userEmail] = txn.context.user.email
232
+ analytics_txn[:userName] = txn.context.user.username
233
+ end
234
+
235
+ if
236
+ defined?(txn.context.company) &&
237
+ !txn.context.company.nil? &&
238
+ !txn.context.company.empty?
239
+ then
240
+ analytics_txn[:companyId] = txn.context.company.id
241
+ end
242
+ end
243
+
244
+ @analytics_lock.synchronize do
245
+ if @analytics_agg.length < 10000
246
+ @analytics_agg << analytics_txn
247
+ end
248
+ end
249
+ end
250
+
131
251
  def add_span(span)
132
252
  ensure_worker_running
133
253
 
@@ -156,6 +276,19 @@ module Atatus
156
276
  return
157
277
  end
158
278
 
279
+ ignore_txn = false
280
+ if @hostinfo_response.key?("ignoreTxnNamePatterns")
281
+ @hostinfo_response['ignoreTxnNamePatterns'].each do |k|
282
+ if txn.name.match(k)
283
+ ignore_txn = true
284
+ break
285
+ end
286
+ end
287
+ end
288
+ if ignore_txn == true
289
+ return
290
+ end
291
+
159
292
  return if txn.name.empty?
160
293
  return if txn.duration <= 0
161
294
 
@@ -229,6 +362,9 @@ module Atatus
229
362
  end
230
363
  k += 1
231
364
  end
365
+ if spans_tuple[j].duration <= 0
366
+ spans_tuple[j].duration = 1
367
+ end
232
368
  end
233
369
 
234
370
  if !@txns_agg[txn.name].spans.key?(spans_tuple[j].name)
@@ -293,29 +429,55 @@ module Atatus
293
429
  !txn.context.response.status_code.nil?
294
430
  then
295
431
  status_code = txn.context.response.status_code.to_i
296
-
432
+ ignore_status_code = false
297
433
  if status_code >= 400 && status_code != 404
298
- if !@error_metrics_agg.key?(txn.name)
299
- @error_metrics_agg[txn.name] = {status_code => 1}
300
- else
301
- if !@error_metrics_agg[txn.name].key?(status_code)
302
- @error_metrics_agg[txn.name][status_code] = 1
303
- else
304
- @error_metrics_agg[txn.name][status_code] += 1
434
+ if @hostinfo_response.key?("ignoreHTTPFailurePatterns")
435
+ @hostinfo_response['ignoreHTTPFailurePatterns'].each do |k, v|
436
+ if txn.name.match(k)
437
+ status_code_array_s = v
438
+ if status_code_array_s.length == 0
439
+ ignore_status_code = true
440
+ else
441
+ status_code_array_s.each do |code|
442
+ if code == txn.context.response.status_code.to_s
443
+ ignore_status_code = true
444
+ end
445
+ end
446
+ end
447
+ break
448
+ end
305
449
  end
306
450
  end
451
+ if ignore_status_code == false
452
+ if !@error_metrics_agg.key?(txn.name)
453
+ @error_metrics_agg[txn.name] = {status_code => 1}
454
+ else
455
+ if !@error_metrics_agg[txn.name].key?(status_code)
456
+ @error_metrics_agg[txn.name][status_code] = 1
457
+ else
458
+ @error_metrics_agg[txn.name][status_code] += 1
459
+ end
460
+ end
307
461
 
308
- trace_id = ""
309
- trace_id = txn.trace_id if !txn.trace_id.nil?
310
- if @error_requests_agg.length < 20
311
- @error_requests_agg.push({'name' => txn.name, 'txn_id' => txn.id, 'trace_id' => trace_id, 'context' => txn.context})
312
- else
313
- i = rand(20)
314
- @error_requests_agg[i] = {'name' => txn.name, 'txn_id' => txn.id, 'trace_id' => trace_id, 'context' => txn.context}
462
+ trace_id = ""
463
+ trace_id = txn.trace_id if !txn.trace_id.nil?
464
+ if @error_requests_agg.length < 20
465
+ @error_requests_agg.push({'name' => txn.name, 'txn_id' => txn.id, 'trace_id' => trace_id, 'context' => txn.context})
466
+ else
467
+ i = rand(20)
468
+ @error_requests_agg[i] = {'name' => txn.name, 'txn_id' => txn.id, 'trace_id' => trace_id, 'context' => txn.context}
469
+ end
315
470
  end
316
471
  end
317
472
  end
318
473
 
474
+ if @hostinfo_response.key?("analytics")
475
+ if @hostinfo_response["analytics"] == true && @analytics == true
476
+ if background == false
477
+ add_analytics txn
478
+ end
479
+ end
480
+ end
319
481
  end
320
482
  end
321
483
 
@@ -353,13 +515,12 @@ module Atatus
353
515
  end
354
516
 
355
517
  if @collect_counter % 30 == 0
356
- @transport.hostinfo(start_time)
518
+ @hostinfo_response = @transport.hostinfo(start_time)
357
519
  @collect_counter = 0
358
520
  end
359
521
  @collect_counter += 1
360
522
 
361
523
  end_time = (Time.now.to_f * 1000).to_i
362
- debug '%s: data collector', pid_str
363
524
 
364
525
  txns_data = nil
365
526
  txn_hist_data = nil
@@ -368,6 +529,7 @@ module Atatus
368
529
  error_requests_data = nil
369
530
  errors_data = nil
370
531
  metrics_data = nil
532
+ analytics_data = nil
371
533
 
372
534
  @txns_lock.synchronize do
373
535
  txns_data = @txns_agg
@@ -386,6 +548,11 @@ module Atatus
386
548
  @error_requests_agg = []
387
549
  end
388
550
 
551
+ @analytics_lock.synchronize do
552
+ analytics_data = @analytics_agg
553
+ @analytics_agg = []
554
+ end
555
+
389
556
  @errors_lock.synchronize do
390
557
  errors_data = @errors_aggs
391
558
  @errors_aggs = []
@@ -412,6 +579,12 @@ module Atatus
412
579
  @transport.errors(start_time, end_time, errors_data) unless errors_data.empty?
413
580
 
414
581
  @transport.metrics(start_time, end_time, metrics_data) unless metrics_data.empty?
582
+
583
+ if @hostinfo_response.key?("analytics")
584
+ if @hostinfo_response["analytics"] == true && @analytics == true
585
+ @transport.analytics(start_time, end_time, analytics_data) unless analytics_data.empty?
586
+ end
587
+ end
415
588
  end
416
589
  end
417
590
  end
@@ -29,7 +29,8 @@ module Atatus
29
29
  version: VERSION
30
30
  },
31
31
  hostname: @metadata.hostname,
32
- hostId: @metadata.hwinfo.hostid
32
+ hostId: @metadata.hwinfo.hostid,
33
+ releaseStage: @config.environment
33
34
  }
34
35
  if !@container_id.nil?
35
36
  common[:containerId] = @container_id
@@ -91,6 +92,14 @@ module Atatus
91
92
  payload
92
93
  end
93
94
 
95
+ def analytics(start_time, end_time, analytics_data)
96
+ payload = common()
97
+ payload[:startTime] = start_time
98
+ payload[:endTime] = end_time
99
+ payload[:requests] = analytics_data
100
+ payload
101
+ end
102
+
94
103
  private
95
104
 
96
105
  def keyword_field(value)
@@ -14,6 +14,7 @@ module Atatus
14
14
  ERROR_ENDPOINT = "/track/apm/error".freeze
15
15
  ERROR_METRIC_ENDPOINT = "/track/apm/error_metric".freeze
16
16
  METRIC_ENDPOINT = "/track/apm/metric".freeze
17
+ ANALYTICS_ENDPOINT = "/track/apm/analytics/txn".freeze
17
18
 
18
19
  def initialize(config)
19
20
  @config = config
@@ -24,17 +25,25 @@ module Atatus
24
25
  @notify_host = "https://apm-rx.atatus.com"
25
26
  end
26
27
 
28
+ @analytics_notify_host = @config.analytics_notify_host
29
+ uri = URI(@analytics_notify_host)
30
+ if not uri.kind_of?(URI::HTTPS) and not uri.kind_of?(URI::HTTP)
31
+ @analytics_notify_host = "https://an-rx.atatus.com"
32
+ end
33
+
27
34
  @builder = Atatus::Builder.new(config)
28
35
  @headers = {}
29
36
  @headers['Content-Type'] = "application/json"
30
37
 
31
38
  @blocked = false
32
39
  @capture_percentiles = false
40
+ @hostinfo_response = {}
33
41
  end
34
42
 
35
43
  def hostinfo(start_time)
36
44
  payload = @builder.hostinfo(start_time)
37
45
  post(HOSTINFO_ENDPOINT, payload)
46
+ @hostinfo_response
38
47
  end
39
48
 
40
49
  def txns(start_time, end_time, data)
@@ -69,6 +78,11 @@ module Atatus
69
78
  post(METRIC_ENDPOINT, payload)
70
79
  end
71
80
 
81
+ def analytics(start_time, end_time, analytics_data)
82
+ payload = @builder.analytics(start_time, end_time, analytics_data)
83
+ post(ANALYTICS_ENDPOINT, payload)
84
+ end
85
+
72
86
  private
73
87
 
74
88
  def post(endpoint, data)
@@ -78,7 +92,12 @@ module Atatus
78
92
  end
79
93
 
80
94
  begin
81
- uri = URI(@notify_host + endpoint)
95
+ notify_host = @notify_host
96
+ if endpoint == ANALYTICS_ENDPOINT
97
+ notify_host = @analytics_notify_host
98
+ end
99
+
100
+ uri = URI(notify_host + endpoint)
82
101
  uri.query = URI.encode_www_form({"license_key": @config.license_key, "agent_name": AGENT_NAME, "agent_version": VERSION})
83
102
 
84
103
  request = Net::HTTP::Post.new(uri.request_uri, @headers)
@@ -88,7 +107,7 @@ module Atatus
88
107
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
89
108
  response = http.start { |http| http.request(request) }
90
109
  rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
91
- error format('Atatus transport [%s%s] failed with exception: %s', @notify_host, endpoint, e.message)
110
+ error format('Atatus transport [%s%s] failed with exception: %s', notify_host, endpoint, e.message)
92
111
  return
93
112
  end
94
113
 
@@ -107,9 +126,31 @@ module Atatus
107
126
 
108
127
  resp = JSON.parse response.body
109
128
  if resp
129
+ if resp.key?("analytics")
130
+ @hostinfo_response['analytics'] = resp["analytics"]
131
+ end
132
+
110
133
  if resp.key?("capturePercentiles")
111
134
  @capture_percentiles = resp["capturePercentiles"]
135
+ @hostinfo_response['capturePercentiles'] = @capture_percentiles
112
136
  end
137
+
138
+ if resp.key?("extRequestPatterns")
139
+ @hostinfo_response['extRequestPatterns'] = resp["extRequestPatterns"]
140
+ end
141
+
142
+ if resp.key?("ignoreTxnNamePatterns")
143
+ @hostinfo_response['ignoreTxnNamePatterns'] = resp["ignoreTxnNamePatterns"]
144
+ end
145
+
146
+ if resp.key?("ignoreHTTPFailurePatterns")
147
+ @hostinfo_response['ignoreHTTPFailurePatterns'] = resp["ignoreHTTPFailurePatterns"]
148
+ end
149
+
150
+ if resp.key?("ignoreExceptionPatterns")
151
+ @hostinfo_response['ignoreExceptionPatterns'] = resp["ignoreExceptionPatterns"]
152
+ end
153
+
113
154
  end
114
155
  else
115
156
  true
data/lib/atatus/config.rb CHANGED
@@ -34,7 +34,9 @@ module Atatus
34
34
  option :app_name, type: :string
35
35
  option :license_key, type: :string
36
36
  option :notify_host, type: :string, default: 'https://apm-rx.atatus.com'
37
+ option :analytics_notify_host, type: :string, default: 'https://an-rx.atatus.com'
37
38
  option :trace_threshold, type: :int, default: 2000
39
+ option :analytics, type: :bool, default: false
38
40
  option :config_file, type: :string, default: 'config/atatus.yml'
39
41
  option :server_url, type: :url, default: ''
40
42
  option :secret_token, type: :string
@@ -52,6 +54,7 @@ module Atatus
52
54
  option :current_user_email_method, type: :string, default: 'email'
53
55
  option :current_user_id_method, type: :string, default: 'id'
54
56
  option :current_user_username_method, type: :string, default: 'username'
57
+ option :current_company_id_method, type: :string, default: 'id'
55
58
  option :custom_key_filters, type: :list, default: [], converter: RegexpList.new
56
59
  option :default_labels, type: :dict, default: {}
57
60
  option :disable_metrics, type: :list, default: [], converter: WildcardPatternList.new
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Atatus
4
+ class Context
5
+ # @api private
6
+ class Company
7
+ def initialize(id: nil)
8
+ @id = id
9
+ end
10
+
11
+ def self.infer(config, record)
12
+ return unless record
13
+
14
+ new(
15
+ id: safe_get(record, config.current_company_id_method)&.to_s
16
+ )
17
+ end
18
+
19
+ attr_accessor :id
20
+
21
+ def empty?
22
+ !id
23
+ end
24
+
25
+ def any?
26
+ !empty?
27
+ end
28
+
29
+ class << self
30
+ private
31
+
32
+ def safe_get(record, method_name)
33
+ record.respond_to?(method_name) ? record.send(method_name) : nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -22,6 +22,7 @@ require 'atatus/context/request/socket'
22
22
  require 'atatus/context/request/url'
23
23
  require 'atatus/context/response'
24
24
  require 'atatus/context/user'
25
+ require 'atatus/context/company'
25
26
 
26
27
  module Atatus
27
28
  # @api private
@@ -42,6 +43,8 @@ module Atatus
42
43
  attr_reader :custom
43
44
  attr_reader :labels
44
45
  attr_reader :service
46
+ attr_accessor :company
47
+ attr_accessor :response_body
45
48
 
46
49
  # rubocop:disable Metrics/CyclomaticComplexity
47
50
  def empty?
@@ -253,6 +253,16 @@ module Atatus
253
253
  current_transaction.set_user(user)
254
254
  end
255
255
 
256
+ def set_company(company)
257
+ return unless current_transaction
258
+ current_transaction.set_company(company)
259
+ end
260
+
261
+ def set_response_body(response_body)
262
+ return unless current_transaction
263
+ current_transaction.set_response_body(response_body)
264
+ end
265
+
256
266
  def inspect
257
267
  '<Atatus::Instrumenter ' \
258
268
  "current_transaction=#{current_transaction.inspect}" \
@@ -66,7 +66,6 @@ module Atatus
66
66
  timeout_interval: TIMEOUT_INTERVAL
67
67
  ) do
68
68
  begin
69
- debug 'Collecting metrics'
70
69
  collect_and_send
71
70
  true
72
71
  rescue StandardError => e
@@ -28,59 +28,60 @@ module Atatus
28
28
  ACTION = 'query'
29
29
 
30
30
  def self.summarizer
31
- @summarizer ||= Sql.summarizer
31
+ @summarizer ||= Sql::Signature::Summarizer.new
32
32
  end
33
33
 
34
- def install
35
- require 'sequel/database/logging'
36
-
37
- if defined?(::Sequel) && defined?(::Sequel::Database)
38
-
39
- ::Sequel::Database.class_eval do
40
- alias log_connection_yield_without_apm log_connection_yield
41
-
42
- def log_connection_yield(sql, connection, args = nil, &block)
43
- unless Atatus.current_transaction
44
- return log_connection_yield_without_apm(
45
- sql, connection, args, &block
46
- )
47
- end
34
+ # @api private
35
+ module Ext
36
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
37
+ def log_connection_yield(sql, connection, args = nil, &block)
38
+ unless Atatus.current_transaction
39
+ return super(sql, connection, args, &block)
40
+ end
48
41
 
49
- subtype = database_type.to_s
42
+ subtype = database_type.to_s
50
43
 
51
- name =
52
- Atatus::Spies::SequelSpy.summarizer.summarize sql
44
+ name =
45
+ Atatus::Spies::SequelSpy.summarizer.summarize sql
53
46
 
54
- context = Atatus::Span::Context.new(
55
- db: { statement: sql, type: 'sql', user: opts[:user] },
56
- destination: { name: subtype, resource: subtype, type: TYPE }
57
- )
47
+ context = Atatus::Span::Context.new(
48
+ db: { statement: sql, type: 'sql', user: opts[:user] },
49
+ destination: { service: { resource: subtype } }
50
+ )
58
51
 
59
- span = Atatus.start_span(
60
- name,
61
- TYPE,
62
- subtype: subtype,
63
- action: ACTION,
64
- context: context
65
- )
66
- yield.tap do |result|
67
- if name =~ /^(UPDATE|DELETE)/
68
- if connection.respond_to?(:changes)
69
- span.context.db.rows_affected = connection.changes
70
- elsif result.is_a?(Integer)
71
- span.context.db.rows_affected = result
72
- end
73
- end
52
+ span = Atatus.start_span(
53
+ name,
54
+ TYPE,
55
+ subtype: subtype,
56
+ action: ACTION,
57
+ context: context
58
+ )
59
+ super(sql, connection, args, &block).tap do |result|
60
+ if /^(UPDATE|DELETE)/.match?(name)
61
+ if connection.respond_to?(:changes)
62
+ span.context.db.rows_affected = connection.changes
63
+ elsif result.is_a?(Integer)
64
+ span.context.db.rows_affected = result
74
65
  end
75
- ensure
76
- Atatus.end_span
77
66
  end
78
67
  end
79
-
68
+ rescue
69
+ span&.outcome = Span::Outcome::FAILURE
70
+ raise
71
+ ensure
72
+ span&.outcome ||= Span::Outcome::SUCCESS
73
+ Atatus.end_span
80
74
  end
75
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
76
+ end
77
+
78
+ def install
79
+ require 'sequel/database/logging'
80
+
81
+ ::Sequel::Database.prepend(Ext)
81
82
  end
82
83
  end
83
84
 
84
85
  register 'Sequel', 'sequel', SequelSpy.new
85
86
  end
86
- end
87
+ end
@@ -148,6 +148,14 @@ module Atatus
148
148
  context.user = Context::User.infer(@config, user)
149
149
  end
150
150
 
151
+ def set_company(company)
152
+ context.company = Context::Company.infer(@config, company)
153
+ end
154
+
155
+ def set_response_body(response_body)
156
+ context.response_body = response_body
157
+ end
158
+
151
159
  def inspect
152
160
  "<Atatus::Transaction id:#{id}" \
153
161
  " name:#{name.inspect} type:#{type.inspect}>"
@@ -19,5 +19,5 @@
19
19
 
20
20
  module Atatus
21
21
  AGENT_NAME = 'Ruby'
22
- VERSION = '1.6.0'
22
+ VERSION = '1.7.0'
23
23
  end
data/lib/atatus.rb CHANGED
@@ -376,6 +376,22 @@ module Atatus
376
376
  agent&.set_user(user)
377
377
  end
378
378
 
379
+ # Provide a company to the current transaction
380
+ #
381
+ # @param company [Object] An object representing a company
382
+ # @return [Object] Given company
383
+ def set_company(company)
384
+ agent&.set_company(company)
385
+ end
386
+
387
+ # Provide the response body to the current transaction
388
+ #
389
+ # @param response_body [String] A string containing the response body
390
+ # @return [String] Given response body
391
+ def set_response_body(response_body)
392
+ agent&.set_response_body(response_body.to_s)
393
+ end
394
+
379
395
  # Provide a filter to transform payloads before sending them off
380
396
  #
381
397
  # @param key [Symbol] Unique filter key
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atatus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atatus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-23 00:00:00.000000000 Z
11
+ date: 2022-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -74,6 +74,7 @@ files:
74
74
  - lib/atatus/config/regexp_list.rb
75
75
  - lib/atatus/config/wildcard_pattern_list.rb
76
76
  - lib/atatus/context.rb
77
+ - lib/atatus/context/company.rb
77
78
  - lib/atatus/context/request.rb
78
79
  - lib/atatus/context/request/socket.rb
79
80
  - lib/atatus/context/request/url.rb