atatus 1.6.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile +49 -13
- data/LICENSE +1 -1
- data/atatus.gemspec +3 -3
- data/lib/atatus/agent.rb +18 -7
- data/lib/atatus/central_config.rb +19 -8
- data/lib/atatus/collector/base.rb +113 -1
- data/lib/atatus/collector/builder.rb +8 -0
- data/lib/atatus/collector/layer.rb +1 -1
- data/lib/atatus/collector/transport.rb +23 -2
- data/lib/atatus/{sql_summarizer.rb → config/log_level_map.rb} +22 -28
- data/lib/atatus/config/options.rb +2 -1
- data/lib/atatus/config/regexp_list.rb +1 -1
- data/lib/atatus/config/round_float.rb +31 -0
- data/lib/atatus/config/server_info.rb +50 -0
- data/lib/atatus/config/wildcard_pattern_list.rb +3 -1
- data/lib/atatus/config.rb +94 -70
- data/lib/atatus/context/company.rb +38 -0
- data/lib/atatus/context/request/socket.rb +1 -2
- data/lib/atatus/context/response.rb +1 -3
- data/lib/atatus/context.rb +4 -8
- data/lib/atatus/context_builder.rb +3 -3
- data/lib/atatus/error.rb +2 -1
- data/lib/atatus/error_builder.rb +1 -1
- data/lib/atatus/fields.rb +98 -0
- data/lib/atatus/graphql.rb +2 -0
- data/lib/atatus/grpc.rb +5 -7
- data/lib/atatus/instrumenter.rb +38 -24
- data/lib/atatus/metadata/cloud_info.rb +156 -0
- data/lib/atatus/metadata/service_info.rb +3 -3
- data/lib/atatus/metadata/system_info/container_info.rb +20 -8
- data/lib/atatus/metadata/system_info.rb +20 -5
- data/lib/atatus/metadata.rb +3 -1
- data/lib/atatus/metrics/cpu_mem_set.rb +10 -38
- data/lib/atatus/metrics/jvm_set.rb +88 -0
- data/lib/atatus/metrics/metric.rb +2 -0
- data/lib/atatus/metrics.rb +32 -16
- data/lib/atatus/middleware.rb +8 -3
- data/lib/atatus/naively_hashable.rb +1 -0
- data/lib/atatus/normalizers/rails/active_record.rb +25 -7
- data/lib/atatus/normalizers.rb +2 -2
- data/lib/atatus/opentracing.rb +5 -3
- data/lib/atatus/rails.rb +1 -1
- data/lib/atatus/span/context/db.rb +1 -1
- data/lib/atatus/span/context/destination.rb +58 -32
- data/lib/atatus/span/context/http.rb +2 -0
- data/lib/atatus/span/context/links.rb +32 -0
- data/lib/atatus/{sql.rb → span/context/message.rb} +16 -12
- data/lib/atatus/span/context/service.rb +55 -0
- data/lib/atatus/span/context.rb +28 -3
- data/lib/atatus/span.rb +35 -5
- data/lib/atatus/span_helpers.rb +12 -23
- data/lib/atatus/spies/action_dispatch.rb +10 -13
- data/lib/atatus/spies/azure_storage_table.rb +148 -0
- data/lib/atatus/spies/delayed_job.rb +19 -13
- data/lib/atatus/spies/dynamo_db.rb +56 -15
- data/lib/atatus/spies/elasticsearch.rb +54 -39
- data/lib/atatus/spies/faraday.rb +92 -58
- data/lib/atatus/spies/http.rb +33 -37
- data/lib/atatus/spies/json.rb +5 -9
- data/lib/atatus/spies/mongo.rb +26 -19
- data/lib/atatus/spies/net_http.rb +53 -51
- data/lib/atatus/spies/racecar.rb +77 -0
- data/lib/atatus/spies/rake.rb +27 -27
- data/lib/atatus/spies/redis.rb +11 -12
- data/lib/atatus/spies/resque.rb +18 -23
- data/lib/atatus/spies/s3.rb +132 -0
- data/lib/atatus/spies/sequel.rb +50 -40
- data/lib/atatus/spies/shoryuken.rb +4 -6
- data/lib/atatus/spies/sidekiq.rb +23 -31
- data/lib/atatus/spies/sinatra.rb +20 -28
- data/lib/atatus/spies/sneakers.rb +2 -0
- data/lib/atatus/spies/sns.rb +126 -0
- data/lib/atatus/spies/sqs.rb +231 -0
- data/lib/atatus/spies/sucker_punch.rb +20 -22
- data/lib/atatus/spies/tilt.rb +10 -13
- data/lib/atatus/spies.rb +20 -0
- data/lib/atatus/sql/signature.rb +4 -2
- data/lib/atatus/sql/tokenizer.rb +23 -7
- data/lib/atatus/stacktrace/frame.rb +1 -0
- data/lib/atatus/stacktrace_builder.rb +12 -16
- data/lib/atatus/subscriber.rb +1 -0
- data/lib/atatus/trace_context/traceparent.rb +5 -8
- data/lib/atatus/trace_context/tracestate.rb +16 -14
- data/lib/atatus/trace_context.rb +6 -16
- data/lib/atatus/transaction.rb +25 -4
- data/lib/atatus/transport/base.rb +1 -3
- data/lib/atatus/transport/connection/http.rb +11 -3
- data/lib/atatus/transport/connection/proxy_pipe.rb +1 -2
- data/lib/atatus/transport/connection.rb +3 -2
- data/lib/atatus/transport/filters/hash_sanitizer.rb +16 -34
- data/lib/atatus/transport/filters/secrets_filter.rb +35 -12
- data/lib/atatus/transport/serializers/context_serializer.rb +1 -2
- data/lib/atatus/transport/serializers/metadata_serializer.rb +54 -8
- data/lib/atatus/transport/serializers/metricset_serializer.rb +2 -2
- data/lib/atatus/transport/serializers/span_serializer.rb +55 -9
- data/lib/atatus/transport/serializers/transaction_serializer.rb +1 -0
- data/lib/atatus/transport/serializers.rb +9 -6
- data/lib/atatus/transport/user_agent.rb +16 -9
- data/lib/atatus/transport/worker.rb +2 -1
- data/lib/atatus/util/deep_dup.rb +65 -0
- data/lib/atatus/util/precision_validator.rb +46 -0
- data/lib/atatus/util.rb +2 -0
- data/lib/atatus/version.rb +1 -1
- data/lib/atatus.rb +48 -5
- metadata +41 -11
data/lib/atatus/grpc.rb
CHANGED
@@ -25,7 +25,7 @@ module Atatus
|
|
25
25
|
TYPE = 'external'
|
26
26
|
SUBTYPE = 'grpc'
|
27
27
|
|
28
|
-
# rubocop:disable Lint/UnusedMethodArgument
|
28
|
+
# rubocop:disable Lint/UnusedMethodArgument, Style/ExplicitBlockArgument
|
29
29
|
def request_response(request:, call:, method:, metadata:)
|
30
30
|
return yield unless (transaction = Atatus.current_transaction)
|
31
31
|
if (trace_context = transaction.trace_context)
|
@@ -40,7 +40,7 @@ module Atatus
|
|
40
40
|
yield
|
41
41
|
end
|
42
42
|
end
|
43
|
-
# rubocop:enable Lint/UnusedMethodArgument
|
43
|
+
# rubocop:enable Lint/UnusedMethodArgument, Style/ExplicitBlockArgument
|
44
44
|
|
45
45
|
private
|
46
46
|
|
@@ -50,11 +50,9 @@ module Atatus
|
|
50
50
|
|
51
51
|
split_peer = URI.split(peer)
|
52
52
|
destination = Atatus::Span::Context::Destination.new(
|
53
|
-
type: TYPE,
|
54
|
-
name: SUBTYPE,
|
55
|
-
resource: peer,
|
56
53
|
address: split_peer[0],
|
57
|
-
port: split_peer[6]
|
54
|
+
port: split_peer[6],
|
55
|
+
service: { type: TYPE, name: SUBTYPE, resource: peer }
|
58
56
|
)
|
59
57
|
Atatus::Span::Context.new(destination: destination)
|
60
58
|
end
|
@@ -71,7 +69,7 @@ module Atatus
|
|
71
69
|
transaction.done 'success'
|
72
70
|
rescue ::Exception => e
|
73
71
|
Atatus.report(e, handled: false)
|
74
|
-
transaction
|
72
|
+
transaction&.done 'error'
|
75
73
|
raise
|
76
74
|
ensure
|
77
75
|
Atatus.end_transaction
|
data/lib/atatus/instrumenter.rb
CHANGED
@@ -89,7 +89,7 @@ module Atatus
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def subscriber=(subscriber)
|
92
|
-
debug 'Registering subscriber'
|
92
|
+
debug 'Registering ActiveSupport::Notifications subscriber'
|
93
93
|
@subscriber = subscriber
|
94
94
|
@subscriber.register!
|
95
95
|
end
|
@@ -120,11 +120,11 @@ module Atatus
|
|
120
120
|
end
|
121
121
|
|
122
122
|
if trace_context
|
123
|
-
|
123
|
+
sampled = trace_context.recorded?
|
124
124
|
sample_rate = trace_context.tracestate.sample_rate
|
125
125
|
else
|
126
126
|
sampled = random_sample?(config)
|
127
|
-
sample_rate = config.transaction_sample_rate
|
127
|
+
sample_rate = sampled ? config.transaction_sample_rate : 0
|
128
128
|
end
|
129
129
|
|
130
130
|
transaction =
|
@@ -150,7 +150,9 @@ module Atatus
|
|
150
150
|
|
151
151
|
transaction.done result
|
152
152
|
|
153
|
-
|
153
|
+
if transaction.sampled? || @config.version < Config::ServerInfo::VERSION_8_0
|
154
|
+
enqueue.call transaction
|
155
|
+
end
|
154
156
|
|
155
157
|
update_transaction_metrics(transaction)
|
156
158
|
|
@@ -179,7 +181,8 @@ module Atatus
|
|
179
181
|
context: nil,
|
180
182
|
trace_context: nil,
|
181
183
|
parent: nil,
|
182
|
-
sync: nil
|
184
|
+
sync: nil,
|
185
|
+
exit_span: nil
|
183
186
|
)
|
184
187
|
|
185
188
|
transaction =
|
@@ -197,6 +200,15 @@ module Atatus
|
|
197
200
|
|
198
201
|
parent ||= (current_span || current_transaction)
|
199
202
|
|
203
|
+
# To not mess with breakdown metric stats, exit spans MUST not add
|
204
|
+
# sub-spans unless they share the same type and subtype.
|
205
|
+
if parent && parent.is_a?(Span) && parent.exit_span?
|
206
|
+
if parent.type != type || parent.subtype != subtype
|
207
|
+
debug "Skipping new span '#{name}' as its parent is an exit_span"
|
208
|
+
return
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
200
212
|
span = Span.new(
|
201
213
|
name: name,
|
202
214
|
subtype: subtype,
|
@@ -207,7 +219,8 @@ module Atatus
|
|
207
219
|
type: type,
|
208
220
|
context: context,
|
209
221
|
stacktrace_builder: stacktrace_builder,
|
210
|
-
sync: sync
|
222
|
+
sync: sync,
|
223
|
+
exit_span: exit_span
|
211
224
|
)
|
212
225
|
|
213
226
|
if backtrace && transaction.span_frames_min_duration
|
@@ -222,8 +235,14 @@ module Atatus
|
|
222
235
|
# rubocop:enable Metrics/CyclomaticComplexity
|
223
236
|
# rubocop:enable Metrics/PerceivedComplexity
|
224
237
|
|
225
|
-
def end_span
|
226
|
-
|
238
|
+
def end_span(span = nil)
|
239
|
+
if span
|
240
|
+
current_spans.delete(span)
|
241
|
+
else
|
242
|
+
span = current_spans.pop
|
243
|
+
end
|
244
|
+
|
245
|
+
return unless span
|
227
246
|
|
228
247
|
span.done
|
229
248
|
|
@@ -239,7 +258,7 @@ module Atatus
|
|
239
258
|
def set_label(key, value)
|
240
259
|
return unless current_transaction
|
241
260
|
|
242
|
-
key = key.to_s.gsub(/[
|
261
|
+
key = key.to_s.gsub(/[."*]/, '_').to_sym
|
243
262
|
current_transaction.context.labels[key] = value
|
244
263
|
end
|
245
264
|
|
@@ -253,6 +272,16 @@ module Atatus
|
|
253
272
|
current_transaction.set_user(user)
|
254
273
|
end
|
255
274
|
|
275
|
+
def set_company(company)
|
276
|
+
return unless current_transaction
|
277
|
+
current_transaction.set_company(company)
|
278
|
+
end
|
279
|
+
|
280
|
+
def set_response_body(response_body)
|
281
|
+
return unless current_transaction
|
282
|
+
current_transaction.set_response_body(response_body)
|
283
|
+
end
|
284
|
+
|
256
285
|
def inspect
|
257
286
|
'<Atatus::Instrumenter ' \
|
258
287
|
"current_transaction=#{current_transaction.inspect}" \
|
@@ -273,24 +302,9 @@ module Atatus
|
|
273
302
|
'transaction.type': transaction.type
|
274
303
|
}
|
275
304
|
|
276
|
-
@metrics.get(:transaction).timer(
|
277
|
-
:'transaction.duration.sum.us',
|
278
|
-
tags: tags, reset_on_collect: true
|
279
|
-
).update(transaction.duration)
|
280
|
-
|
281
|
-
@metrics.get(:transaction).counter(
|
282
|
-
:'transaction.duration.count',
|
283
|
-
tags: tags, reset_on_collect: true
|
284
|
-
).inc!
|
285
|
-
|
286
305
|
return unless transaction.sampled?
|
287
306
|
return unless transaction.breakdown_metrics
|
288
307
|
|
289
|
-
@metrics.get(:breakdown).counter(
|
290
|
-
:'transaction.breakdown.count',
|
291
|
-
tags: tags, reset_on_collect: true
|
292
|
-
).inc!
|
293
|
-
|
294
308
|
span_tags = tags.merge('span.type': 'app')
|
295
309
|
|
296
310
|
@metrics.get(:breakdown).timer(
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
+
# not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
require "http"
|
21
|
+
|
22
|
+
module Atatus
|
23
|
+
class Metadata
|
24
|
+
# @api private
|
25
|
+
class CloudInfo
|
26
|
+
include Logging
|
27
|
+
|
28
|
+
AWS_URI = "http://169.254.169.254/latest/dynamic/instance-identity/document"
|
29
|
+
GCP_URI = "http://metadata.google.internal/computeMetadata/v1/?recursive=true"
|
30
|
+
AZURE_URI = "http://169.254.169.254/metadata/instance/compute?api-version=2019-08-15"
|
31
|
+
|
32
|
+
def initialize(config)
|
33
|
+
@config = config
|
34
|
+
@client = HTTP.timeout(connect: 0.1, read: 0.1)
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :config
|
38
|
+
|
39
|
+
attr_accessor(
|
40
|
+
:account_id,
|
41
|
+
:account_name,
|
42
|
+
:instance_id,
|
43
|
+
:instance_name,
|
44
|
+
:machine_type,
|
45
|
+
:project_id,
|
46
|
+
:project_name,
|
47
|
+
:availability_zone,
|
48
|
+
:provider,
|
49
|
+
:region
|
50
|
+
)
|
51
|
+
|
52
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
53
|
+
def fetch!
|
54
|
+
case config.cloud_provider
|
55
|
+
when "aws"
|
56
|
+
fetch_aws
|
57
|
+
when "gcp"
|
58
|
+
fetch_gcp
|
59
|
+
when "azure"
|
60
|
+
fetch_azure || read_azure_app_services
|
61
|
+
when "auto"
|
62
|
+
fetch_aws || fetch_gcp || fetch_azure || read_azure_app_services
|
63
|
+
when "none"
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
error("Unknown setting for cloud_provider '#{config.cloud_provider}'")
|
67
|
+
end
|
68
|
+
|
69
|
+
self
|
70
|
+
end
|
71
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def fetch_aws
|
76
|
+
resp = @client.get(AWS_URI)
|
77
|
+
|
78
|
+
return unless resp.status == 200
|
79
|
+
return unless (metadata = JSON.parse(resp.body.to_s))
|
80
|
+
|
81
|
+
self.provider = "aws"
|
82
|
+
self.account_id = metadata["accountId"]
|
83
|
+
self.instance_id = metadata["instanceId"]
|
84
|
+
self.availability_zone = metadata["availabilityZone"]
|
85
|
+
self.machine_type = metadata["instanceType"]
|
86
|
+
self.region = metadata["region"]
|
87
|
+
rescue HTTP::TimeoutError, HTTP::ConnectionError
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetch_gcp
|
92
|
+
resp = @client.headers("Metadata-Flavor" => "Google").get(GCP_URI)
|
93
|
+
|
94
|
+
return unless resp.status == 200
|
95
|
+
return unless (metadata = JSON.parse(resp.body.to_s))
|
96
|
+
|
97
|
+
zone = metadata["instance"]["zone"]&.split("/")&.at(-1)
|
98
|
+
|
99
|
+
self.provider = "gcp"
|
100
|
+
self.instance_id = metadata["instance"]["id"].to_s
|
101
|
+
self.instance_name = metadata["instance"]["name"]
|
102
|
+
self.project_id = metadata["project"]["projectId"]
|
103
|
+
self.availability_zone = zone
|
104
|
+
self.region = zone.split("-")[0..-2].join("-")
|
105
|
+
self.machine_type = metadata["instance"]["machineType"].split("/")[-1]
|
106
|
+
rescue HTTP::TimeoutError, HTTP::ConnectionError
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def fetch_azure
|
111
|
+
resp = @client.headers("Metadata" => "true").get(AZURE_URI)
|
112
|
+
|
113
|
+
return unless resp.status == 200
|
114
|
+
return unless (metadata = JSON.parse(resp.body.to_s))
|
115
|
+
|
116
|
+
self.provider = 'azure'
|
117
|
+
self.account_id = metadata["subscriptionId"]
|
118
|
+
self.instance_id = metadata["vmId"]
|
119
|
+
self.instance_name = metadata["name"]
|
120
|
+
self.project_name = metadata["resourceGroupName"]
|
121
|
+
self.availability_zone = metadata["zone"]
|
122
|
+
self.machine_type = metadata["vmSize"]
|
123
|
+
self.region = metadata["location"]
|
124
|
+
rescue HTTP::TimeoutError, HTTP::ConnectionError
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def read_azure_app_services
|
129
|
+
owner_name, instance_id, site_name, resource_group =
|
130
|
+
ENV.values_at(
|
131
|
+
'WEBSITE_OWNER_NAME',
|
132
|
+
'WEBSITE_INSTANCE_ID',
|
133
|
+
'WEBSITE_SITE_NAME',
|
134
|
+
'WEBSITE_RESOURCE_GROUP'
|
135
|
+
)
|
136
|
+
|
137
|
+
return unless owner_name && instance_id && site_name && resource_group
|
138
|
+
|
139
|
+
self.provider = 'azure'
|
140
|
+
self.instance_id = instance_id
|
141
|
+
self.instance_name = site_name
|
142
|
+
self.project_name = resource_group
|
143
|
+
self.account_id, self.region = parse_azure_app_services_owner_name(owner_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def parse_azure_app_services_owner_name(owner_name)
|
149
|
+
id, rest = owner_name.split('+')
|
150
|
+
*_, region = rest.split('-')
|
151
|
+
region.gsub!(/webspace.*$/, '')
|
152
|
+
[id, region]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -49,11 +49,11 @@ module Atatus
|
|
49
49
|
)
|
50
50
|
@language = Language.new(name: 'ruby', version: RUBY_VERSION)
|
51
51
|
@runtime = lookup_runtime
|
52
|
-
@version = @config.service_version
|
52
|
+
@version = @config.service_version
|
53
53
|
end
|
54
54
|
|
55
|
-
attr_reader :name, :node_name, :environment, :agent, :framework,
|
56
|
-
:runtime, :version
|
55
|
+
attr_reader :name, :node_name, :environment, :agent, :framework,
|
56
|
+
:language, :runtime, :version
|
57
57
|
|
58
58
|
private
|
59
59
|
|
@@ -33,14 +33,15 @@ module Atatus
|
|
33
33
|
|
34
34
|
attr_reader :cgroup_path
|
35
35
|
|
36
|
-
def read!
|
36
|
+
def read!(hostname)
|
37
37
|
read_from_cgroup!
|
38
|
+
self.kubernetes_pod_name = hostname if kubernetes_pod_uid
|
38
39
|
read_from_env!
|
39
40
|
self
|
40
41
|
end
|
41
42
|
|
42
|
-
def self.read!
|
43
|
-
new.read!
|
43
|
+
def self.read!(hostname)
|
44
|
+
new.read!(hostname)
|
44
45
|
end
|
45
46
|
|
46
47
|
def container
|
@@ -81,15 +82,23 @@ module Atatus
|
|
81
82
|
ENV.fetch('KUBERNETES_POD_UID', kubernetes_pod_uid)
|
82
83
|
end
|
83
84
|
|
85
|
+
# rubocop:disable Style/RegexpLiteral
|
84
86
|
CONTAINER_ID_REGEXES = [
|
85
87
|
%r{^[[:xdigit:]]{64}$},
|
86
|
-
%r{
|
87
|
-
|
88
|
+
%r{
|
89
|
+
^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]
|
90
|
+
{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4,}$
|
91
|
+
}x
|
92
|
+
].freeze
|
88
93
|
KUBEPODS_REGEXES = [
|
89
94
|
%r{(?:^/kubepods[^\s]*/pod([^/]+)$)},
|
90
|
-
%r{
|
91
|
-
|
95
|
+
%r{
|
96
|
+
(?:^/kubepods\.slice/(kubepods-[^/]+\.slice/)?
|
97
|
+
kubepods[^/]*-pod([^/]+)\.slice$)
|
98
|
+
}x
|
99
|
+
].freeze
|
92
100
|
SYSTEMD_SCOPE_SUFFIX = '.scope'
|
101
|
+
# rubocop:enable Style/RegexpLiteral
|
93
102
|
|
94
103
|
# rubocop:disable Metrics/PerceivedComplexity
|
95
104
|
# rubocop:disable Metrics/CyclomaticComplexity
|
@@ -125,7 +134,10 @@ module Atatus
|
|
125
134
|
end
|
126
135
|
|
127
136
|
if (kubepods_match = match_kubepods(directory))
|
128
|
-
pod_id = kubepods_match[1]
|
137
|
+
unless (pod_id = kubepods_match[1])
|
138
|
+
pod_id = kubepods_match[2]
|
139
|
+
pod_id&.tr!('_', '-')
|
140
|
+
end
|
129
141
|
|
130
142
|
self.container_id = container_id
|
131
143
|
self.kubernetes_pod_uid = pod_id
|
@@ -24,11 +24,13 @@ module Atatus
|
|
24
24
|
def initialize(config)
|
25
25
|
@config = config
|
26
26
|
|
27
|
-
@
|
27
|
+
@configured_hostname = @config.hostname
|
28
|
+
@detected_hostname = detect_hostname
|
29
|
+
@hostname = @configured_hostname || @detected_hostname
|
28
30
|
@architecture = gem_platform.cpu
|
29
31
|
@platform = gem_platform.os
|
30
32
|
|
31
|
-
container_info = ContainerInfo.read!
|
33
|
+
container_info = ContainerInfo.read!(@detected_hostname)
|
32
34
|
@container = container_info.container
|
33
35
|
@kubernetes = container_info.kubernetes
|
34
36
|
|
@@ -36,14 +38,27 @@ module Atatus
|
|
36
38
|
@osinfo = OSInfo.read!
|
37
39
|
end
|
38
40
|
|
39
|
-
attr_reader
|
41
|
+
attr_reader(
|
42
|
+
:detected_hostname,
|
43
|
+
:configured_hostname,
|
44
|
+
:architecture,
|
45
|
+
:platform,
|
46
|
+
:container,
|
47
|
+
:kubernetes,
|
48
|
+
:hwinfo,
|
49
|
+
:osinfo,
|
50
|
+
:hostname
|
51
|
+
)
|
40
52
|
|
41
53
|
def gem_platform
|
42
54
|
@gem_platform ||= Gem::Platform.local
|
43
55
|
end
|
44
56
|
|
45
|
-
|
46
|
-
|
57
|
+
private
|
58
|
+
|
59
|
+
def detect_hostname
|
60
|
+
Socket.gethostname.chomp
|
61
|
+
rescue
|
47
62
|
end
|
48
63
|
end
|
49
64
|
end
|
data/lib/atatus/metadata.rb
CHANGED
@@ -25,12 +25,14 @@ module Atatus
|
|
25
25
|
@process = ProcessInfo.new(config)
|
26
26
|
@system = SystemInfo.new(config)
|
27
27
|
@labels = config.global_labels
|
28
|
+
@cloud = CloudInfo.new(config).fetch!
|
28
29
|
end
|
29
30
|
|
30
|
-
attr_reader :service, :process, :system, :labels
|
31
|
+
attr_reader :service, :process, :system, :cloud, :labels
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
require 'atatus/metadata/service_info'
|
35
36
|
require 'atatus/metadata/system_info'
|
36
37
|
require 'atatus/metadata/process_info'
|
38
|
+
require 'atatus/metadata/cloud_info'
|
@@ -60,11 +60,10 @@ module Atatus
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def initialize(config)
|
63
|
-
@vmset_disabled = false
|
64
63
|
super
|
65
64
|
|
66
|
-
@sampler =
|
67
|
-
read! # set
|
65
|
+
@sampler = sampler_for_os(Metrics.os)
|
66
|
+
read! # set initial values to calculate deltas from
|
68
67
|
end
|
69
68
|
|
70
69
|
attr_reader :config
|
@@ -76,19 +75,11 @@ module Atatus
|
|
76
75
|
|
77
76
|
private
|
78
77
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
def vmset_disabled?
|
84
|
-
@vmset_disabled
|
85
|
-
end
|
86
|
-
|
87
|
-
def sampler_for_platform(platform)
|
88
|
-
case platform
|
89
|
-
when :linux then Linux.new
|
78
|
+
def sampler_for_os(os)
|
79
|
+
case os
|
80
|
+
when /^linux/ then Linux.new
|
90
81
|
else
|
91
|
-
warn "
|
82
|
+
warn "Disabling system metrics, unsupported host OS '#{os}'"
|
92
83
|
disable!
|
93
84
|
nil
|
94
85
|
end
|
@@ -115,29 +106,6 @@ module Atatus
|
|
115
106
|
current.process_memory_rss * current.page_size
|
116
107
|
|
117
108
|
@previous = current
|
118
|
-
|
119
|
-
return if vmset_disabled?
|
120
|
-
|
121
|
-
stat = GC.stat
|
122
|
-
|
123
|
-
gauge(:'ruby.gc.count').value = stat[:count]
|
124
|
-
gauge(:'ruby.threads').value = Thread.list.count
|
125
|
-
gauge(:'ruby.heap.slots.live').value = stat[:heap_live_slots]
|
126
|
-
|
127
|
-
gauge(:'ruby.heap.slots.free').value = stat[:heap_free_slots]
|
128
|
-
gauge(:'ruby.heap.allocations.total').value =
|
129
|
-
stat[:total_allocated_objects]
|
130
|
-
|
131
|
-
return unless GC::Profiler.enabled?
|
132
|
-
@total_time ||= 0
|
133
|
-
@total_time += GC::Profiler.total_time
|
134
|
-
GC::Profiler.clear
|
135
|
-
gauge(:'ruby.gc.time').value = @total_time
|
136
|
-
rescue TypeError => e
|
137
|
-
error 'VM metrics encountered error: %s', e
|
138
|
-
debug('Backtrace:') { e.backtrace.join("\n") }
|
139
|
-
|
140
|
-
vmset_disable!
|
141
109
|
end
|
142
110
|
|
143
111
|
def calculate_deltas(current, previous)
|
@@ -148,6 +116,9 @@ module Atatus
|
|
148
116
|
process_cpu_usage =
|
149
117
|
current.process_cpu_usage - previous.process_cpu_usage
|
150
118
|
|
119
|
+
# No change / avoid dividing by 0
|
120
|
+
return [0, 0] if system_cpu_total == 0
|
121
|
+
|
151
122
|
cpu_usage_pct = system_cpu_usage.to_f / system_cpu_total
|
152
123
|
cpu_process_pct = process_cpu_usage.to_f / system_cpu_total
|
153
124
|
|
@@ -246,6 +217,7 @@ module Atatus
|
|
246
217
|
# @api private
|
247
218
|
class Meminfo
|
248
219
|
attr_reader :total, :available, :page_size
|
220
|
+
|
249
221
|
# rubocop:disable Metrics/PerceivedComplexity
|
250
222
|
# rubocop:disable Metrics/CyclomaticComplexity
|
251
223
|
def read!
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
+
# not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# frozen_string_literal: true
|
19
|
+
|
20
|
+
require 'java'
|
21
|
+
|
22
|
+
module Atatus
|
23
|
+
module Metrics
|
24
|
+
# @api private
|
25
|
+
class JVMSet < Set
|
26
|
+
include Logging
|
27
|
+
|
28
|
+
MAX_TRIES = 3
|
29
|
+
|
30
|
+
def initialize(*args)
|
31
|
+
super
|
32
|
+
|
33
|
+
@error_count = 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def collect
|
37
|
+
read!
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def read!
|
42
|
+
return if disabled?
|
43
|
+
|
44
|
+
heap = platform_bean.get_heap_memory_usage
|
45
|
+
non_heap = platform_bean.get_non_heap_memory_usage
|
46
|
+
|
47
|
+
gauge(:"jvm.memory.heap.used").value = heap.get_used
|
48
|
+
gauge(:"jvm.memory.heap.committed").value = heap.get_committed
|
49
|
+
gauge(:"jvm.memory.heap.max").value = heap.get_max
|
50
|
+
|
51
|
+
gauge(:"jvm.memory.non_heap.used").value = non_heap.get_used
|
52
|
+
gauge(:"jvm.memory.non_heap.committed").value = non_heap.get_committed
|
53
|
+
gauge(:"jvm.memory.non_heap.max").value = non_heap.get_max
|
54
|
+
|
55
|
+
pool_beans.each do |bean|
|
56
|
+
next unless bean.type.name == "HEAP"
|
57
|
+
|
58
|
+
tags = { name: bean.get_name }
|
59
|
+
|
60
|
+
gauge(:"jvm.memory.heap.pool.used", tags: tags).value = bean.get_usage.get_used
|
61
|
+
gauge(:"jvm.memory.heap.pool.committed", tags: tags).value = bean.get_usage.get_committed
|
62
|
+
gauge(:"jvm.memory.heap.pool.max", tags: tags).value = bean.get_usage.get_max
|
63
|
+
end
|
64
|
+
rescue Exception => e
|
65
|
+
error("JVM metrics encountered error: %s", e)
|
66
|
+
debug("Backtrace:") { e.backtrace.join("\n") }
|
67
|
+
|
68
|
+
@error_count += 1
|
69
|
+
if @error_count >= MAX_TRIES
|
70
|
+
disable!
|
71
|
+
error("Disabling JVM metrics after #{MAX_TRIES} errors", e)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def platform_bean
|
78
|
+
@platform_bean ||= java.lang.management.ManagementFactory.getPlatformMXBean(
|
79
|
+
java.lang.management.MemoryMXBean.java_class
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def pool_beans
|
84
|
+
@pool_beans ||= java.lang.management.ManagementFactory.getMemoryPoolMXBeans()
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|