atatus 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/atatus/collector/base.rb +127 -148
- data/lib/atatus/collector/builder.rb +244 -180
- data/lib/atatus/collector/layer.rb +58 -0
- data/lib/atatus/collector/transport.rb +61 -21
- data/lib/atatus/config.rb +2 -1
- data/lib/atatus/metadata/system_info/hw_info.rb +1 -1
- data/lib/atatus/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ebfb72781685c274fbd7f4516df59c2ba5dc6533bc887dfbad3a3b6b93e08f6
|
4
|
+
data.tar.gz: 756f210e8bb7136aa87806fbdb3dcf1e1a9bd5986e8717322b26fba4148a9613
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a309c3b2ad681d3dc7a0a95b655e80ef0184a8b6522bf3f724b1266f65a0904e963043e21518711e3582d10757a7ab0c8c8550fd4df53d0a68442496291a352
|
7
|
+
data.tar.gz: 65c1dd53f5b6115b27edded97df2240af6e2d6217517fb59641792a60d185b6916a1bf442cb5fa277ece9711bca96a6a56acec0948edc7d6282ece771140c64e
|
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
|
+
## 1.0.2 (Thu, 21 Nov 2019)
|
8
|
+
|
9
|
+
- Changed Linux memory size to bytes.
|
10
|
+
- Set type to agent name if framework is not deducted.
|
11
|
+
- Code refactoring for checking existence of properties.
|
12
|
+
|
13
|
+
|
7
14
|
## 1.0.1 (Wed, 13 Nov 2019)
|
8
15
|
|
9
16
|
- Fixed Instrumenting classes only when there are defined.
|
@@ -1,81 +1,19 @@
|
|
1
|
+
require 'json'
|
1
2
|
require 'atatus'
|
2
|
-
require 'atatus/transaction'
|
3
3
|
require 'atatus/config'
|
4
|
-
|
4
|
+
require 'atatus/transaction'
|
5
|
+
require 'atatus/collector/layer'
|
5
6
|
require 'atatus/collector/transport'
|
6
|
-
require 'json'
|
7
7
|
|
8
8
|
module Atatus
|
9
9
|
module Collector
|
10
|
-
class Layer
|
11
|
-
attr_reader :count, :min, :max, :total, :type, :kind, :id, :pid
|
12
|
-
attr_writer :id, :pid
|
13
|
-
|
14
|
-
def initialize(type, kind, duration)
|
15
|
-
@type = type
|
16
|
-
@kind = kind
|
17
|
-
@count = 1
|
18
|
-
@min = duration
|
19
|
-
@max = duration
|
20
|
-
@total = duration
|
21
|
-
end
|
22
|
-
|
23
|
-
def aggregate!(duration)
|
24
|
-
@count += 1
|
25
|
-
@min = duration if duration < @min
|
26
|
-
@max = duration if duration > @max
|
27
|
-
@total += duration
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.span_kind(value)
|
31
|
-
return KINDS.fetch(value, value)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.span_type(value)
|
35
|
-
return TYPES.fetch(value, value)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
KINDS = {
|
40
|
-
'db' => 'Database',
|
41
|
-
'cache' => 'Database',
|
42
|
-
'ext' => 'Remote',
|
43
|
-
'websocket' => 'Remote',
|
44
|
-
'template' => 'Template'
|
45
|
-
}.freeze
|
46
|
-
|
47
|
-
TYPES = {
|
48
|
-
'mysql' => 'MySQL',
|
49
|
-
'mysql2' => 'MySQL',
|
50
|
-
'postgresql' => 'Postgres',
|
51
|
-
'mssql' => 'MS SQL',
|
52
|
-
'mongodb' => 'MongoDB',
|
53
|
-
'redis' => 'Redis',
|
54
|
-
'graphql' => 'GraphQL',
|
55
|
-
'elasticsearch' => 'Elasticsearch',
|
56
|
-
'cassandra' => 'Cassandra',
|
57
|
-
'http' => 'External Requests',
|
58
|
-
'http2' => 'External Requests',
|
59
|
-
'http_rb' => 'External Requests',
|
60
|
-
'net_http' => 'External Requests'
|
61
|
-
}.freeze
|
62
|
-
end
|
63
|
-
|
64
10
|
class Txn < Layer
|
65
|
-
attr_reader :spans
|
66
|
-
|
67
11
|
def initialize(type, kind, duration)
|
68
12
|
super(type, kind, duration)
|
69
|
-
@spans =
|
13
|
+
@spans = {}
|
70
14
|
end
|
71
15
|
|
72
|
-
|
73
|
-
if !@spans.has_key?(span_name)
|
74
|
-
@spans[key] = Layer.new(type, kind, duration)
|
75
|
-
else
|
76
|
-
@spans[key].aggregate! duration
|
77
|
-
end
|
78
|
-
end
|
16
|
+
attr_reader :spans
|
79
17
|
end
|
80
18
|
|
81
19
|
class Base
|
@@ -85,21 +23,22 @@ module Atatus
|
|
85
23
|
# info 'Initializing Collector'
|
86
24
|
@config = config
|
87
25
|
@spans = Hash.new {|h,k| h[k]=[]}
|
88
|
-
@running = false
|
89
|
-
uri = URI("https://apm-rx.atatus.com/")
|
90
|
-
@transport = Atatus::BaseTransport.new(config, uri.host, uri.port)
|
91
|
-
@txn_lock = Mutex.new
|
92
|
-
@txn_aggs = Hash.new {}
|
93
|
-
@trace_aggs = Array.new()
|
94
|
-
@error_metrics = Hash.new {}
|
95
|
-
@error_requests = Array.new()
|
96
26
|
|
97
|
-
@
|
98
|
-
@
|
27
|
+
@txns_lock = Mutex.new
|
28
|
+
@txns_agg = {}
|
29
|
+
@traces_agg = []
|
30
|
+
@error_metrics_agg = {}
|
31
|
+
@error_requests_agg = []
|
32
|
+
|
33
|
+
@errors_lock = Mutex.new
|
34
|
+
@errors_aggs = []
|
99
35
|
|
100
36
|
@metrics_lock = Mutex.new
|
101
|
-
@
|
37
|
+
@metrics_agg = []
|
38
|
+
|
39
|
+
@transport = Atatus::BaseTransport.new(config)
|
102
40
|
@collect_counter = 0
|
41
|
+
@running = false
|
103
42
|
end
|
104
43
|
|
105
44
|
attr_reader :config
|
@@ -130,80 +69,113 @@ module Atatus
|
|
130
69
|
def add_error(error)
|
131
70
|
ensure_worker_running
|
132
71
|
|
133
|
-
@
|
134
|
-
if @
|
135
|
-
@
|
72
|
+
@errors_lock.synchronize do
|
73
|
+
if @errors_aggs.length < 20
|
74
|
+
@errors_aggs.push(error)
|
136
75
|
else
|
137
76
|
i = rand(20)
|
138
|
-
@
|
77
|
+
@errors_aggs[i] = error
|
139
78
|
end
|
140
79
|
end
|
141
|
-
# puts error.to_yaml
|
142
80
|
end
|
143
81
|
|
144
82
|
def add_metrics(metricset)
|
145
83
|
ensure_worker_running
|
84
|
+
|
85
|
+
metric_added = false
|
146
86
|
metric = {}
|
147
|
-
|
87
|
+
|
88
|
+
if %i[system.cpu.total.norm.pct system.memory.actual.free system.memory.total system.process.cpu.total.norm.pct system.process.memory.size system.process.memory.rss.bytes].all? {|s| metricset.samples.key? s}
|
89
|
+
then
|
148
90
|
metric[:'system.cpu.total.norm.pct'] = metricset.samples[:'system.cpu.total.norm.pct']
|
149
91
|
metric[:'system.memory.actual.free'] = metricset.samples[:'system.memory.actual.free']
|
150
92
|
metric[:'system.memory.total'] = metricset.samples[:'system.memory.total']
|
151
93
|
metric[:'system.process.cpu.total.norm.pct'] = metricset.samples[:'system.process.cpu.total.norm.pct']
|
152
94
|
metric[:'system.process.memory.size'] = metricset.samples[:'system.process.memory.size']
|
153
95
|
metric[:'system.process.memory.rss.bytes'] = metricset.samples[:'system.process.memory.rss.bytes']
|
96
|
+
metric_added = true
|
154
97
|
end
|
155
98
|
|
156
|
-
if metricset.samples.key?
|
99
|
+
if %i[ruby.gc.count ruby.threads ruby.heaps.slots.live ruby.heap.slots.free ruby.heap.allocations.total].all? {|s| metricset.samples.key? s}
|
100
|
+
then
|
157
101
|
metric[:'ruby.gc.count'] = metricset.samples[:'ruby.gc.count']
|
158
102
|
metric[:'ruby.threads'] = metricset.samples[:'ruby.threads']
|
159
103
|
metric[:'ruby.heap.slots.live'] = metricset.samples[:'ruby.heap.slots.live']
|
160
104
|
metric[:'ruby.heap.slots.free'] = metricset.samples[:'ruby.heap.slots.free']
|
161
105
|
metric[:'ruby.heap.allocations.total'] = metricset.samples[:'ruby.heap.allocations.total']
|
106
|
+
metric_added = true
|
162
107
|
end
|
163
108
|
|
164
|
-
|
165
|
-
@
|
109
|
+
if metric_added
|
110
|
+
@metrics_lock.synchronize do
|
111
|
+
@metrics_agg << metric
|
112
|
+
end
|
166
113
|
end
|
167
|
-
# puts metric.to_yaml
|
168
114
|
end
|
169
115
|
|
170
116
|
def add_span(span)
|
171
117
|
ensure_worker_running
|
172
118
|
|
119
|
+
if
|
120
|
+
span.transaction_id.nil? ||
|
121
|
+
span.name.nil? ||
|
122
|
+
span.type.nil? ||
|
123
|
+
span.subtype.nil? ||
|
124
|
+
span.duration.nil?
|
125
|
+
then
|
126
|
+
return
|
127
|
+
end
|
128
|
+
|
173
129
|
@spans[span.transaction_id] << span if span.transaction_id
|
174
|
-
# puts span.to_yaml
|
175
130
|
end
|
176
131
|
|
177
132
|
def add_txn(txn)
|
178
133
|
ensure_worker_running
|
179
134
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
135
|
+
if
|
136
|
+
txn.name.nil? ||
|
137
|
+
txn.id.nil? ||
|
138
|
+
txn.duration.nil?
|
139
|
+
then
|
140
|
+
return
|
141
|
+
end
|
142
|
+
|
143
|
+
return if txn.name.empty?
|
144
|
+
|
145
|
+
@txns_lock.synchronize do
|
146
|
+
if !@txns_agg.key?(txn.name)
|
147
|
+
@txns_agg[txn.name] = Txn.new(@config.framework_name, "Ruby", txn.duration)
|
148
|
+
@txns_agg[txn.name].id = txn.id
|
149
|
+
@txns_agg[txn.name].pid = txn.id
|
188
150
|
else
|
189
|
-
@
|
151
|
+
@txns_agg[txn.name].aggregate! txn.duration
|
190
152
|
end
|
191
153
|
|
192
154
|
spans_present = false
|
193
|
-
if @spans.
|
155
|
+
if @spans.key?(txn.id)
|
194
156
|
@spans[txn.id].each do |span|
|
195
|
-
|
196
|
-
|
157
|
+
if
|
158
|
+
span.name.nil? ||
|
159
|
+
span.type.nil? ||
|
160
|
+
span.subtype.nil? ||
|
161
|
+
span.duration.nil?
|
162
|
+
then
|
163
|
+
next
|
164
|
+
end
|
165
|
+
|
166
|
+
next if span.name.empty?
|
167
|
+
|
168
|
+
if !@txns_agg[txn.name].spans.key?(span.name)
|
197
169
|
kind = Layer.span_kind(span.type)
|
198
170
|
type = Layer.span_type(span.subtype)
|
199
|
-
@
|
200
|
-
@
|
201
|
-
@
|
171
|
+
@txns_agg[txn.name].spans[span.name] = Layer.new(type, kind, span.duration)
|
172
|
+
@txns_agg[txn.name].spans[span.name].id = span.id
|
173
|
+
@txns_agg[txn.name].spans[span.name].pid = span.transaction_id
|
202
174
|
else
|
203
|
-
@
|
175
|
+
@txns_agg[txn.name].spans[span.name].aggregate! span.duration
|
204
176
|
end
|
177
|
+
spans_present = true
|
205
178
|
end
|
206
|
-
spans_present = true
|
207
179
|
end
|
208
180
|
|
209
181
|
if spans_present
|
@@ -211,11 +183,11 @@ module Atatus
|
|
211
183
|
trace_txn = txn
|
212
184
|
trace_txn.spans = @spans[txn.id]
|
213
185
|
|
214
|
-
if @
|
215
|
-
@
|
186
|
+
if @traces_agg.length < 5
|
187
|
+
@traces_agg.push(trace_txn)
|
216
188
|
else
|
217
189
|
i = rand(5)
|
218
|
-
@
|
190
|
+
@traces_agg[i] = trace_txn
|
219
191
|
end
|
220
192
|
end
|
221
193
|
end
|
@@ -224,25 +196,30 @@ module Atatus
|
|
224
196
|
@spans.delete(txn.id)
|
225
197
|
end
|
226
198
|
|
227
|
-
|
199
|
+
if
|
200
|
+
!txn.context.nil? &&
|
201
|
+
!txn.context.response.nil? &&
|
202
|
+
!txn.context.response.status_code.nil?
|
203
|
+
then
|
204
|
+
status_code = txn.context.response.status_code
|
228
205
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
else
|
233
|
-
if !@error_metrics[txn_name].has_key?(status_code)
|
234
|
-
@error_metrics[txn_name][status_code] = 1
|
206
|
+
if status_code >= 400 && status_code != 404
|
207
|
+
if !@error_metrics_agg.key?(txn.name)
|
208
|
+
@error_metrics_agg[txn.name] = {status_code => 1}
|
235
209
|
else
|
236
|
-
|
210
|
+
if !@error_metrics_agg[txn.name].key?(status_code)
|
211
|
+
@error_metrics_agg[txn.name][status_code] = 1
|
212
|
+
else
|
213
|
+
@error_metrics_agg[txn.name][status_code] += 1
|
214
|
+
end
|
237
215
|
end
|
238
|
-
end
|
239
216
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
217
|
+
if @error_requests_agg.length < 20
|
218
|
+
@error_requests_agg.push({'name' => txn.name, 'context' => txn.context})
|
219
|
+
else
|
220
|
+
i = rand(20)
|
221
|
+
@error_requests_agg[i] = {'name' => txn.name, 'context' => txn.context}
|
222
|
+
end
|
246
223
|
end
|
247
224
|
end
|
248
225
|
|
@@ -257,7 +234,7 @@ module Atatus
|
|
257
234
|
debug '%s: Starting collector worker', pid_str
|
258
235
|
|
259
236
|
while @running
|
260
|
-
start_time = Time.now
|
237
|
+
start_time = (Time.now.to_f * 1000).to_i
|
261
238
|
sleep(60)
|
262
239
|
collect start_time
|
263
240
|
end
|
@@ -269,8 +246,6 @@ module Atatus
|
|
269
246
|
end
|
270
247
|
|
271
248
|
def collect(start_time)
|
272
|
-
# puts @config.to_yaml
|
273
|
-
# return
|
274
249
|
if @config.license_key.nil? || @config.app_name.nil?
|
275
250
|
if @config.license_key.nil? && @config.app_name.nil?
|
276
251
|
error '%s: Atatus configuration license_key and app_name are missing', pid_str
|
@@ -290,44 +265,48 @@ module Atatus
|
|
290
265
|
end
|
291
266
|
@collect_counter += 1
|
292
267
|
|
293
|
-
end_time = Time.now
|
268
|
+
end_time = (Time.now.to_f * 1000).to_i
|
294
269
|
debug '%s: Collecting transactions', pid_str
|
295
270
|
|
296
|
-
|
297
|
-
|
298
|
-
error_data = nil
|
271
|
+
txns_data = nil
|
272
|
+
traces_data = nil
|
299
273
|
error_metrics_data = nil
|
300
274
|
error_requests_data = nil
|
275
|
+
errors_data = nil
|
301
276
|
metrics_data = nil
|
302
277
|
|
303
|
-
@
|
304
|
-
|
305
|
-
@
|
278
|
+
@txns_lock.synchronize do
|
279
|
+
txns_data = @txns_agg
|
280
|
+
@txns_agg = {}
|
306
281
|
|
307
|
-
|
308
|
-
@
|
282
|
+
traces_data = @traces_agg
|
283
|
+
@traces_agg = []
|
309
284
|
|
310
|
-
error_metrics_data = @
|
311
|
-
@
|
285
|
+
error_metrics_data = @error_metrics_agg
|
286
|
+
@error_metrics_agg = {}
|
312
287
|
|
313
|
-
error_requests_data = @
|
314
|
-
@
|
288
|
+
error_requests_data = @error_requests_agg
|
289
|
+
@error_requests_agg = []
|
315
290
|
end
|
316
291
|
|
317
|
-
@
|
318
|
-
|
319
|
-
@
|
292
|
+
@errors_lock.synchronize do
|
293
|
+
errors_data = @errors_aggs
|
294
|
+
@errors_aggs = []
|
320
295
|
end
|
321
296
|
|
322
297
|
@metrics_lock.synchronize do
|
323
|
-
metrics_data = @
|
324
|
-
@
|
298
|
+
metrics_data = @metrics_agg
|
299
|
+
@metrics_agg = []
|
325
300
|
end
|
326
301
|
|
327
|
-
@transport.
|
328
|
-
|
302
|
+
@transport.txns(start_time, end_time, txns_data) unless txns_data.empty?
|
303
|
+
|
304
|
+
@transport.traces(start_time, end_time, traces_data) unless traces_data.empty?
|
305
|
+
|
329
306
|
@transport.error_metrics(start_time, end_time, error_metrics_data, error_requests_data) unless error_metrics_data.empty?
|
330
|
-
|
307
|
+
|
308
|
+
@transport.errors(start_time, end_time, errors_data) unless errors_data.empty?
|
309
|
+
|
331
310
|
@transport.metrics(start_time, end_time, metrics_data) unless metrics_data.empty?
|
332
311
|
end
|
333
312
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'atatus/metadata'
|
3
|
-
|
3
|
+
require 'yaml'
|
4
4
|
module Atatus
|
5
5
|
class Builder
|
6
6
|
AGENT_NAME = 'Ruby'
|
@@ -8,6 +8,15 @@ module Atatus
|
|
8
8
|
def initialize(config)
|
9
9
|
@config = config
|
10
10
|
@metadata = Metadata::SystemInfo.new(config)
|
11
|
+
@container_id = nil
|
12
|
+
if
|
13
|
+
!@metadata.container.nil? &&
|
14
|
+
@metadata.container.key?(:id)
|
15
|
+
then
|
16
|
+
@container_id = @metadata.container[:id]
|
17
|
+
end
|
18
|
+
|
19
|
+
@real_hostname = Socket.gethostname
|
11
20
|
end
|
12
21
|
|
13
22
|
attr_reader :config
|
@@ -20,49 +29,47 @@ module Atatus
|
|
20
29
|
name: AGENT_NAME,
|
21
30
|
version: VERSION
|
22
31
|
},
|
23
|
-
# tags: @config.default_tags,
|
24
|
-
uniqueHostname: Socket.gethostname,
|
25
32
|
hostname: @metadata.hostname,
|
26
33
|
hostId: @metadata.hwinfo.hostid
|
27
34
|
}
|
28
|
-
|
29
|
-
common[:containerId] = @
|
35
|
+
if !@container_id.nil?
|
36
|
+
common[:containerId] = @container_id
|
30
37
|
end
|
31
38
|
common
|
32
39
|
end
|
33
40
|
|
41
|
+
def hostinfo(start_time)
|
42
|
+
payload = common()
|
43
|
+
payload[:timestamp] = start_time
|
44
|
+
payload[:environment] = build_hostinfo_obj()
|
45
|
+
payload
|
46
|
+
end
|
47
|
+
|
34
48
|
def txns(start_time, end_time, data)
|
35
49
|
payload = common()
|
36
|
-
payload[:startTime] =
|
37
|
-
payload[:endTime] =
|
50
|
+
payload[:startTime] = start_time
|
51
|
+
payload[:endTime] = end_time
|
38
52
|
payload[:transactions] = build_txns_obj(data)
|
39
53
|
payload
|
40
54
|
end
|
41
55
|
|
42
56
|
def traces(start_time, end_time, data)
|
43
57
|
payload = common()
|
44
|
-
payload[:startTime] =
|
45
|
-
payload[:endTime] =
|
58
|
+
payload[:startTime] = start_time
|
59
|
+
payload[:endTime] = end_time
|
46
60
|
payload[:traces] = build_traces_obj(data)
|
47
61
|
payload
|
48
62
|
end
|
49
63
|
|
50
64
|
def error_metrics(start_time, end_time, metrics_data, requests_data)
|
51
65
|
payload = common()
|
52
|
-
payload[:startTime] =
|
53
|
-
payload[:endTime] =
|
66
|
+
payload[:startTime] = start_time
|
67
|
+
payload[:endTime] = end_time
|
54
68
|
payload[:errorMetrics] = build_error_metrics_obj(metrics_data)
|
55
69
|
payload[:errorRequests] = build_error_requests_obj(requests_data)
|
56
70
|
payload
|
57
71
|
end
|
58
72
|
|
59
|
-
def hostinfo(start_time)
|
60
|
-
payload = common()
|
61
|
-
payload[:timestamp] = (start_time.to_f * 1000).to_i
|
62
|
-
payload[:environment] = build_hostinfo_obj()
|
63
|
-
payload
|
64
|
-
end
|
65
|
-
|
66
73
|
def errors(start_time, end_time, error_data)
|
67
74
|
payload = common()
|
68
75
|
payload[:errors] = build_errors_obj(error_data)
|
@@ -71,8 +78,8 @@ module Atatus
|
|
71
78
|
|
72
79
|
def metrics(start_time, end_time, metric_data)
|
73
80
|
payload = common()
|
74
|
-
payload[:startTime] =
|
75
|
-
payload[:endTime] =
|
81
|
+
payload[:startTime] = start_time
|
82
|
+
payload[:endTime] = end_time
|
76
83
|
payload[:ruby] = metric_data
|
77
84
|
payload
|
78
85
|
end
|
@@ -83,99 +90,45 @@ module Atatus
|
|
83
90
|
Util.truncate(value)
|
84
91
|
end
|
85
92
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
'accept-encoding': context.request.headers['Accept-Encoding'],
|
93
|
-
'accept-language': context.request.headers['Accept-Language'],
|
94
|
-
host: context.request.url.hostname,
|
95
|
-
port: (context.request.url.port).to_i,
|
96
|
-
method: context.request.method,
|
97
|
-
userAgent: context.request.headers['User-Agent'],
|
98
|
-
path: context.request.url.pathname
|
99
|
-
}
|
100
|
-
unless context.response.nil?
|
101
|
-
unless context.response.status_code.nil?
|
102
|
-
request[:statusCode] = context.response.status_code
|
103
|
-
end
|
104
|
-
end
|
105
|
-
request
|
93
|
+
def build_hostinfo_obj()
|
94
|
+
environment = {}
|
95
|
+
environment[:gems] = build_hostinfo_gems()
|
96
|
+
environment[:host] = build_hostinfo_env_host()
|
97
|
+
environment[:settings] = build_hostinfo_env_settings()
|
98
|
+
environment
|
106
99
|
end
|
107
100
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
101
|
+
def build_hostinfo_env_host()
|
102
|
+
host_info = {
|
103
|
+
cpu: [@metadata.hwinfo.cpuinfo],
|
104
|
+
ram: @metadata.hwinfo.meminfo,
|
105
|
+
hostname: @real_hostname,
|
106
|
+
bootId: @metadata.hwinfo.hostid,
|
107
|
+
hostId: @metadata.hwinfo.hostid,
|
108
|
+
os: @metadata.osinfo.os,
|
109
|
+
kernel: @metadata.osinfo.kernel
|
110
|
+
}
|
111
|
+
if !@container_id.nil?
|
112
|
+
host_info[:containerId] = @container_id
|
117
113
|
end
|
118
|
-
|
114
|
+
host_info
|
119
115
|
end
|
120
116
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
exception = {}
|
132
|
-
exception[:class] = v.exception.type
|
133
|
-
exception[:message] = v.exception.message
|
134
|
-
exception[:stacktrace] = []
|
135
|
-
unless v.exception.stacktrace.nil?
|
136
|
-
unless v.exception.stacktrace.frames.nil?
|
137
|
-
v.exception.stacktrace.frames.each do |f|
|
138
|
-
frame = {}
|
139
|
-
frame[:f] = f.filename
|
140
|
-
frame[:m] = f.function
|
141
|
-
frame[:ln] = f.lineno
|
142
|
-
if f.library_frame == false
|
143
|
-
frame[:inp] = true
|
144
|
-
unless f.context_line.nil?
|
145
|
-
frame[:code] = []
|
146
|
-
|
147
|
-
unless f.pre_context.nil?
|
148
|
-
psize = f.pre_context.size
|
149
|
-
lineno = 0
|
150
|
-
if f.lineno - psize >= 0
|
151
|
-
lineno = f.lineno - psize
|
152
|
-
end
|
153
|
-
f.pre_context.each do |c|
|
154
|
-
frame[:code].push([lineno.to_s, c])
|
155
|
-
lineno += 1
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
frame[:code].push([f.lineno.to_s, f.context_line])
|
117
|
+
def build_hostinfo_env_settings()
|
118
|
+
{
|
119
|
+
agentVersion: VERSION,
|
120
|
+
appName: @config.app_name,
|
121
|
+
framework: @config.framework_name,
|
122
|
+
frameworkVersion: @config.framework_version,
|
123
|
+
logLevel: @config.log_level,
|
124
|
+
ruby: RUBY_VERSION
|
125
|
+
}
|
126
|
+
end
|
160
127
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
frame[:code].push([lineno.to_s, c])
|
166
|
-
lineno += 1
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
exception[:stacktrace] << frame
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
error[:exceptions] << exception
|
176
|
-
errors << error
|
177
|
-
end
|
178
|
-
errors
|
128
|
+
def build_hostinfo_gems()
|
129
|
+
Bundler.rubygems.all_specs.map {|spec| [spec.name, spec.version.to_s]}.sort.to_h
|
130
|
+
rescue => e
|
131
|
+
{}
|
179
132
|
end
|
180
133
|
|
181
134
|
def build_metric(name, value)
|
@@ -190,6 +143,38 @@ module Atatus
|
|
190
143
|
}
|
191
144
|
end
|
192
145
|
|
146
|
+
def build_request(context)
|
147
|
+
request = {}
|
148
|
+
return request unless context
|
149
|
+
|
150
|
+
if !context.request.nil?
|
151
|
+
r = context.request
|
152
|
+
request[:method] = r.method if !r.method.nil?
|
153
|
+
if !r.headers.nil?
|
154
|
+
h = r.headers
|
155
|
+
request[:accept] = h['Accept'] if h.key?('Accept')
|
156
|
+
request[:'accept-encoding'] = h['Accept-Encoding'] if h.key?('Accept-Encoding')
|
157
|
+
request[:'accept-language'] = h['Accept-Language'] if h.key?('Accept-Language')
|
158
|
+
request[:'userAgent'] = h['User-Agent'] if h.key?('User-Agent')
|
159
|
+
end
|
160
|
+
|
161
|
+
if !r.url.nil?
|
162
|
+
u = r.url
|
163
|
+
request[:host] = u.hostname if !u.hostname.nil?
|
164
|
+
request[:port] = (u.port).to_i if !u.port.nil?
|
165
|
+
request[:path] = u.pathname if !u.pathname.nil?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
if !context.response.nil?
|
170
|
+
if !context.response.status_code.nil?
|
171
|
+
request[:statusCode] = context.response.status_code
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
request
|
176
|
+
end
|
177
|
+
|
193
178
|
def build_txns_obj(data)
|
194
179
|
txns = []
|
195
180
|
data.each do |t, v|
|
@@ -207,49 +192,60 @@ module Atatus
|
|
207
192
|
def build_traces_obj(data)
|
208
193
|
traces = []
|
209
194
|
data.each do |txn|
|
195
|
+
if
|
196
|
+
txn.name.nil? ||
|
197
|
+
txn.timestamp.nil? ||
|
198
|
+
txn.duration.nil?
|
199
|
+
then
|
200
|
+
next
|
201
|
+
end
|
202
|
+
|
210
203
|
trace = {}
|
211
204
|
trace[:name] = txn.name
|
212
|
-
trace[:type] = @config.framework_name
|
213
|
-
trace[:kind] =
|
205
|
+
trace[:type] = @config.framework_name || AGENT_NAME
|
206
|
+
trace[:kind] = AGENT_NAME
|
214
207
|
trace[:start] = txn.timestamp
|
215
208
|
trace[:duration] = Util.ms(txn.duration)
|
216
|
-
|
209
|
+
if !txn.context.nil?
|
210
|
+
trace[:request] = build_request(txn.context)
|
211
|
+
end
|
217
212
|
trace[:entries] = []
|
218
213
|
trace[:funcs] = []
|
219
214
|
i = 0
|
220
215
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
entry[:
|
232
|
-
entry[:ly] = {}
|
233
|
-
entry[:ly][:name] = span.name
|
234
|
-
entry[:ly][:type] = Atatus::Collector::Layer.span_type(span.subtype)
|
235
|
-
entry[:ly][:kind] = Atatus::Collector::Layer.span_kind(span.type)
|
236
|
-
unless span.context.nil?
|
237
|
-
unless span.context.db.nil?
|
238
|
-
unless span.context.db.statement.nil?
|
239
|
-
entry[:dt] = {}
|
240
|
-
entry[:dt][:query] = span.context.db.statement
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
trace[:entries] << entry
|
245
|
-
func_index = trace[:funcs].index(span.name)
|
246
|
-
if func_index.nil?
|
247
|
-
trace[:funcs] << span.name
|
248
|
-
func_index = i
|
249
|
-
i = i + 1
|
250
|
-
end
|
251
|
-
entry[:i] = func_index
|
216
|
+
if
|
217
|
+
!txn.spans.nil? &&
|
218
|
+
!txn.spans.empty?
|
219
|
+
then
|
220
|
+
txn.spans.each do |span|
|
221
|
+
entry = {}
|
222
|
+
entry[:lv] = 1
|
223
|
+
if span.timestamp >= txn.timestamp
|
224
|
+
entry[:so] = Util.ms(span.timestamp - txn.timestamp)
|
225
|
+
else
|
226
|
+
entry[:so] = 0
|
252
227
|
end
|
228
|
+
entry[:du] = Util.ms(span.duration)
|
229
|
+
entry[:ly] = {}
|
230
|
+
entry[:ly][:name] = span.name
|
231
|
+
entry[:ly][:type] = Atatus::Collector::Layer.span_type(span.subtype)
|
232
|
+
entry[:ly][:kind] = Atatus::Collector::Layer.span_kind(span.type)
|
233
|
+
if
|
234
|
+
!span.context.nil? &&
|
235
|
+
!span.context.db.nil? &&
|
236
|
+
!span.context.db.statement.nil?
|
237
|
+
then
|
238
|
+
entry[:dt] = {}
|
239
|
+
entry[:dt][:query] = span.context.db.statement
|
240
|
+
end
|
241
|
+
trace[:entries] << entry
|
242
|
+
func_index = trace[:funcs].index(span.name)
|
243
|
+
if func_index.nil?
|
244
|
+
trace[:funcs] << span.name
|
245
|
+
func_index = i
|
246
|
+
i = i + 1
|
247
|
+
end
|
248
|
+
entry[:i] = func_index
|
253
249
|
end
|
254
250
|
end
|
255
251
|
|
@@ -263,55 +259,123 @@ module Atatus
|
|
263
259
|
metrics_data.each do |t, v|
|
264
260
|
error_metric = {}
|
265
261
|
error_metric[:name] = t
|
266
|
-
error_metric[:type] = @config.framework_name
|
267
|
-
error_metric[:kind] =
|
262
|
+
error_metric[:type] = @config.framework_name || AGENT_NAME
|
263
|
+
error_metric[:kind] = AGENT_NAME
|
268
264
|
error_metric[:statusCodes] = v
|
269
265
|
error_metrics << error_metric
|
270
266
|
end
|
271
267
|
error_metrics
|
272
268
|
end
|
273
269
|
|
274
|
-
def
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
hostId: @metadata.hwinfo.hostid,
|
290
|
-
os: @metadata.osinfo.os,
|
291
|
-
kernel: @metadata.osinfo.kernel
|
292
|
-
}
|
293
|
-
unless @metadata.container.nil?
|
294
|
-
host_info[:containerId] = @metadata.container[:id] if @metadata.container.key?(:id)
|
270
|
+
def build_error_requests_obj(requests_data)
|
271
|
+
error_requests = []
|
272
|
+
requests_data.each do |v|
|
273
|
+
if
|
274
|
+
!v.key?('name') ||
|
275
|
+
!v.key?('context')
|
276
|
+
then
|
277
|
+
next
|
278
|
+
end
|
279
|
+
error_request = {}
|
280
|
+
error_request[:name] = v['name']
|
281
|
+
error_request[:type] = @config.framework_name || AGENT_NAME
|
282
|
+
error_request[:kind] = AGENT_NAME
|
283
|
+
error_request[:request] = build_request(v['context'])
|
284
|
+
error_requests << error_request
|
295
285
|
end
|
296
|
-
|
286
|
+
error_requests
|
297
287
|
end
|
298
288
|
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
end
|
289
|
+
def build_errors_obj(data)
|
290
|
+
errors = []
|
291
|
+
data.each do |v|
|
292
|
+
if
|
293
|
+
v.timestamp.nil? ||
|
294
|
+
v.exception.nil?
|
295
|
+
then
|
296
|
+
next
|
297
|
+
end
|
309
298
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
299
|
+
if
|
300
|
+
v.exception.type.nil? ||
|
301
|
+
v.exception.message.nil?
|
302
|
+
then
|
303
|
+
next
|
304
|
+
end
|
305
|
+
|
306
|
+
error = {}
|
307
|
+
error[:timestamp] = v.timestamp
|
308
|
+
|
309
|
+
if
|
310
|
+
!v.transaction.nil? &&
|
311
|
+
v.transaction.key?(:name)
|
312
|
+
then
|
313
|
+
error[:transaction] = v.transaction[:name]
|
314
|
+
end
|
315
|
+
|
316
|
+
if !v.context.nil?
|
317
|
+
error[:request] = build_request(v.context)
|
318
|
+
end
|
319
|
+
error[:exceptions] = []
|
320
|
+
exception = {}
|
321
|
+
exception[:class] = v.exception.type
|
322
|
+
exception[:message] = v.exception.message
|
323
|
+
exception[:stacktrace] = []
|
324
|
+
if
|
325
|
+
!v.exception.stacktrace.nil? &&
|
326
|
+
!v.exception.stacktrace.frames.nil?
|
327
|
+
then
|
328
|
+
v.exception.stacktrace.frames.each do |f|
|
329
|
+
if
|
330
|
+
f.filename.nil? ||
|
331
|
+
f.function.nil? ||
|
332
|
+
f.lineno.nil? ||
|
333
|
+
f.library_frame.nil?
|
334
|
+
then
|
335
|
+
next
|
336
|
+
end
|
337
|
+
|
338
|
+
frame = {}
|
339
|
+
frame[:f] = f.filename
|
340
|
+
frame[:m] = f.function
|
341
|
+
frame[:ln] = f.lineno
|
342
|
+
if f.library_frame == false
|
343
|
+
frame[:inp] = true
|
344
|
+
if !f.context_line.nil?
|
345
|
+
frame[:code] = []
|
346
|
+
|
347
|
+
if !f.pre_context.nil?
|
348
|
+
psize = f.pre_context.size
|
349
|
+
lineno = 0
|
350
|
+
if f.lineno - psize >= 0
|
351
|
+
lineno = f.lineno - psize
|
352
|
+
end
|
353
|
+
f.pre_context.each do |c|
|
354
|
+
frame[:code].push([lineno.to_s, c])
|
355
|
+
lineno += 1
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
frame[:code].push([f.lineno.to_s, f.context_line])
|
360
|
+
|
361
|
+
if !f.post_context.nil?
|
362
|
+
psize = f.post_context.size
|
363
|
+
lineno = f.lineno + 1
|
364
|
+
f.post_context.each do |c|
|
365
|
+
frame[:code].push([lineno.to_s, c])
|
366
|
+
lineno += 1
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
exception[:stacktrace] << frame
|
372
|
+
end
|
373
|
+
end
|
374
|
+
error[:exceptions] << exception
|
375
|
+
errors << error
|
376
|
+
end
|
377
|
+
errors
|
315
378
|
end
|
379
|
+
|
316
380
|
end
|
317
381
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
module Atatus
|
3
|
+
module Collector
|
4
|
+
class Layer
|
5
|
+
def initialize(type, kind, duration)
|
6
|
+
@type = type
|
7
|
+
@kind = kind
|
8
|
+
@count = 1
|
9
|
+
@min = duration
|
10
|
+
@max = duration
|
11
|
+
@total = duration
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :type, :kind, :count, :min, :max, :total
|
15
|
+
attr_accessor :id, :pid
|
16
|
+
|
17
|
+
def aggregate!(duration)
|
18
|
+
@count += 1
|
19
|
+
@min = duration if duration < @min
|
20
|
+
@max = duration if duration > @max
|
21
|
+
@total += duration
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.span_kind(value)
|
25
|
+
return KINDS.fetch(value, value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.span_type(value)
|
29
|
+
return TYPES.fetch(value, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
KINDS = {
|
34
|
+
'db' => 'Database',
|
35
|
+
'cache' => 'Database',
|
36
|
+
'ext' => 'Remote',
|
37
|
+
'websocket' => 'Remote',
|
38
|
+
'template' => 'Template'
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
TYPES = {
|
42
|
+
'mysql' => 'MySQL',
|
43
|
+
'mysql2' => 'MySQL',
|
44
|
+
'postgresql' => 'Postgres',
|
45
|
+
'mssql' => 'MS SQL',
|
46
|
+
'mongodb' => 'MongoDB',
|
47
|
+
'redis' => 'Redis',
|
48
|
+
'graphql' => 'GraphQL',
|
49
|
+
'elasticsearch' => 'Elasticsearch',
|
50
|
+
'cassandra' => 'Cassandra',
|
51
|
+
'http' => 'External Requests',
|
52
|
+
'http2' => 'External Requests',
|
53
|
+
'http_rb' => 'External Requests',
|
54
|
+
'net_http' => 'External Requests'
|
55
|
+
}.freeze
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,11 +2,10 @@ require 'json'
|
|
2
2
|
require 'thread'
|
3
3
|
require 'net/http'
|
4
4
|
require 'atatus/collector/builder'
|
5
|
-
require 'json'
|
6
5
|
|
7
6
|
module Atatus
|
8
7
|
class BaseTransport
|
9
|
-
|
8
|
+
include Logging
|
10
9
|
|
11
10
|
TXN_ENDPOINT = '/track/apm/txn'.freeze
|
12
11
|
TRACE_ENDPOINT = '/track/apm/trace'.freeze
|
@@ -15,23 +14,32 @@ module Atatus
|
|
15
14
|
ERROR_METRIC_ENDPOINT = "/track/apm/error_metric".freeze
|
16
15
|
METRIC_ENDPOINT = "/track/apm/metric".freeze
|
17
16
|
|
18
|
-
def initialize(config
|
17
|
+
def initialize(config)
|
19
18
|
@config = config
|
20
|
-
@hostname = hostname
|
21
|
-
@port = port
|
22
19
|
|
23
|
-
@
|
20
|
+
@notify_host = @config.notify_host
|
21
|
+
@uri = URI(@notify_host)
|
22
|
+
if not @uri.kind_of?(URI::HTTPS) and not @uri.kind_of?(URI::HTTP)
|
23
|
+
@notify_host = "https://apm-rx.atatus.com"
|
24
|
+
@uri = URI(@notify_host)
|
25
|
+
end
|
24
26
|
|
27
|
+
@builder = Atatus::Builder.new(config)
|
25
28
|
@headers = {}
|
26
29
|
@headers['Content-Type'] = "application/json"
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
32
|
+
def hostinfo(start_time)
|
33
|
+
payload = @builder.hostinfo(start_time)
|
34
|
+
post(HOSTINFO_ENDPOINT, payload)
|
35
|
+
end
|
36
|
+
|
37
|
+
def txns(start_time, end_time, data)
|
30
38
|
payload = @builder.txns(start_time, end_time, data)
|
31
39
|
post(TXN_ENDPOINT, payload)
|
32
40
|
end
|
33
41
|
|
34
|
-
def
|
42
|
+
def traces(start_time, end_time, data)
|
35
43
|
payload = @builder.traces(start_time, end_time, data)
|
36
44
|
post(TRACE_ENDPOINT, payload)
|
37
45
|
end
|
@@ -41,11 +49,6 @@ module Atatus
|
|
41
49
|
post(ERROR_METRIC_ENDPOINT, payload)
|
42
50
|
end
|
43
51
|
|
44
|
-
def hostinfo(start_time)
|
45
|
-
payload = @builder.hostinfo(start_time)
|
46
|
-
post(HOSTINFO_ENDPOINT, payload)
|
47
|
-
end
|
48
|
-
|
49
52
|
def errors(start_time, end_time, error_data)
|
50
53
|
payload = @builder.errors(start_time, end_time, error_data)
|
51
54
|
post(ERROR_ENDPOINT, payload)
|
@@ -59,14 +62,51 @@ module Atatus
|
|
59
62
|
private
|
60
63
|
|
61
64
|
def post(endpoint, data)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
# puts ::JSON.pretty_generate(data, :max_nesting => false)
|
66
|
+
if @blocked == true and endpoint != HOSTINFO_ENDPOINT
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
begin
|
71
|
+
request = Net::HTTP::Post.new(endpoint, @headers)
|
72
|
+
request.body = ::JSON.dump(data)
|
73
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
74
|
+
http.use_ssl = true
|
75
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
76
|
+
response = http.start { |http| http.request(request) }
|
77
|
+
rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
|
78
|
+
puts "Atatus transport [#{@notify_host}#{endpoint}] failed with exception: #{e}"
|
79
|
+
end
|
80
|
+
|
81
|
+
if @blocked == true
|
82
|
+
@blocked = false
|
83
|
+
end
|
84
|
+
|
85
|
+
case response
|
86
|
+
when Net::HTTPSuccess
|
87
|
+
true
|
88
|
+
when Net::HTTPBadRequest
|
89
|
+
if not response.body
|
90
|
+
error format('Atatus transport status 400, failed without content')
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
resp = JSON.parse response.body
|
95
|
+
if resp
|
96
|
+
if resp.key?(:blocked)
|
97
|
+
@blocked = resp[:blocked]
|
98
|
+
if @blocked == true
|
99
|
+
if resp.key?(:errorMessage)
|
100
|
+
error format('Atatus blocked from sending data as: %s', resp[:errorMessage])
|
101
|
+
return
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
error format('Atatus transport status 400, failed with content: %s', response.message)
|
108
|
+
else
|
109
|
+
end
|
70
110
|
end
|
71
111
|
end
|
72
112
|
end
|
data/lib/atatus/config.rb
CHANGED
@@ -22,9 +22,10 @@ module Atatus
|
|
22
22
|
# rubocop:disable Metrics/LineLength, Layout/ExtraSpacing
|
23
23
|
option :app_name, type: :string
|
24
24
|
option :license_key, type: :string
|
25
|
+
option :notify_host, type: :string, default: 'https://apm-rx.atatus.com'
|
25
26
|
option :trace_threshold, type: :int, default: 2000
|
26
27
|
option :config_file, type: :string, default: 'config/atatus.yml'
|
27
|
-
option :server_url, type: :string, default: '
|
28
|
+
option :server_url, type: :string, default: ''
|
28
29
|
option :secret_token, type: :string
|
29
30
|
|
30
31
|
option :active, type: :bool, default: true
|
@@ -92,7 +92,7 @@ module Atatus
|
|
92
92
|
def read_from_meminfo!
|
93
93
|
return unless File.exist?(LINUX_MEMINFO_PATH)
|
94
94
|
meminfo = File.read(LINUX_MEMINFO_PATH)
|
95
|
-
self.meminfo_total = meminfo.scan(TOTAL_MEMORY_REGEX).flatten.first.to_i
|
95
|
+
self.meminfo_total = (meminfo.scan(TOTAL_MEMORY_REGEX).flatten.first.to_i) * 1024 # to bytes
|
96
96
|
end
|
97
97
|
# rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
|
98
98
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
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: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Atatus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-21 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/central_config/cache_control.rb
|
75
75
|
- lib/atatus/collector/base.rb
|
76
76
|
- lib/atatus/collector/builder.rb
|
77
|
+
- lib/atatus/collector/layer.rb
|
77
78
|
- lib/atatus/collector/transport.rb
|
78
79
|
- lib/atatus/config.rb
|
79
80
|
- lib/atatus/config/bytes.rb
|