atatus 1.6.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +49 -13
  4. data/LICENSE +1 -1
  5. data/atatus.gemspec +3 -3
  6. data/lib/atatus/agent.rb +18 -7
  7. data/lib/atatus/central_config.rb +19 -8
  8. data/lib/atatus/collector/base.rb +113 -1
  9. data/lib/atatus/collector/builder.rb +8 -0
  10. data/lib/atatus/collector/layer.rb +1 -1
  11. data/lib/atatus/collector/transport.rb +23 -2
  12. data/lib/atatus/{sql_summarizer.rb → config/log_level_map.rb} +22 -28
  13. data/lib/atatus/config/options.rb +2 -1
  14. data/lib/atatus/config/regexp_list.rb +1 -1
  15. data/lib/atatus/config/round_float.rb +31 -0
  16. data/lib/atatus/config/server_info.rb +50 -0
  17. data/lib/atatus/config/wildcard_pattern_list.rb +3 -1
  18. data/lib/atatus/config.rb +94 -70
  19. data/lib/atatus/context/company.rb +38 -0
  20. data/lib/atatus/context/request/socket.rb +1 -2
  21. data/lib/atatus/context/response.rb +1 -3
  22. data/lib/atatus/context.rb +4 -8
  23. data/lib/atatus/context_builder.rb +3 -3
  24. data/lib/atatus/error.rb +2 -1
  25. data/lib/atatus/error_builder.rb +1 -1
  26. data/lib/atatus/fields.rb +98 -0
  27. data/lib/atatus/graphql.rb +2 -0
  28. data/lib/atatus/grpc.rb +5 -7
  29. data/lib/atatus/instrumenter.rb +38 -24
  30. data/lib/atatus/metadata/cloud_info.rb +156 -0
  31. data/lib/atatus/metadata/service_info.rb +3 -3
  32. data/lib/atatus/metadata/system_info/container_info.rb +20 -8
  33. data/lib/atatus/metadata/system_info.rb +20 -5
  34. data/lib/atatus/metadata.rb +3 -1
  35. data/lib/atatus/metrics/cpu_mem_set.rb +10 -38
  36. data/lib/atatus/metrics/jvm_set.rb +88 -0
  37. data/lib/atatus/metrics/metric.rb +2 -0
  38. data/lib/atatus/metrics.rb +32 -16
  39. data/lib/atatus/middleware.rb +8 -3
  40. data/lib/atatus/naively_hashable.rb +1 -0
  41. data/lib/atatus/normalizers/rails/active_record.rb +25 -7
  42. data/lib/atatus/normalizers.rb +2 -2
  43. data/lib/atatus/opentracing.rb +5 -3
  44. data/lib/atatus/rails.rb +1 -1
  45. data/lib/atatus/span/context/db.rb +1 -1
  46. data/lib/atatus/span/context/destination.rb +58 -32
  47. data/lib/atatus/span/context/http.rb +2 -0
  48. data/lib/atatus/span/context/links.rb +32 -0
  49. data/lib/atatus/{sql.rb → span/context/message.rb} +16 -12
  50. data/lib/atatus/span/context/service.rb +55 -0
  51. data/lib/atatus/span/context.rb +28 -3
  52. data/lib/atatus/span.rb +35 -5
  53. data/lib/atatus/span_helpers.rb +12 -23
  54. data/lib/atatus/spies/action_dispatch.rb +10 -13
  55. data/lib/atatus/spies/azure_storage_table.rb +148 -0
  56. data/lib/atatus/spies/delayed_job.rb +19 -13
  57. data/lib/atatus/spies/dynamo_db.rb +56 -15
  58. data/lib/atatus/spies/elasticsearch.rb +54 -39
  59. data/lib/atatus/spies/faraday.rb +92 -58
  60. data/lib/atatus/spies/http.rb +33 -37
  61. data/lib/atatus/spies/json.rb +5 -9
  62. data/lib/atatus/spies/mongo.rb +26 -19
  63. data/lib/atatus/spies/net_http.rb +53 -51
  64. data/lib/atatus/spies/racecar.rb +77 -0
  65. data/lib/atatus/spies/rake.rb +27 -27
  66. data/lib/atatus/spies/redis.rb +11 -12
  67. data/lib/atatus/spies/resque.rb +18 -23
  68. data/lib/atatus/spies/s3.rb +132 -0
  69. data/lib/atatus/spies/sequel.rb +50 -40
  70. data/lib/atatus/spies/shoryuken.rb +4 -6
  71. data/lib/atatus/spies/sidekiq.rb +23 -31
  72. data/lib/atatus/spies/sinatra.rb +20 -28
  73. data/lib/atatus/spies/sneakers.rb +2 -0
  74. data/lib/atatus/spies/sns.rb +126 -0
  75. data/lib/atatus/spies/sqs.rb +231 -0
  76. data/lib/atatus/spies/sucker_punch.rb +20 -22
  77. data/lib/atatus/spies/tilt.rb +10 -13
  78. data/lib/atatus/spies.rb +20 -0
  79. data/lib/atatus/sql/signature.rb +4 -2
  80. data/lib/atatus/sql/tokenizer.rb +23 -7
  81. data/lib/atatus/stacktrace/frame.rb +1 -0
  82. data/lib/atatus/stacktrace_builder.rb +12 -16
  83. data/lib/atatus/subscriber.rb +1 -0
  84. data/lib/atatus/trace_context/traceparent.rb +5 -8
  85. data/lib/atatus/trace_context/tracestate.rb +16 -14
  86. data/lib/atatus/trace_context.rb +6 -16
  87. data/lib/atatus/transaction.rb +25 -4
  88. data/lib/atatus/transport/base.rb +1 -3
  89. data/lib/atatus/transport/connection/http.rb +11 -3
  90. data/lib/atatus/transport/connection/proxy_pipe.rb +1 -2
  91. data/lib/atatus/transport/connection.rb +3 -2
  92. data/lib/atatus/transport/filters/hash_sanitizer.rb +16 -34
  93. data/lib/atatus/transport/filters/secrets_filter.rb +35 -12
  94. data/lib/atatus/transport/serializers/context_serializer.rb +1 -2
  95. data/lib/atatus/transport/serializers/metadata_serializer.rb +54 -8
  96. data/lib/atatus/transport/serializers/metricset_serializer.rb +2 -2
  97. data/lib/atatus/transport/serializers/span_serializer.rb +55 -9
  98. data/lib/atatus/transport/serializers/transaction_serializer.rb +1 -0
  99. data/lib/atatus/transport/serializers.rb +9 -6
  100. data/lib/atatus/transport/user_agent.rb +16 -9
  101. data/lib/atatus/transport/worker.rb +2 -1
  102. data/lib/atatus/util/deep_dup.rb +65 -0
  103. data/lib/atatus/util/precision_validator.rb +46 -0
  104. data/lib/atatus/util.rb +2 -0
  105. data/lib/atatus/version.rb +1 -1
  106. data/lib/atatus.rb +48 -5
  107. metadata +41 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48a2777c09d7af196314fb322c9a55feadb46f50d90ffd88976ff978eb5039a2
4
- data.tar.gz: 59f1f63ebd4ad84f23359cc2c96ccb62e0c0eabceaa6b48bf63c711c3383bf64
3
+ metadata.gz: 454ba0ab877ac91b387bb0d4b3355494c2707a56634cd97774b0bcdb3e2194a6
4
+ data.tar.gz: dc8b8beca08a3a6ecc278c999d48ea7c316ac1fe8f5a221cd32df8a0bcd37262
5
5
  SHA512:
6
- metadata.gz: 1a705d56af3228c31ce400a16eae3d961fe2bbcae949db3effc4828682563bd4ce3070adb14613cb096caa48d71e8ccce2969dc21f4b0c910c73ca99b28bf566
7
- data.tar.gz: 30461593c406cf6f7b8f2e08c9bef4aa64b9f60f0f4c2b3f0bff9de1cff8a26f5cf25e07507b263e8638a37345916f15d479eb11bcb3e58f69a7f34d79d51d70
6
+ metadata.gz: 8377d4e174399b782592ce39b48ca738a806a8b881fe045cb3586cdc232d1f9d29a3f99ec02ab27cddd8c84a3c250b9bf35ac1f1bbb5f82c94a4d7fb8f7db661
7
+ data.tar.gz: 6bc01e9bec29bf52a0910abc465cbee55ca8c17dbd9bee531028d8ade630fa91517b06493c928aecfdd7cccee0bbc88cfeeff6ee143c758aec2e606d2f830367
data/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ 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.0.0 (Fri, 19 Jan 2024)
8
+
9
+ - Change the instrumentation method to prepend mode.
10
+
11
+
12
+ ## 1.7.0 (Fri, 15 Jul 2022)
13
+
14
+ - Added support for analytics.
15
+ - Fixed sequel instrumentation.
16
+
17
+
7
18
  ## 1.6.2 (Mon, 31 Jan 2022)
8
19
 
9
20
  - Fixed config environment.
data/Gemfile CHANGED
@@ -22,42 +22,50 @@ source 'https://rubygems.org'
22
22
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
23
23
 
24
24
  # Tools
25
- gem 'bootsnap', require: false
26
25
  gem 'cucumber', require: false
27
- gem 'pry'
28
26
  gem 'rack-test'
29
27
  gem 'rspec', '~> 3'
30
28
  gem 'rspec-its'
31
- gem 'rubocop', require: nil
32
- gem 'rubocop-performance', require: nil
29
+ gem 'rubocop', require: false
30
+ gem 'rubocop-performance', require: false
33
31
  gem 'timecop'
34
32
  gem 'webmock'
35
33
 
36
34
  # Integrations
37
35
  gem 'aws-sdk-dynamodb', require: nil
36
+ gem 'aws-sdk-s3', require: nil
38
37
  gem 'aws-sdk-sqs', require: nil
38
+ gem 'aws-sdk-sns', require: nil
39
+ gem 'azure-storage-table', require: nil if RUBY_VERSION < '3.0'
40
+ gem 'ecs-logging', require: 'ecs_logging/logger'
39
41
  gem 'elasticsearch', require: nil
40
42
  gem 'fakeredis', require: nil
41
43
  gem 'faraday', require: nil
42
44
  gem 'graphql', require: nil
43
- gem 'google-protobuf', '< 3.12' if !defined?(JRUBY_VERSION) && RUBY_VERSION < '2.5'
44
- gem 'grpc' if !defined?(JRUBY_VERSION)
45
+ if !defined?(JRUBY_VERSION) && RUBY_VERSION < '2.5'
46
+ gem 'google-protobuf', '< 3.12'
47
+ end
48
+ gem 'grpc' if !defined?(JRUBY_VERSION) && RUBY_VERSION < '3.0'
45
49
  gem 'json'
46
50
  gem 'json-schema', require: nil
47
51
  gem 'mongo', require: nil
48
52
  gem 'opentracing', require: nil
49
- gem 'rake', require: nil
53
+ gem 'rake', '>= 13.0', require: nil
54
+ gem 'racecar', require: nil if !defined?(JRUBY_VERSION)
50
55
  gem 'resque', require: nil
51
56
  gem 'sequel', require: nil
52
57
  gem 'shoryuken', require: nil
53
58
  gem 'sidekiq', require: nil
54
59
  gem 'simplecov', require: false
55
60
  gem 'simplecov-cobertura', require: false
56
- gem 'sneakers', '~> 2.12', require: nil
57
61
  gem 'sucker_punch', '~> 2.0', require: nil
58
62
  gem 'yard', require: nil
59
63
  gem 'yarjuf'
60
64
 
65
+ if RUBY_VERSION < '2.5'
66
+ gem 'loofah', '~> 2.20.0', require: nil
67
+ end
68
+
61
69
  ## Install Framework
62
70
  GITHUB_REPOS = {
63
71
  'grape' => 'ruby-grape/grape',
@@ -74,9 +82,15 @@ frameworks_versions = parsed_frameworks.inject({}) do |frameworks, str|
74
82
  end
75
83
 
76
84
  frameworks_versions.each do |framework, version|
85
+ if framework =='rails' && RUBY_VERSION >= '3.1'
86
+ gem 'net-smtp', require: false
87
+ end
88
+
77
89
  case version
78
- when 'master'
90
+ when 'master' # grape
79
91
  gem framework, github: GITHUB_REPOS.fetch(framework)
92
+ when 'main' # sinatra, rails
93
+ gem framework, github: GITHUB_REPOS.fetch(framework), branch: 'main'
80
94
  when /.+/
81
95
  gem framework, "~> #{version}.0"
82
96
  else
@@ -85,18 +99,40 @@ frameworks_versions.each do |framework, version|
85
99
  end
86
100
 
87
101
  if frameworks_versions.key?('rails')
88
- unless frameworks_versions['rails'] =~ /^(master|6)/
102
+ unless /^(main|6)/.match?(frameworks_versions['rails'])
89
103
  gem 'delayed_job', require: nil
90
104
  end
91
105
  end
92
106
 
93
107
  if RUBY_PLATFORM == 'java'
94
- gem 'activerecord-jdbcsqlite3-adapter'
95
- gem 'jdbc-sqlite3'
108
+ # See issue #6547 in the JRuby repo. It is fixed in JRuby 9.3
109
+ gem 'i18n', '< 1.8.8' if JRUBY_VERSION < '9.3'
110
+
111
+ case rails = frameworks_versions['rails']
112
+ when 'main'
113
+ gem 'activerecord-jdbcsqlite3-adapter', git: 'https://github.com/jruby/activerecord-jdbc-adapter', glob: 'activerecord-jdbcsqlite3-adapter/*.gemspec'
114
+ when ''
115
+ gem 'activerecord-jdbcsqlite3-adapter', "~> 61.0"
116
+ when nil
117
+ gem 'jdbc-sqlite3'
118
+ else
119
+ gem 'activerecord-jdbcsqlite3-adapter', "~> #{rails.tr('.', '')}.0"
120
+ end
96
121
  elsif frameworks_versions['rails'] =~ /^(4|5)/
97
122
  gem 'sqlite3', '~> 1.3.6'
123
+ elsif RUBY_VERSION < '2.7'
124
+ gem 'sqlite3', '~> 1.4.4'
98
125
  else
99
- gem 'sqlite3' # rubocop:disable Bundler/DuplicatedGem
126
+ gem 'sqlite3'
127
+ end
128
+
129
+ # sneakers main only supports >=2.5.0
130
+ if Gem::Version.create(RUBY_VERSION) >= Gem::Version.create('2.5.0') && !defined?(JRUBY_VERSION)
131
+ gem 'sneakers', github: 'jondot/sneakers', ref: 'd761dfe1493', require: nil
132
+ end
133
+
134
+ if Gem::Version.create(RUBY_VERSION) <= Gem::Version.create('2.5.0')
135
+ gem 'bigdecimal', '1.3.5'
100
136
  end
101
137
 
102
138
  group :bench do
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- All components of this product are Copyright (c) 2022 Atatus. All rights reserved.
1
+ All components of this product are Copyright (c) 2024 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/atatus.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
6
6
  spec.name = 'atatus'
7
7
  spec.version = Atatus::VERSION
8
8
  spec.authors = ['Atatus']
9
- spec.email = 'success@atatus.com'
9
+ spec.email = ['success@atatus.com']
10
10
 
11
11
  spec.summary = 'Atatus Ruby Agent'
12
12
  spec.homepage = 'https://www.atatus.com'
@@ -14,8 +14,7 @@ Gem::Specification.new do |spec|
14
14
  'changelog_uri' => 'https://docs.atatus.com/docs/release-notes/ruby.html',
15
15
  'documentation_uri' => 'https://docs.atatus.com/docs/application-monitoring/ruby-agent/overview.html',
16
16
  }
17
- spec.date = Time.now.strftime('%Y-%m-%d')
18
- spec.licenses = ['Atatus']
17
+ spec.license = 'Apache-2.0'
19
18
  spec.required_ruby_version = ">= 2.3.0"
20
19
  spec.extra_rdoc_files = [
21
20
  "CHANGELOG.md",
@@ -31,6 +30,7 @@ Gem::Specification.new do |spec|
31
30
 
32
31
  spec.add_dependency('concurrent-ruby', '~> 1.0')
33
32
  spec.add_dependency('http', '>= 3.0')
33
+ spec.add_runtime_dependency('ruby2_keywords')
34
34
 
35
35
  spec.require_paths = ['lib']
36
36
  end
data/lib/atatus/agent.rb CHANGED
@@ -137,7 +137,7 @@ module Atatus
137
137
  end
138
138
 
139
139
  def stop
140
- debug 'Stopping agent'
140
+ info 'Stopping agent'
141
141
 
142
142
  central_config.stop
143
143
  metrics.stop
@@ -154,7 +154,6 @@ module Atatus
154
154
  # transport
155
155
 
156
156
  def enqueue(obj)
157
- # transport.submit obj
158
157
  case obj
159
158
  when Atatus::Transaction
160
159
  collector.add_txn(obj)
@@ -164,7 +163,7 @@ module Atatus
164
163
  collector.add_error(obj)
165
164
  when Atatus::Metricset
166
165
  collector.add_metrics(obj)
167
- end
166
+ end
168
167
  end
169
168
 
170
169
  # instrumentation
@@ -231,8 +230,8 @@ module Atatus
231
230
  end
232
231
  # rubocop:enable Metrics/ParameterLists
233
232
 
234
- def end_span
235
- instrumenter.end_span
233
+ def end_span(span = nil)
234
+ instrumenter.end_span(span)
236
235
  end
237
236
 
238
237
  def set_label(key, value)
@@ -247,6 +246,18 @@ module Atatus
247
246
  instrumenter.set_user(user)
248
247
  end
249
248
 
249
+ def set_company(company)
250
+ instrumenter.set_company(company)
251
+ end
252
+
253
+ def set_response_body(response_body)
254
+ instrumenter.set_response_body(response_body)
255
+ end
256
+
257
+ def set_destination(address: nil, port: nil, service: nil, cloud: nil)
258
+ current_span&.set_destination(address: nil, port: nil, service: nil, cloud: nil)
259
+ end
260
+
250
261
  def build_context(rack_env:, for_type:)
251
262
  @context_builder.build(rack_env: rack_env, for_type: for_type)
252
263
  end
@@ -296,8 +307,8 @@ module Atatus
296
307
  def detect_forking!
297
308
  return if @pid == Process.pid
298
309
 
299
- config.logger.debug "Detected forking,
300
- restarting threads in process [PID:#{Process.pid}]"
310
+ config.logger.debug(
311
+ "Forked process detected, restarting threads in process [PID:#{Process.pid}]")
301
312
 
302
313
  central_config.handle_forking!
303
314
  collector.handle_forking!
@@ -19,6 +19,7 @@
19
19
 
20
20
  require 'atatus/central_config/cache_control'
21
21
 
22
+ # rubocop:disable Style/AccessorGrouping
22
23
  module Atatus
23
24
  # @api private
24
25
  class CentralConfig
@@ -27,6 +28,7 @@ module Atatus
27
28
  # @api private
28
29
  class ResponseError < InternalError
29
30
  def initialize(response)
31
+ super
30
32
  @response = response
31
33
  end
32
34
 
@@ -66,14 +68,15 @@ module Atatus
66
68
  def fetch_and_apply_config
67
69
  @promise =
68
70
  Concurrent::Promise
69
- .execute(&method(:fetch_config))
70
- .on_success(&method(:handle_success))
71
- .rescue(&method(:handle_error))
71
+ .execute { fetch_config }
72
+ .on_success { |resp| handle_success(resp) }
73
+ .rescue { |err| handle_error(err) }
72
74
  end
73
75
 
74
76
  def fetch_config
75
77
  resp = perform_request
76
78
 
79
+ # rubocop:disable Lint/DuplicateBranch
77
80
  case resp.status
78
81
  when 200..299
79
82
  resp
@@ -84,6 +87,7 @@ module Atatus
84
87
  when 500..599
85
88
  raise ServerError, resp
86
89
  end
90
+ # rubocop:enable Lint/DuplicateBranch
87
91
  end
88
92
 
89
93
  def assign(update)
@@ -117,14 +121,14 @@ module Atatus
117
121
  end
118
122
 
119
123
  if resp.status == 304
120
- info 'Received 304 Not Modified'
124
+ debug 'Received 304 Not Modified'
121
125
  else
122
126
  if resp.body && !resp.body.empty?
123
127
  update = JSON.parse(resp.body.to_s)
124
128
  assign(update)
125
129
  end
126
130
 
127
- if update && update.any?
131
+ if update&.any?
128
132
  info 'Updated config from Kibana'
129
133
  debug 'Modified: %s', update.inspect
130
134
  debug 'Modified original options: %s', @modified_options.inspect
@@ -162,11 +166,12 @@ module Atatus
162
166
  @server_url ||=
163
167
  config.server_url +
164
168
  '/config/v1/agents' \
165
- "?service.name=#{config.service_name}"
169
+ "?service.name=#{CGI.escape(config.service_name)}" \
170
+ "&service.environment=#{CGI.escape(config.environment || '')}"
166
171
  end
167
172
 
168
173
  def headers
169
- { 'Etag': @etag }
174
+ { 'If-None-Match': @etag }
170
175
  end
171
176
 
172
177
  def schedule_next_fetch(resp = nil)
@@ -178,9 +183,15 @@ module Atatus
178
183
  DEFAULT_MAX_AGE
179
184
  end
180
185
 
186
+ if seconds < 5
187
+ debug "Next fetch is too low (#{seconds}s) - increasing to default"
188
+ seconds = 5
189
+ end
190
+
181
191
  @scheduled_task =
182
192
  Concurrent::ScheduledTask
183
- .execute(seconds, &method(:fetch_and_apply_config))
193
+ .execute(seconds) { fetch_and_apply_config }
184
194
  end
185
195
  end
186
196
  end
197
+ # rubocop:enable Style/AccessorGrouping
@@ -42,7 +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
+
45
49
  @hostinfo_response = {}
50
+ @hostinfo_response["analytics"] = true
46
51
  @transport = Atatus::BaseTransport.new(config)
47
52
  @collect_counter = 0
48
53
  @running = false
@@ -154,6 +159,95 @@ module Atatus
154
159
  end
155
160
  end
156
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
+
157
251
  def add_span(span)
158
252
  ensure_worker_running
159
253
 
@@ -377,6 +471,13 @@ module Atatus
377
471
  end
378
472
  end
379
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
380
481
  end
381
482
  end
382
483
 
@@ -420,7 +521,6 @@ module Atatus
420
521
  @collect_counter += 1
421
522
 
422
523
  end_time = (Time.now.to_f * 1000).to_i
423
- debug '%s: data collector', pid_str
424
524
 
425
525
  txns_data = nil
426
526
  txn_hist_data = nil
@@ -429,6 +529,7 @@ module Atatus
429
529
  error_requests_data = nil
430
530
  errors_data = nil
431
531
  metrics_data = nil
532
+ analytics_data = nil
432
533
 
433
534
  @txns_lock.synchronize do
434
535
  txns_data = @txns_agg
@@ -447,6 +548,11 @@ module Atatus
447
548
  @error_requests_agg = []
448
549
  end
449
550
 
551
+ @analytics_lock.synchronize do
552
+ analytics_data = @analytics_agg
553
+ @analytics_agg = []
554
+ end
555
+
450
556
  @errors_lock.synchronize do
451
557
  errors_data = @errors_aggs
452
558
  @errors_aggs = []
@@ -473,6 +579,12 @@ module Atatus
473
579
  @transport.errors(start_time, end_time, errors_data) unless errors_data.empty?
474
580
 
475
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
476
588
  end
477
589
  end
478
590
  end
@@ -92,6 +92,14 @@ module Atatus
92
92
  payload
93
93
  end
94
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
+
95
103
  private
96
104
 
97
105
  def keyword_field(value)
@@ -33,7 +33,7 @@ module Atatus
33
33
  KINDS = {
34
34
  'db' => 'Database',
35
35
  'cache' => 'Database',
36
- 'ext' => 'Remote',
36
+ 'external' => 'Remote',
37
37
  'websocket' => 'Remote',
38
38
  'template' => 'Template'
39
39
  }.freeze
@@ -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,6 +25,12 @@ 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"
@@ -71,6 +78,11 @@ module Atatus
71
78
  post(METRIC_ENDPOINT, payload)
72
79
  end
73
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
+
74
86
  private
75
87
 
76
88
  def post(endpoint, data)
@@ -80,7 +92,12 @@ module Atatus
80
92
  end
81
93
 
82
94
  begin
83
- 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)
84
101
  uri.query = URI.encode_www_form({"license_key": @config.license_key, "agent_name": AGENT_NAME, "agent_version": VERSION})
85
102
 
86
103
  request = Net::HTTP::Post.new(uri.request_uri, @headers)
@@ -90,7 +107,7 @@ module Atatus
90
107
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
91
108
  response = http.start { |http| http.request(request) }
92
109
  rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
93
- 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)
94
111
  return
95
112
  end
96
113
 
@@ -109,6 +126,10 @@ module Atatus
109
126
 
110
127
  resp = JSON.parse response.body
111
128
  if resp
129
+ if resp.key?("analytics")
130
+ @hostinfo_response['analytics'] = resp["analytics"]
131
+ end
132
+
112
133
  if resp.key?("capturePercentiles")
113
134
  @capture_percentiles = resp["capturePercentiles"]
114
135
  @hostinfo_response['capturePercentiles'] = @capture_percentiles
@@ -17,37 +17,31 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'atatus/util/lru_cache'
21
-
22
20
  module Atatus
23
- # @api private
24
- class SqlSummarizer
25
- DEFAULT = 'SQL'
26
- TABLE_REGEX = %{["'`]?([A-Za-z0-9_]+)["'`]?}
27
-
28
- REGEXES = {
29
- /^BEGIN/iu => 'BEGIN',
30
- /^COMMIT/iu => 'COMMIT',
31
- /^SELECT .* FROM #{TABLE_REGEX}/iu => 'SELECT FROM ',
32
- /^INSERT INTO #{TABLE_REGEX}/iu => 'INSERT INTO ',
33
- /^UPDATE #{TABLE_REGEX}/iu => 'UPDATE ',
34
- /^DELETE FROM #{TABLE_REGEX}/iu => 'DELETE FROM '
35
- }.freeze
21
+ class Config
22
+ # @api private
23
+ class LogLevelMap
24
+ LEVELS = {
25
+ debug: Logger::DEBUG,
26
+ info: Logger::INFO,
27
+ warn: Logger::WARN,
28
+ error: Logger::ERROR,
29
+ fatal: Logger::FATAL,
30
+ trace: Logger::DEBUG,
31
+ warning: Logger::WARN,
32
+ critical: Logger::FATAL,
33
+ off: Logger::FATAL
34
+ }.freeze
36
35
 
37
- FORMAT = '%s%s'
38
-
39
- def self.cache
40
- @cache ||= Util::LruCache.new
41
- end
36
+ DEFAULT = Logger::INFO
42
37
 
43
- def summarize(sql)
44
- sql = sql.encode('utf-8', invalid: :replace, undef: :replace)
45
- self.class.cache[sql] ||=
46
- REGEXES.find do |regex, sig|
47
- if (match = sql[0...1000].match(regex))
48
- break format(FORMAT, sig, match[1] && match[1].gsub(/["']/, ''))
49
- end
50
- end || DEFAULT
38
+ def call(value)
39
+ if value.is_a?(Integer)
40
+ LEVELS.value?(value) ? value : DEFAULT
41
+ else
42
+ LEVELS.fetch(value.to_sym, DEFAULT)
43
+ end
44
+ end
51
45
  end
52
46
  end
53
47
  end
@@ -38,7 +38,8 @@ module Atatus
38
38
  set(value || default)
39
39
  end
40
40
 
41
- attr_reader :key, :value, :default, :type
41
+ attr_reader :key, :default, :type, :converter
42
+ attr_accessor :value
42
43
 
43
44
  def set(value)
44
45
  @value = normalize(value)
@@ -23,7 +23,7 @@ module Atatus
23
23
  class RegexpList
24
24
  def call(value)
25
25
  value = value.is_a?(String) ? value.split(',') : Array(value)
26
- value.map(&Regexp.method(:new))
26
+ value.map { |p| Regexp.new(p) }
27
27
  end
28
28
  end
29
29
  end