atatus 2.0.3 → 2.1.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/atatus/collector/base.rb +66 -7
- data/lib/atatus/collector/builder.rb +15 -5
- data/lib/atatus/collector/compress_body.rb +14 -0
- data/lib/atatus/collector/transport.rb +62 -28
- data/lib/atatus/config/error_limit_converter.rb +17 -0
- data/lib/atatus/config/log_level_map.rb +1 -0
- data/lib/atatus/config/options.rb +11 -2
- data/lib/atatus/config/wildcard_pattern_list.rb +38 -3
- data/lib/atatus/config.rb +12 -3
- data/lib/atatus/logging.rb +30 -2
- data/lib/atatus/metadata/system_info/container_info.rb +33 -1
- data/lib/atatus/metadata/system_info/hw_info.rb +1 -1
- data/lib/atatus/transport/connection/http.rb +2 -2
- data/lib/atatus/transport/connection.rb +6 -1
- data/lib/atatus/transport/serializers/span_serializer.rb +4 -2
- data/lib/atatus/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e583b9f10ae2db24b5ffedfe79959daf38c6b1b947a0cb71ddcf2fb1005e6495
|
|
4
|
+
data.tar.gz: 5db30ee5dd57494608263eeb2b45943a81dbd5eb8bce84a8e19fecad49ba2650
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e88330ad4178a8b991792e2c518e2b4b4d9144508365953b8e2528fad479b01fe6d445487adf3d00c31315119ecab8a146b673145fd6cc76dda9b57ed145f03
|
|
7
|
+
data.tar.gz: f522a2e7f232b8892b7f8a4a07a36c39fa982a4cad992c3e4edd7ef7100b7a0df2309876670f4e5f17e391703170f4a9ddd9184447c8354de05bc5e1ebf5dca1
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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.1.0 (Wed, 7 Jan 2026)
|
|
8
|
+
|
|
9
|
+
- Fixed host details fetching issue in docker.
|
|
10
|
+
- Added support for distributed tracing.
|
|
11
|
+
- Added support for server url.
|
|
12
|
+
|
|
13
|
+
|
|
7
14
|
## 2.0.3 (Wed, 16 Oct 2024)
|
|
8
15
|
|
|
9
16
|
- Fixed Action Dispatch exception handler failure in Rails 7.1
|
|
@@ -6,6 +6,7 @@ require 'atatus/transaction'
|
|
|
6
6
|
require 'atatus/collector/hist'
|
|
7
7
|
require 'atatus/collector/layer'
|
|
8
8
|
require 'atatus/collector/transport'
|
|
9
|
+
require 'atatus/transport/base'
|
|
9
10
|
|
|
10
11
|
SpanTiming = Struct.new(:name, :type, :subtype, :start, :end, :duration, :id, :transaction_id)
|
|
11
12
|
|
|
@@ -27,6 +28,8 @@ module Atatus
|
|
|
27
28
|
def initialize(config)
|
|
28
29
|
# info 'Initializing Collector'
|
|
29
30
|
@config = config
|
|
31
|
+
initialize_server_urls
|
|
32
|
+
|
|
30
33
|
@spans = Hash.new {|h,k| h[k]=[]}
|
|
31
34
|
|
|
32
35
|
@txns_lock = Mutex.new
|
|
@@ -38,6 +41,7 @@ module Atatus
|
|
|
38
41
|
|
|
39
42
|
@errors_lock = Mutex.new
|
|
40
43
|
@errors_aggs = []
|
|
44
|
+
@error_limit = 20
|
|
41
45
|
|
|
42
46
|
@metrics_lock = Mutex.new
|
|
43
47
|
@metrics_agg = []
|
|
@@ -48,9 +52,39 @@ module Atatus
|
|
|
48
52
|
|
|
49
53
|
@hostinfo_response = {}
|
|
50
54
|
@hostinfo_response["analytics"] = true
|
|
51
|
-
@transport = Atatus::BaseTransport.new(config)
|
|
55
|
+
@transport = Atatus::BaseTransport.new(@config)
|
|
56
|
+
@dt_transport = Atatus::Transport::Base.new(@config)
|
|
52
57
|
@collect_counter = 0
|
|
53
58
|
@running = false
|
|
59
|
+
|
|
60
|
+
@transaction_ignore_urls = @config.transaction_ignore_urls.dup
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def initialize_server_urls
|
|
64
|
+
url = nil
|
|
65
|
+
|
|
66
|
+
if @config.notify_host != "https://apm-rx.atatus.com"
|
|
67
|
+
url = @config.notify_host
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if @config.server_url != ''
|
|
71
|
+
url = @config.server_url
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if url
|
|
75
|
+
if @config.apm_server_url == "https://apm-rx.atatus.com"
|
|
76
|
+
@config.apm_server_url = url
|
|
77
|
+
end
|
|
78
|
+
if @config.analytics_server_url == "https://an-rx.atatus.com"
|
|
79
|
+
@config.analytics_server_url = url
|
|
80
|
+
end
|
|
81
|
+
if @config.traces_server_url == "https://dt-rx.atatus.com"
|
|
82
|
+
@config.traces_server_url = url
|
|
83
|
+
end
|
|
84
|
+
if @config.logs_server_url == "https://log-rx.atatus.com"
|
|
85
|
+
@config.logs_server_url = url
|
|
86
|
+
end
|
|
87
|
+
end
|
|
54
88
|
end
|
|
55
89
|
|
|
56
90
|
attr_reader :config
|
|
@@ -60,6 +94,7 @@ module Atatus
|
|
|
60
94
|
end
|
|
61
95
|
|
|
62
96
|
def start
|
|
97
|
+
@dt_transport.start
|
|
63
98
|
debug '%s: Starting collector', pid_str
|
|
64
99
|
|
|
65
100
|
ensure_worker_running
|
|
@@ -67,6 +102,7 @@ module Atatus
|
|
|
67
102
|
|
|
68
103
|
def stop
|
|
69
104
|
return unless @running
|
|
105
|
+
@dt_transport.stop
|
|
70
106
|
@running = false
|
|
71
107
|
if worker_active?
|
|
72
108
|
debug '%s: Waiting for collector worker to exit', pid_str
|
|
@@ -81,6 +117,7 @@ module Atatus
|
|
|
81
117
|
def handle_forking!
|
|
82
118
|
stop
|
|
83
119
|
start
|
|
120
|
+
@dt_transport.handle_forking!
|
|
84
121
|
end
|
|
85
122
|
|
|
86
123
|
def add_error(error)
|
|
@@ -93,7 +130,7 @@ module Atatus
|
|
|
93
130
|
then
|
|
94
131
|
if @hostinfo_response.key?("ignoreExceptionPatterns")
|
|
95
132
|
@hostinfo_response['ignoreExceptionPatterns'].each do |k, v|
|
|
96
|
-
if error.exception.type
|
|
133
|
+
if k.match(error.exception.type)
|
|
97
134
|
exception_values = v
|
|
98
135
|
if exception_values.length == 0
|
|
99
136
|
ignore_error = true
|
|
@@ -111,10 +148,10 @@ module Atatus
|
|
|
111
148
|
end
|
|
112
149
|
if ignore_error == false
|
|
113
150
|
@errors_lock.synchronize do
|
|
114
|
-
if @errors_aggs.length <
|
|
151
|
+
if @errors_aggs.length < @error_limit
|
|
115
152
|
@errors_aggs.push(error)
|
|
116
153
|
else
|
|
117
|
-
i = rand(
|
|
154
|
+
i = rand(@error_limit)
|
|
118
155
|
@errors_aggs[i] = error
|
|
119
156
|
end
|
|
120
157
|
end
|
|
@@ -249,6 +286,15 @@ module Atatus
|
|
|
249
286
|
end
|
|
250
287
|
|
|
251
288
|
def add_span(span)
|
|
289
|
+
|
|
290
|
+
if @hostinfo_response.key?("tracing")
|
|
291
|
+
if @hostinfo_response["tracing"] == true && @config.tracing == true
|
|
292
|
+
if @hostinfo_response["performance"] && @config.performance
|
|
293
|
+
@dt_transport.submit(span)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
252
298
|
ensure_worker_running
|
|
253
299
|
|
|
254
300
|
if
|
|
@@ -265,6 +311,15 @@ module Atatus
|
|
|
265
311
|
end
|
|
266
312
|
|
|
267
313
|
def add_txn(txn)
|
|
314
|
+
|
|
315
|
+
if @hostinfo_response.key?("tracing")
|
|
316
|
+
if @hostinfo_response["tracing"] == true && @config.tracing == true
|
|
317
|
+
if @hostinfo_response["performance"] && @config.performance
|
|
318
|
+
@dt_transport.submit(txn)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
268
323
|
ensure_worker_running
|
|
269
324
|
|
|
270
325
|
if
|
|
@@ -279,7 +334,7 @@ module Atatus
|
|
|
279
334
|
ignore_txn = false
|
|
280
335
|
if @hostinfo_response.key?("ignoreTxnNamePatterns")
|
|
281
336
|
@hostinfo_response['ignoreTxnNamePatterns'].each do |k|
|
|
282
|
-
if txn.name
|
|
337
|
+
if k.match(txn.name)
|
|
283
338
|
ignore_txn = true
|
|
284
339
|
break
|
|
285
340
|
end
|
|
@@ -433,7 +488,7 @@ module Atatus
|
|
|
433
488
|
if status_code >= 400 && status_code != 404
|
|
434
489
|
if @hostinfo_response.key?("ignoreHTTPFailurePatterns")
|
|
435
490
|
@hostinfo_response['ignoreHTTPFailurePatterns'].each do |k, v|
|
|
436
|
-
if txn.name
|
|
491
|
+
if k.match(txn.name)
|
|
437
492
|
status_code_array_s = v
|
|
438
493
|
if status_code_array_s.length == 0
|
|
439
494
|
ignore_status_code = true
|
|
@@ -490,8 +545,8 @@ module Atatus
|
|
|
490
545
|
|
|
491
546
|
while @running
|
|
492
547
|
start_time = (Time.now.to_f * 1000).to_i
|
|
493
|
-
sleep(60)
|
|
494
548
|
collect start_time
|
|
549
|
+
sleep(60)
|
|
495
550
|
end
|
|
496
551
|
end
|
|
497
552
|
end
|
|
@@ -516,6 +571,10 @@ module Atatus
|
|
|
516
571
|
|
|
517
572
|
if @collect_counter % 30 == 0
|
|
518
573
|
@hostinfo_response = @transport.hostinfo(start_time)
|
|
574
|
+
@config.transaction_ignore_urls = @transaction_ignore_urls | @hostinfo_response["ignoreTxnUrlPatterns"]
|
|
575
|
+
if @hostinfo_response.key?("errorLimit")
|
|
576
|
+
@error_limit = @hostinfo_response["errorLimit"]
|
|
577
|
+
end
|
|
519
578
|
@collect_counter = 0
|
|
520
579
|
end
|
|
521
580
|
@collect_counter += 1
|
|
@@ -131,14 +131,24 @@ module Atatus
|
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
def build_hostinfo_env_settings()
|
|
134
|
-
{
|
|
134
|
+
settings = {
|
|
135
135
|
agentVersion: VERSION,
|
|
136
|
-
appName: @config.app_name,
|
|
137
|
-
framework: @config.framework_name,
|
|
138
|
-
frameworkVersion: @config.framework_version,
|
|
139
|
-
logLevel: @config.log_level,
|
|
140
136
|
ruby: RUBY_VERSION
|
|
141
137
|
}
|
|
138
|
+
|
|
139
|
+
@config.options.each do |key, opt|
|
|
140
|
+
value = opt.value
|
|
141
|
+
|
|
142
|
+
next if value.nil? ||
|
|
143
|
+
value == "" ||
|
|
144
|
+
(value.respond_to?(:empty?) && value.empty?)
|
|
145
|
+
|
|
146
|
+
settings[key] = value
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
settings.delete(:license_key)
|
|
150
|
+
settings.delete(:sanitize_field_names)
|
|
151
|
+
settings
|
|
142
152
|
end
|
|
143
153
|
|
|
144
154
|
def build_hostinfo_gems()
|
|
@@ -2,6 +2,8 @@ require 'json'
|
|
|
2
2
|
require 'thread'
|
|
3
3
|
require 'net/http'
|
|
4
4
|
require 'atatus/collector/builder'
|
|
5
|
+
require 'atatus/config/wildcard_pattern_list'
|
|
6
|
+
require 'atatus/collector/compress_body'
|
|
5
7
|
|
|
6
8
|
module Atatus
|
|
7
9
|
class BaseTransport
|
|
@@ -19,25 +21,21 @@ module Atatus
|
|
|
19
21
|
def initialize(config)
|
|
20
22
|
@config = config
|
|
21
23
|
|
|
22
|
-
@
|
|
23
|
-
|
|
24
|
-
if not uri.kind_of?(URI::HTTPS) and not uri.kind_of?(URI::HTTP)
|
|
25
|
-
@notify_host = "https://apm-rx.atatus.com"
|
|
26
|
-
end
|
|
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
|
|
24
|
+
@apm_server_url = @config.apm_server_url
|
|
25
|
+
@analytics_server_url = @config.analytics_server_url
|
|
33
26
|
|
|
34
27
|
@builder = Atatus::Builder.new(config)
|
|
35
28
|
@headers = {}
|
|
36
29
|
@headers['Content-Type'] = "application/json"
|
|
30
|
+
@headers['Content-Encoding'] = "gzip"
|
|
37
31
|
|
|
38
32
|
@blocked = false
|
|
39
33
|
@capture_percentiles = false
|
|
40
34
|
@hostinfo_response = {}
|
|
35
|
+
@wildcard_pattern_factory = Config::WildcardPatternList.new
|
|
36
|
+
|
|
37
|
+
@http_transport = Transport::Connection::Http.new(@config, headers: @headers)
|
|
38
|
+
@compressor = Compress.new
|
|
41
39
|
end
|
|
42
40
|
|
|
43
41
|
def hostinfo(start_time)
|
|
@@ -47,11 +45,15 @@ module Atatus
|
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
def txns(start_time, end_time, data)
|
|
48
|
+
return unless @hostinfo_response["performance"] && @config.performance
|
|
49
|
+
|
|
50
50
|
payload = @builder.txns(start_time, end_time, data)
|
|
51
51
|
post(TXN_ENDPOINT, payload)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def txn_hist(start_time, end_time, data)
|
|
55
|
+
return unless @hostinfo_response["performance"] && @config.performance
|
|
56
|
+
|
|
55
57
|
if @capture_percentiles == true
|
|
56
58
|
payload = @builder.txn_hist(start_time, end_time, data)
|
|
57
59
|
post(TXN_HIST_ENDPOINT, payload)
|
|
@@ -59,11 +61,15 @@ module Atatus
|
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
def traces(start_time, end_time, data)
|
|
64
|
+
return unless @hostinfo_response["performance"] && @config.performance
|
|
65
|
+
|
|
62
66
|
payload = @builder.traces(start_time, end_time, data)
|
|
63
67
|
post(TRACE_ENDPOINT, payload)
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
def error_metrics(start_time, end_time, metrics_data, requests_data)
|
|
71
|
+
return unless @hostinfo_response["performance"] && @config.performance
|
|
72
|
+
|
|
67
73
|
payload = @builder.error_metrics(start_time, end_time, metrics_data, requests_data)
|
|
68
74
|
post(ERROR_METRIC_ENDPOINT, payload)
|
|
69
75
|
end
|
|
@@ -74,6 +80,8 @@ module Atatus
|
|
|
74
80
|
end
|
|
75
81
|
|
|
76
82
|
def metrics(start_time, end_time, metric_data)
|
|
83
|
+
return unless @hostinfo_response["performance"] && @config.performance
|
|
84
|
+
|
|
77
85
|
payload = @builder.metrics(start_time, end_time, metric_data)
|
|
78
86
|
post(METRIC_ENDPOINT, payload)
|
|
79
87
|
end
|
|
@@ -86,28 +94,30 @@ module Atatus
|
|
|
86
94
|
private
|
|
87
95
|
|
|
88
96
|
def post(endpoint, data)
|
|
89
|
-
|
|
97
|
+
|
|
90
98
|
if @blocked == true and endpoint != HOSTINFO_ENDPOINT
|
|
99
|
+
debug "Client blocked"
|
|
91
100
|
return
|
|
92
101
|
end
|
|
93
102
|
|
|
94
103
|
begin
|
|
95
|
-
|
|
104
|
+
server_url = @apm_server_url
|
|
96
105
|
if endpoint == ANALYTICS_ENDPOINT
|
|
97
|
-
|
|
106
|
+
server_url = @analytics_server_url
|
|
98
107
|
end
|
|
99
108
|
|
|
100
|
-
uri = URI(
|
|
109
|
+
uri = URI(server_url + endpoint)
|
|
101
110
|
uri.query = URI.encode_www_form({"license_key": @config.license_key, "agent_name": AGENT_NAME, "agent_version": VERSION})
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
response =
|
|
112
|
+
verbose "Sending data to #{uri}"
|
|
113
|
+
verbose "Payload: #{::JSON.pretty_generate(data, :max_nesting => false)}"
|
|
114
|
+
|
|
115
|
+
compressed_body = @compressor.compress(::JSON.generate(data))
|
|
116
|
+
headers_new = @headers.merge('Content-Length' => compressed_body.bytesize.to_s)
|
|
117
|
+
response = @http_transport.post(uri, body: compressed_body, headers: headers_new)
|
|
118
|
+
|
|
109
119
|
rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
|
|
110
|
-
error format('Atatus transport [%s%s] failed with exception: %s',
|
|
120
|
+
error format('Atatus transport [%s%s] failed with exception: %s', server_url, endpoint, e.message)
|
|
111
121
|
return
|
|
112
122
|
end
|
|
113
123
|
|
|
@@ -115,8 +125,8 @@ module Atatus
|
|
|
115
125
|
@blocked = false
|
|
116
126
|
end
|
|
117
127
|
|
|
118
|
-
case response
|
|
119
|
-
when
|
|
128
|
+
case response.status
|
|
129
|
+
when 200
|
|
120
130
|
if endpoint == HOSTINFO_ENDPOINT
|
|
121
131
|
@capture_percentiles = false
|
|
122
132
|
|
|
@@ -125,11 +135,16 @@ module Atatus
|
|
|
125
135
|
end
|
|
126
136
|
|
|
127
137
|
resp = JSON.parse response.body
|
|
138
|
+
|
|
128
139
|
if resp
|
|
129
140
|
if resp.key?("analytics")
|
|
130
141
|
@hostinfo_response['analytics'] = resp["analytics"]
|
|
131
142
|
end
|
|
132
143
|
|
|
144
|
+
if resp.key?("tracing")
|
|
145
|
+
@hostinfo_response['tracing'] = resp["tracing"]
|
|
146
|
+
end
|
|
147
|
+
|
|
133
148
|
if resp.key?("capturePercentiles")
|
|
134
149
|
@capture_percentiles = resp["capturePercentiles"]
|
|
135
150
|
@hostinfo_response['capturePercentiles'] = @capture_percentiles
|
|
@@ -138,24 +153,43 @@ module Atatus
|
|
|
138
153
|
if resp.key?("extRequestPatterns")
|
|
139
154
|
@hostinfo_response['extRequestPatterns'] = resp["extRequestPatterns"]
|
|
140
155
|
end
|
|
156
|
+
|
|
157
|
+
if resp.key?("ignoreTxnUrlPatterns")
|
|
158
|
+
@hostinfo_response['ignoreTxnUrlPatterns'] = resp["ignoreTxnUrlPatterns"]
|
|
159
|
+
else
|
|
160
|
+
@hostinfo_response['ignoreTxnUrlPatterns'] = []
|
|
161
|
+
end
|
|
141
162
|
|
|
142
163
|
if resp.key?("ignoreTxnNamePatterns")
|
|
143
|
-
@hostinfo_response['ignoreTxnNamePatterns'] = resp["ignoreTxnNamePatterns"]
|
|
164
|
+
@hostinfo_response['ignoreTxnNamePatterns'] = @wildcard_pattern_factory.call(resp["ignoreTxnNamePatterns"])
|
|
144
165
|
end
|
|
145
166
|
|
|
146
167
|
if resp.key?("ignoreHTTPFailurePatterns")
|
|
147
|
-
@hostinfo_response['ignoreHTTPFailurePatterns'] = resp["ignoreHTTPFailurePatterns"]
|
|
168
|
+
@hostinfo_response['ignoreHTTPFailurePatterns'] = @wildcard_pattern_factory.call(resp["ignoreHTTPFailurePatterns"])
|
|
148
169
|
end
|
|
149
170
|
|
|
150
171
|
if resp.key?("ignoreExceptionPatterns")
|
|
151
|
-
@hostinfo_response['ignoreExceptionPatterns'] = resp["ignoreExceptionPatterns"]
|
|
172
|
+
@hostinfo_response['ignoreExceptionPatterns'] = @wildcard_pattern_factory.call(resp["ignoreExceptionPatterns"])
|
|
152
173
|
end
|
|
153
174
|
|
|
175
|
+
if resp.key?("performance")
|
|
176
|
+
@hostinfo_response['performance'] = resp["performance"]
|
|
177
|
+
else
|
|
178
|
+
@hostinfo_response['performance'] = true
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
if resp.key?("errorLimit") and resp["errorLimit"].is_a?(Integer)
|
|
182
|
+
if resp["errorLimit"] < 20
|
|
183
|
+
@hostinfo_response['errorLimit'] = 20
|
|
184
|
+
else
|
|
185
|
+
@hostinfo_response['errorLimit'] = resp["errorLimit"]
|
|
186
|
+
end
|
|
187
|
+
end
|
|
154
188
|
end
|
|
155
189
|
else
|
|
156
190
|
true
|
|
157
191
|
end
|
|
158
|
-
when
|
|
192
|
+
when 400..499
|
|
159
193
|
if not response.body
|
|
160
194
|
error format('Transport status 400, failed without content')
|
|
161
195
|
return
|
|
@@ -90,8 +90,17 @@ module Atatus
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def normalize_url(val)
|
|
93
|
-
val
|
|
94
|
-
|
|
93
|
+
if key.to_s == "server_url" and val == ""
|
|
94
|
+
return ""
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
uri = URI(val)
|
|
98
|
+
|
|
99
|
+
if not uri.kind_of?(URI::HTTPS) and not uri.kind_of?(URI::HTTP)
|
|
100
|
+
raise InternalError, "Invalid URL for #{key}: #{val}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
uri.to_s.chomp('/')
|
|
95
104
|
end
|
|
96
105
|
end
|
|
97
106
|
|
|
@@ -33,6 +33,12 @@ module Atatus
|
|
|
33
33
|
!!@pattern.match(other)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def ==(other)
|
|
37
|
+
other.is_a?(WildcardPattern) && @pattern == other.pattern
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias eql? ==
|
|
41
|
+
|
|
36
42
|
alias :match :match?
|
|
37
43
|
|
|
38
44
|
private
|
|
@@ -55,11 +61,40 @@ module Atatus
|
|
|
55
61
|
case_sensitive ? nil : Regexp::IGNORECASE
|
|
56
62
|
)
|
|
57
63
|
end
|
|
58
|
-
end
|
|
64
|
+
end
|
|
59
65
|
|
|
60
66
|
def call(value)
|
|
61
|
-
|
|
62
|
-
value.
|
|
67
|
+
hash = false
|
|
68
|
+
if value.is_a?(Hash)
|
|
69
|
+
hash = true
|
|
70
|
+
elsif value.is_a?(String)
|
|
71
|
+
value = value.split(',')
|
|
72
|
+
else
|
|
73
|
+
value = Array(value)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if !hash
|
|
77
|
+
value = value.map do |p|
|
|
78
|
+
if p.is_a?(WildcardPattern)
|
|
79
|
+
p
|
|
80
|
+
else
|
|
81
|
+
begin
|
|
82
|
+
WildcardPattern.new(p)
|
|
83
|
+
rescue RegexpError
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
else
|
|
90
|
+
new_hash = {}
|
|
91
|
+
value = value.map do |k, v|
|
|
92
|
+
new_hash[WildcardPattern.new(k)] = v
|
|
93
|
+
end
|
|
94
|
+
value = new_hash
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
value.uniq.compact
|
|
63
98
|
end
|
|
64
99
|
end
|
|
65
100
|
end
|
data/lib/atatus/config.rb
CHANGED
|
@@ -26,6 +26,7 @@ require 'atatus/config/regexp_list'
|
|
|
26
26
|
require 'atatus/config/wildcard_pattern_list'
|
|
27
27
|
require 'atatus/deprecations'
|
|
28
28
|
require 'atatus/config/server_info'
|
|
29
|
+
require 'atatus/config/error_limit_converter'
|
|
29
30
|
|
|
30
31
|
module Atatus
|
|
31
32
|
# @api private
|
|
@@ -39,12 +40,17 @@ module Atatus
|
|
|
39
40
|
# rubocop:disable Layout/LineLength, Layout/ExtraSpacing
|
|
40
41
|
option :app_name, type: :string
|
|
41
42
|
option :license_key, type: :string
|
|
42
|
-
option :notify_host, type: :
|
|
43
|
-
option :analytics_notify_host, type: :
|
|
43
|
+
option :notify_host, type: :url, default: 'https://apm-rx.atatus.com'
|
|
44
|
+
option :analytics_notify_host, type: :url, default: 'https://an-rx.atatus.com'
|
|
44
45
|
option :trace_threshold, type: :int, default: 2000
|
|
45
46
|
option :analytics, type: :bool, default: false
|
|
47
|
+
option :tracing, type: :bool, default: false
|
|
46
48
|
option :config_file, type: :string, default: 'config/atatus.yml'
|
|
47
49
|
option :server_url, type: :url, default: ''
|
|
50
|
+
option :apm_server_url, type: :url, default: 'https://apm-rx.atatus.com'
|
|
51
|
+
option :analytics_server_url, type: :url, default: 'https://an-rx.atatus.com'
|
|
52
|
+
option :traces_server_url, type: :url, default: 'https://dt-rx.atatus.com'
|
|
53
|
+
option :logs_server_url, type: :url, default: 'https://log-rx.atatus.com'
|
|
48
54
|
option :secret_token, type: :string
|
|
49
55
|
option :api_key, type: :string
|
|
50
56
|
|
|
@@ -105,8 +111,11 @@ module Atatus
|
|
|
105
111
|
option :transaction_ignore_urls, type: :list, default: [], converter: WildcardPatternList.new
|
|
106
112
|
option :transaction_max_spans, type: :int, default: 500
|
|
107
113
|
option :transaction_sample_rate, type: :float, default: 1.0, converter: RoundFloat.new
|
|
108
|
-
option :use_atatus_traceparent_header,
|
|
114
|
+
option :use_atatus_traceparent_header, type: :bool, default: true
|
|
109
115
|
option :verify_server_cert, type: :bool, default: true
|
|
116
|
+
# option :error_limit, type: :int, default: 20, converter: ErrorLimitConverter.new
|
|
117
|
+
option :performance, type: :bool, default: true
|
|
118
|
+
|
|
110
119
|
|
|
111
120
|
def log_ecs_formatting
|
|
112
121
|
log_ecs_reformatting
|
data/lib/atatus/logging.rb
CHANGED
|
@@ -14,6 +14,25 @@
|
|
|
14
14
|
# KIND, either express or implied. See the License for the
|
|
15
15
|
# specific language governing permissions and limitations
|
|
16
16
|
# under the License.
|
|
17
|
+
require 'logger'
|
|
18
|
+
|
|
19
|
+
class Logger
|
|
20
|
+
module Severity
|
|
21
|
+
VERBOSE = -1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def format_severity(severity)
|
|
25
|
+
if severity == Severity::VERBOSE
|
|
26
|
+
'VERBOSE'
|
|
27
|
+
else
|
|
28
|
+
SEV_LABEL[severity] || 'ANY'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verbose(progname = nil, &block)
|
|
33
|
+
add(Severity::VERBOSE, nil, progname, &block)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
17
36
|
|
|
18
37
|
# frozen_string_literal: true
|
|
19
38
|
|
|
@@ -23,6 +42,7 @@ module Atatus
|
|
|
23
42
|
PREFIX = '[Atatus] '
|
|
24
43
|
|
|
25
44
|
LEVELS = {
|
|
45
|
+
verbose: Logger::VERBOSE,
|
|
26
46
|
debug: Logger::DEBUG,
|
|
27
47
|
info: Logger::INFO,
|
|
28
48
|
warn: Logger::WARN,
|
|
@@ -30,6 +50,10 @@ module Atatus
|
|
|
30
50
|
fatal: Logger::FATAL
|
|
31
51
|
}.freeze
|
|
32
52
|
|
|
53
|
+
def verbose(msg, *args, &block)
|
|
54
|
+
log(:verbose, msg, *args, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
33
57
|
def debug(msg, *args, &block)
|
|
34
58
|
log(:debug, msg, *args, &block)
|
|
35
59
|
end
|
|
@@ -55,8 +79,12 @@ module Atatus
|
|
|
55
79
|
def log(lvl, msg, *args)
|
|
56
80
|
return unless (logger = @config&.logger)
|
|
57
81
|
return unless LEVELS[lvl] >= (@config&.log_level || 0)
|
|
58
|
-
|
|
59
|
-
|
|
82
|
+
|
|
83
|
+
if not args.length == 0
|
|
84
|
+
formatted_msg = prepend_prefix(format(msg.to_s, *args))
|
|
85
|
+
else
|
|
86
|
+
formatted_msg = prepend_prefix(msg.to_s)
|
|
87
|
+
end
|
|
60
88
|
|
|
61
89
|
return logger.send(lvl, formatted_msg) unless block_given?
|
|
62
90
|
|
|
@@ -23,6 +23,7 @@ module Atatus
|
|
|
23
23
|
# @api private
|
|
24
24
|
class ContainerInfo
|
|
25
25
|
CGROUP_PATH = '/proc/self/cgroup'
|
|
26
|
+
MOUNTINFO_PATH = '/proc/self/mountinfo'
|
|
26
27
|
|
|
27
28
|
attr_accessor :container_id, :kubernetes_namespace,
|
|
28
29
|
:kubernetes_node_name, :kubernetes_pod_name, :kubernetes_pod_uid
|
|
@@ -34,7 +35,9 @@ module Atatus
|
|
|
34
35
|
attr_reader :cgroup_path
|
|
35
36
|
|
|
36
37
|
def read!(hostname)
|
|
37
|
-
|
|
38
|
+
read_from_mountinfo!
|
|
39
|
+
read_from_cgroup! unless container_id && kubernetes_pod_uid
|
|
40
|
+
|
|
38
41
|
self.kubernetes_pod_name = hostname if kubernetes_pod_uid
|
|
39
42
|
read_from_env!
|
|
40
43
|
self
|
|
@@ -98,8 +101,37 @@ module Atatus
|
|
|
98
101
|
}x
|
|
99
102
|
].freeze
|
|
100
103
|
SYSTEMD_SCOPE_SUFFIX = '.scope'
|
|
104
|
+
|
|
105
|
+
CONTAINER_ID_V2_REGEX = %r{
|
|
106
|
+
([[:xdigit:]]{64}|
|
|
107
|
+
[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4,})
|
|
108
|
+
}x.freeze
|
|
109
|
+
|
|
110
|
+
POD_UID_V2_REGEX = %r{/kubelet/pods/([[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4,})}.freeze
|
|
111
|
+
|
|
101
112
|
# rubocop:enable Style/RegexpLiteral
|
|
102
113
|
|
|
114
|
+
def read_from_mountinfo!
|
|
115
|
+
return unless File.exist?(MOUNTINFO_PATH)
|
|
116
|
+
|
|
117
|
+
IO.readlines(MOUNTINFO_PATH).each do |line|
|
|
118
|
+
if line.include?('/etc/hostname')
|
|
119
|
+
parts = line.split(' ')
|
|
120
|
+
if parts.length > 3
|
|
121
|
+
if (match = CONTAINER_ID_V2_REGEX.match(parts[3]))
|
|
122
|
+
self.container_id = match[1]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
if (match = POD_UID_V2_REGEX.match(line))
|
|
128
|
+
self.kubernetes_pod_uid = match[1] if match.size > 1
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
break if container_id && kubernetes_pod_uid
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
103
135
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
104
136
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
105
137
|
def read_from_cgroup!
|
|
@@ -81,7 +81,7 @@ module Atatus
|
|
|
81
81
|
return unless File.exist?(LINUX_CPUINFO_PATH)
|
|
82
82
|
cpuinfo = File.read(LINUX_CPUINFO_PATH)
|
|
83
83
|
self.cpuinfo_cores = cpuinfo.scan(PROCESSOR_COUNT_REGEX).size
|
|
84
|
-
self.cpuinfo_model = cpuinfo.scan(MODEL_NAME_REGEX).flatten.first
|
|
84
|
+
self.cpuinfo_model = cpuinfo.scan(MODEL_NAME_REGEX).flatten.first&.strip
|
|
85
85
|
self.cpuinfo_mhz = cpuinfo.scan(CPU_MHZ_REGEX).flatten.first
|
|
86
86
|
end
|
|
87
87
|
# rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
@@ -116,8 +116,8 @@ module Atatus
|
|
|
116
116
|
begin
|
|
117
117
|
resp = post(url, body: @rd, headers: @headers.chunked.to_h)
|
|
118
118
|
|
|
119
|
-
if resp&.status ==
|
|
120
|
-
debug 'APM Server responded with status
|
|
119
|
+
if resp&.status == 200
|
|
120
|
+
debug 'APM Server responded with status 200'
|
|
121
121
|
elsif resp
|
|
122
122
|
error "APM Server responded with an error:\n%p", resp.body.to_s
|
|
123
123
|
end
|
|
@@ -42,7 +42,12 @@ module Atatus
|
|
|
42
42
|
Metadata.new(config)
|
|
43
43
|
)
|
|
44
44
|
)
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
uri = URI(@config.traces_server_url + "/track/traces/spans")
|
|
47
|
+
uri.query = URI.encode_www_form({"license_key": @config.license_key, "agent_name": AGENT_NAME, "agent_version": VERSION, "app_name": @config.app_name})
|
|
48
|
+
|
|
49
|
+
@url = uri
|
|
50
|
+
|
|
46
51
|
@mutex = Mutex.new
|
|
47
52
|
end
|
|
48
53
|
|
|
@@ -30,14 +30,16 @@ module Atatus
|
|
|
30
30
|
|
|
31
31
|
attr_reader :context_serializer
|
|
32
32
|
|
|
33
|
-
def build(span)
|
|
33
|
+
def build(span)
|
|
34
34
|
{
|
|
35
35
|
span: {
|
|
36
36
|
id: span.id,
|
|
37
37
|
transaction_id: span.transaction.id,
|
|
38
38
|
parent_id: span.parent_id,
|
|
39
39
|
name: keyword_field(span.name),
|
|
40
|
-
type:
|
|
40
|
+
type: keyword_field(span.type),
|
|
41
|
+
subtype: keyword_field(span.subtype),
|
|
42
|
+
action: keyword_field(span.action),
|
|
41
43
|
duration: ms(span.duration),
|
|
42
44
|
context: context_serializer.build(span.context),
|
|
43
45
|
stacktrace: span.stacktrace.to_a,
|
data/lib/atatus/version.rb
CHANGED
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: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Atatus
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -79,12 +79,14 @@ files:
|
|
|
79
79
|
- lib/atatus/child_durations.rb
|
|
80
80
|
- lib/atatus/collector/base.rb
|
|
81
81
|
- lib/atatus/collector/builder.rb
|
|
82
|
+
- lib/atatus/collector/compress_body.rb
|
|
82
83
|
- lib/atatus/collector/hist.rb
|
|
83
84
|
- lib/atatus/collector/layer.rb
|
|
84
85
|
- lib/atatus/collector/transport.rb
|
|
85
86
|
- lib/atatus/config.rb
|
|
86
87
|
- lib/atatus/config/bytes.rb
|
|
87
88
|
- lib/atatus/config/duration.rb
|
|
89
|
+
- lib/atatus/config/error_limit_converter.rb
|
|
88
90
|
- lib/atatus/config/log_level_map.rb
|
|
89
91
|
- lib/atatus/config/options.rb
|
|
90
92
|
- lib/atatus/config/regexp_list.rb
|