atatus 1.6.2 → 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 (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