elastic-apm 3.8.0 → 3.11.1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.asciidoc +72 -0
  3. data/Gemfile +2 -3
  4. data/docs/configuration.asciidoc +1 -0
  5. data/docs/debugging.asciidoc +14 -0
  6. data/docs/supported-technologies.asciidoc +2 -1
  7. data/lib/elastic_apm/config.rb +32 -5
  8. data/lib/elastic_apm/config/options.rb +2 -1
  9. data/lib/elastic_apm/config/round_float.rb +31 -0
  10. data/lib/elastic_apm/config/wildcard_pattern_list.rb +13 -1
  11. data/lib/elastic_apm/context_builder.rb +1 -1
  12. data/lib/elastic_apm/instrumenter.rb +10 -3
  13. data/lib/elastic_apm/metadata.rb +3 -1
  14. data/lib/elastic_apm/metadata/cloud_info.rb +128 -0
  15. data/lib/elastic_apm/metadata/system_info.rb +5 -3
  16. data/lib/elastic_apm/metadata/system_info/container_info.rb +28 -4
  17. data/lib/elastic_apm/middleware.rb +8 -2
  18. data/lib/elastic_apm/span.rb +7 -3
  19. data/lib/elastic_apm/spies/delayed_job.rb +4 -2
  20. data/lib/elastic_apm/spies/dynamo_db.rb +58 -0
  21. data/lib/elastic_apm/spies/elasticsearch.rb +11 -1
  22. data/lib/elastic_apm/trace_context.rb +1 -1
  23. data/lib/elastic_apm/trace_context/traceparent.rb +2 -4
  24. data/lib/elastic_apm/trace_context/tracestate.rb +112 -9
  25. data/lib/elastic_apm/transaction.rb +26 -5
  26. data/lib/elastic_apm/transport/connection.rb +1 -0
  27. data/lib/elastic_apm/transport/filters/hash_sanitizer.rb +9 -16
  28. data/lib/elastic_apm/transport/filters/secrets_filter.rb +8 -6
  29. data/lib/elastic_apm/transport/serializers.rb +8 -6
  30. data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +43 -3
  31. data/lib/elastic_apm/transport/serializers/span_serializer.rb +2 -1
  32. data/lib/elastic_apm/transport/serializers/transaction_serializer.rb +1 -0
  33. data/lib/elastic_apm/transport/user_agent.rb +3 -3
  34. data/lib/elastic_apm/transport/worker.rb +5 -0
  35. data/lib/elastic_apm/util.rb +2 -0
  36. data/lib/elastic_apm/util/precision_validator.rb +46 -0
  37. data/lib/elastic_apm/version.rb +1 -1
  38. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32d176ac5c22246df60ecc92f1baad37011a872af4e64f842b5a43c699a6ced3
4
- data.tar.gz: bf0505e728d8f1bd0bb941574a844a8990d14e13a94a7c9f2a6c2d0f9eb5d35b
3
+ metadata.gz: 54d7b5d46523e74fc797ec2030a355b6137e92a40ecb8242a9a79d551d6b2f89
4
+ data.tar.gz: ba614dd32ce665845f09d9c840fff0f6e8a34637a703f849a7b22edbeb350d25
5
5
  SHA512:
6
- metadata.gz: d57b6bdbc7e78bea95e197d33f3eef4db7a35b23f9e450c636c3c1e3a5dd75ee8ee195709944ac51d6af7a3ab2451fd19d6139f0dedf9e86a4827732d5097f2a
7
- data.tar.gz: 924b9bbf782a0fa4e376137e9a44d10cc01be71455ca7614ab1374c70f0926d174eb1078b985cd60c1693e2e0ec1cdd8446502bd40007359262dcc31241250aa
6
+ metadata.gz: fd0d35a56be409fd3ee55352d68a9ef7cfd13add082edb41ca971bde54895c70babd30025e6a87134123a999be2732b476a8868b3db617b9f315940124f8e2ad
7
+ data.tar.gz: 75e7e737b4f927dbbbb6b828ae5c628b3e37334409a43b1e94cc09cb9b403dcbb7030e766e49cadba9683536032119514f022570abb97c066fce6a59959dbf6f
@@ -35,6 +35,78 @@ endif::[]
35
35
  [[release-notes-3.x]]
36
36
  === Ruby Agent version 3.x
37
37
 
38
+ [[release-notes-3.11.1]]
39
+ ==== 3.11.1 (2020-11-05)
40
+
41
+ [float]
42
+ ===== Fixed
43
+
44
+ - Fix reporting from Kubernetes based deploys to APM Server 7.9.x {pull}885[#885]
45
+
46
+ [[release-notes-3.11.0]]
47
+ ==== 3.11.0 (2020-10-27)
48
+
49
+ [float]
50
+ ===== Added
51
+
52
+ - Add and read sampling info from Tracestate headers {pull}858[#858]
53
+ - Add information about cloud hosting environment if available {pull}871[#871]
54
+
55
+ [float]
56
+ ===== Changed
57
+
58
+ - Align the default value of `sanitize_field_names` with other agents {pull}867[#867]
59
+ - Ensure max 4 digits of precision for `sample_rate` as per agent spec {pull}880[#880]
60
+
61
+ [float]
62
+ ===== Fixed
63
+
64
+ - Fix Delayed::Job class names when used through ActiveJob {pull}869[#869]
65
+ - Fix Delayed::Job when run without the agent running {pull}874[#874]
66
+ - Fix Kubernetes related metadata {pull}882[#882]
67
+
68
+ [[release-notes-3.10.1]]
69
+ ==== 3.10.1 (2020-08-26)
70
+
71
+ [float]
72
+ ===== Fixed
73
+
74
+ - Remove secrets from cookies in errors {pull}863[#863]
75
+ - Silence deprecation warning when setting `ignore_url_patterns` to default {pull}865[#865]
76
+
77
+ [[release-notes-3.10.0]]
78
+ ==== 3.10.0 (2020-08-26)
79
+
80
+ [float]
81
+ ===== Added
82
+
83
+ - Config option `transaction_ignore_urls` to replace `ignore_url_patterns` {pull}844[#844]
84
+ - Prepend `(?-i)` to patterns to make them case-sensitive {pull}846[#846]
85
+
86
+ [float]
87
+ ===== Fixed
88
+
89
+ - Reverted {pull}839[#839]
90
+ - Improved Kubernetes pod ID detection {pull}859[#859]
91
+
92
+ [[release-notes-3.9.0]]
93
+ ==== 3.9.0 (2020-08-04)
94
+
95
+ [float]
96
+ ===== Fixed
97
+ - Scrub request body of illegal UTF-8 characters {pull}832[#832]
98
+
99
+ [float]
100
+ ===== Added
101
+
102
+ - Support for DynamoDB {pull}827[#827]
103
+
104
+ [float]
105
+ ===== Fixed
106
+
107
+ - Fix Rails Engine views' paths being reported as absolute {pull}839[#839]
108
+ - Fix an issue when using Elasticsearch spy without a running agent {pull}830[#830]
109
+
38
110
  [[release-notes-3.8.0]]
39
111
  ==== 3.8.0 (2020-06-18)
40
112
 
data/Gemfile CHANGED
@@ -22,18 +22,16 @@ 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
26
  gem 'pry'
28
27
  gem 'rack-test'
29
28
  gem 'rspec', '~> 3'
30
29
  gem 'rspec-its'
31
- gem 'rubocop', require: nil
32
- gem 'rubocop-performance', require: nil
33
30
  gem 'timecop'
34
31
  gem 'webmock'
35
32
 
36
33
  # Integrations
34
+ gem 'aws-sdk-dynamodb', require: nil
37
35
  gem 'aws-sdk-sqs', require: nil
38
36
  gem 'elasticsearch', require: nil
39
37
  gem 'fakeredis', require: nil
@@ -41,6 +39,7 @@ gem 'faraday', require: nil
41
39
  gem 'graphql', require: nil
42
40
  gem 'google-protobuf', '< 3.12' if !defined?(JRUBY_VERSION) && RUBY_VERSION < '2.5'
43
41
  gem 'grpc' if !defined?(JRUBY_VERSION)
42
+ gem 'json'
44
43
  gem 'json-schema', require: nil
45
44
  gem 'mongo', require: nil
46
45
  gem 'opentracing', require: nil
@@ -853,6 +853,7 @@ To reduce overhead and storage requirements, you can set the sample rate to a va
853
853
  between `0.0` and `1.0`.
854
854
  We still record overall time and the result for unsampled transactions, but no
855
855
  context information, tags, or spans.
856
+ Note that the sample rate will be rounded to 4 digits of precision.
856
857
 
857
858
  [float]
858
859
  [[config-use-experimental-sql-parser]]
@@ -28,3 +28,17 @@ Things to consider:
28
28
  - Experiencing high load? The agent can spawn multiple instances of its Workers that pick off the queue by changing the option `pool_size` (default is `1`).
29
29
  - If you have high load you may also consider setting `transaction_sample_rate` to something smaller than `1.0`. This determines whether to include _spans_ for every _transaction_. If you have enough traffic, skipping some (probably) identical spans won't have a noticeable effect on your data.
30
30
 
31
+ [float]
32
+ [[disable-agent]]
33
+ === Disable the Agent
34
+
35
+ In the unlikely event the agent causes disruptions to a production application,
36
+ you can disable the agent while you troubleshoot.
37
+
38
+ If you have access to <<dynamic-configuration,dynamic configuration>>,
39
+ you can disable the recording of events by setting <<config-recording,`recording`>> to `false`.
40
+ When changed at runtime from a supported source, there's no need to restart your application.
41
+
42
+ If that doesn't work, or you don't have access to dynamic configuration, you can disable the agent by setting
43
+ <<config-enabled,`enabled`>> to `false`.
44
+ You'll need to restart your application for the changes to apply.
@@ -60,6 +60,7 @@ See <<getting-started-grape>>.
60
60
  We automatically instrument database actions using:
61
61
 
62
62
  - ActiveRecord (v4.2+)
63
+ - DynamoDB (v1.0+)
63
64
  - Elasticsearch (v0.9+)
64
65
  - Mongo (v2.1+)
65
66
  - Redis (v3.1+)
@@ -151,4 +152,4 @@ To instrument a server, add the `ElasticAPM::GRPC::ServerInterceptor`.
151
152
  [source,ruby]
152
153
  ----
153
154
  GRPC::RpcServer.new(interceptors: [ElasticAPM::GRPC::ServerInterceptor.new])
154
- ----
155
+ ----
@@ -17,9 +17,10 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'elastic_apm/config/options'
21
- require 'elastic_apm/config/duration'
22
20
  require 'elastic_apm/config/bytes'
21
+ require 'elastic_apm/config/duration'
22
+ require 'elastic_apm/config/options'
23
+ require 'elastic_apm/config/round_float'
23
24
  require 'elastic_apm/config/regexp_list'
24
25
  require 'elastic_apm/config/wildcard_pattern_list'
25
26
 
@@ -30,6 +31,11 @@ module ElasticAPM
30
31
 
31
32
  DEPRECATED_OPTIONS = %i[].freeze
32
33
 
34
+ # DEPRECATED: To align with other agents, change on next major bump to:
35
+ # "password, passwd, pwd, secret, *key, *token*, *session*, *credit*, *card*, authorization, set-cookie"
36
+ SANITIZE_FIELD_NAMES_DEFAULT =
37
+ %w[*password* *passwd* *pwd* *secret* *key* *token* *session* *credit* *card* *authorization* *set-cookie*]
38
+
33
39
  # rubocop:disable Metrics/LineLength, Layout/ExtraSpacing
34
40
  option :config_file, type: :string, default: 'config/elastic_apm.yml'
35
41
  option :server_url, type: :url, default: 'http://localhost:8200'
@@ -45,6 +51,7 @@ module ElasticAPM
45
51
  option :capture_elasticsearch_queries, type: :bool, default: false
46
52
  option :capture_env, type: :bool, default: true
47
53
  option :central_config, type: :bool, default: true
54
+ option :cloud_provider, type: :string, default: 'auto'
48
55
  option :current_user_email_method, type: :string, default: 'email'
49
56
  option :current_user_id_method, type: :string, default: 'id'
50
57
  option :current_user_username_method, type: :string, default: 'username'
@@ -76,7 +83,8 @@ module ElasticAPM
76
83
  option :proxy_port, type: :int
77
84
  option :proxy_username, type: :string
78
85
  option :recording, type: :bool, default: true
79
- option :sanitize_field_names, type: :list, default: [], converter: WildcardPatternList.new
86
+ option :sanitize_field_names, type: :list,
87
+ default: SANITIZE_FIELD_NAMES_DEFAULT, converter: WildcardPatternList.new
80
88
  option :server_ca_cert, type: :string
81
89
  option :service_name, type: :string
82
90
  option :service_node_name, type: :string
@@ -87,8 +95,9 @@ module ElasticAPM
87
95
  option :source_lines_span_library_frames, type: :int, default: 0
88
96
  option :span_frames_min_duration, type: :float, default: '5ms', converter: Duration.new(default_unit: 'ms')
89
97
  option :stack_trace_limit, type: :int, default: 999_999
98
+ option :transaction_ignore_urls, type: :list, default: [], converter: WildcardPatternList.new
90
99
  option :transaction_max_spans, type: :int, default: 500
91
- option :transaction_sample_rate, type: :float, default: 1.0
100
+ option :transaction_sample_rate, type: :float, default: 1.0, converter: RoundFloat.new
92
101
  option :use_elastic_traceparent_header, type: :bool, default: true
93
102
  option :use_legacy_sql_parser, type: :bool, default: false
94
103
  option :verify_server_cert, type: :bool, default: true
@@ -131,6 +140,7 @@ module ElasticAPM
131
140
  %w[
132
141
  action_dispatch
133
142
  delayed_job
143
+ dynamo_db
134
144
  elasticsearch
135
145
  faraday
136
146
  http
@@ -187,6 +197,14 @@ module ElasticAPM
187
197
  metrics_interval > 0
188
198
  end
189
199
 
200
+ # DEPRECATED: Remove this in next major version
201
+ def sanitize_field_names=(value)
202
+ list = WildcardPatternList.new.call(value)
203
+ defaults = WildcardPatternList.new.call(SANITIZE_FIELD_NAMES_DEFAULT)
204
+ get(:sanitize_field_names).value =
205
+ defaults.concat(list).uniq(&:pattern) # use regex pattern for comparisons
206
+ end
207
+
190
208
  def span_frames_min_duration?
191
209
  span_frames_min_duration != 0
192
210
  end
@@ -233,6 +251,15 @@ module ElasticAPM
233
251
  self.default_labels = value
234
252
  end
235
253
 
254
+ def ignore_url_patterns=(value)
255
+ unless value == self.class.schema[:ignore_url_patterns][:default]
256
+ warn '[DEPRECATED] The option ignore_url_patterns is being removed. ' \
257
+ 'Consider using transaction_ignore_urls instead.'
258
+ end
259
+
260
+ set(:ignore_url_patterns, value)
261
+ end
262
+
236
263
  def custom_key_filters=(value)
237
264
  unless value == self.class.schema[:custom_key_filters][:default]
238
265
  warn '[DEPRECATED] The option custom_key_filters is being removed. ' \
@@ -317,7 +344,7 @@ module ElasticAPM
317
344
  self.logger ||= ::Rails.logger
318
345
 
319
346
  self.__root_path = ::Rails.root.to_s
320
- self.__view_paths = app.config.paths['app/views'].existent
347
+ self.__view_paths = app.config.paths['app/views'].existent + [::Rails.root.to_s]
321
348
  end
322
349
 
323
350
  def rails_app_name(app)
@@ -38,7 +38,8 @@ module ElasticAPM
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)
@@ -0,0 +1,31 @@
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 'elastic_apm/util/precision_validator'
21
+
22
+ module ElasticAPM
23
+ class Config
24
+ # @api private
25
+ class RoundFloat
26
+ def call(value)
27
+ Util::PrecisionValidator.validate(value, precision: 4, minimum: 0.0001)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -27,6 +27,8 @@ module ElasticAPM
27
27
  @pattern = convert(str)
28
28
  end
29
29
 
30
+ attr_reader :pattern
31
+
30
32
  def match?(other)
31
33
  !!@pattern.match(other)
32
34
  end
@@ -36,12 +38,22 @@ module ElasticAPM
36
38
  private
37
39
 
38
40
  def convert(str)
41
+ case_sensitive = false
42
+
43
+ if str.start_with?('(?-i)')
44
+ str = str.gsub(/^\(\?-\i\)/, '')
45
+ case_sensitive = true
46
+ end
47
+
39
48
  parts =
40
49
  str.chars.each_with_object([]) do |char, arr|
41
50
  arr << (char == '*' ? '.*' : Regexp.escape(char))
42
51
  end
43
52
 
44
- Regexp.new('\A' + parts.join + '\Z', Regexp::IGNORECASE)
53
+ Regexp.new(
54
+ '\A' + parts.join + '\Z',
55
+ case_sensitive ? nil : Regexp::IGNORECASE
56
+ )
45
57
  end
46
58
  end
47
59
 
@@ -76,7 +76,7 @@ module ElasticAPM
76
76
  else
77
77
  body = req.body.read
78
78
  req.body.rewind
79
- body.byteslice(0, MAX_BODY_LENGTH).force_encoding('utf-8')
79
+ body.byteslice(0, MAX_BODY_LENGTH).force_encoding('utf-8').scrub
80
80
  end
81
81
  end
82
82
 
@@ -119,7 +119,13 @@ module ElasticAPM
119
119
  "Already inside #{transaction.inspect}"
120
120
  end
121
121
 
122
- sampled = trace_context ? trace_context.recorded? : random_sample?(config)
122
+ if trace_context
123
+ sampled = trace_context.recorded?
124
+ sample_rate = trace_context.tracestate.sample_rate
125
+ else
126
+ sampled = random_sample?(config)
127
+ sample_rate = config.transaction_sample_rate
128
+ end
123
129
 
124
130
  transaction =
125
131
  Transaction.new(
@@ -128,6 +134,7 @@ module ElasticAPM
128
134
  context: context,
129
135
  trace_context: trace_context,
130
136
  sampled: sampled,
137
+ sample_rate: sample_rate,
131
138
  config: config
132
139
  )
133
140
 
@@ -259,7 +266,7 @@ module ElasticAPM
259
266
  end
260
267
 
261
268
  def update_transaction_metrics(transaction)
262
- return unless transaction.collect_metrics
269
+ return unless transaction.collect_metrics?
263
270
 
264
271
  tags = {
265
272
  'transaction.name': transaction.name,
@@ -298,7 +305,7 @@ module ElasticAPM
298
305
  end
299
306
 
300
307
  def update_span_metrics(span)
301
- return unless span.transaction.breakdown_metrics
308
+ return unless span.transaction.collect_metrics?
302
309
 
303
310
  tags = {
304
311
  'span.type': span.type,
@@ -25,12 +25,14 @@ module ElasticAPM
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 'elastic_apm/metadata/service_info'
35
36
  require 'elastic_apm/metadata/system_info'
36
37
  require 'elastic_apm/metadata/process_info'
38
+ require 'elastic_apm/metadata/cloud_info'
@@ -0,0 +1,128 @@
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 ElasticAPM
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(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
+ def fetch!
53
+ case config.cloud_provider
54
+ when "aws"
55
+ fetch_aws
56
+ when "gcp"
57
+ fetch_gcp
58
+ when "azure"
59
+ fetch_azure
60
+ when "auto"
61
+ fetch_aws || fetch_gcp || fetch_azure
62
+ when "none"
63
+ nil
64
+ else
65
+ error("Unknown setting for cloud_provider '#{config.cloud_provider}'")
66
+ end
67
+
68
+ self
69
+ end
70
+
71
+ private
72
+
73
+ def fetch_aws
74
+ resp = @client.get(AWS_URI)
75
+
76
+ return unless resp.status === 200
77
+ return unless (metadata = JSON.parse(resp.body))
78
+
79
+ self.provider = "aws"
80
+ self.account_id = metadata["accountId"]
81
+ self.instance_id = metadata["instanceId"]
82
+ self.availability_zone = metadata["availabilityZone"]
83
+ self.machine_type = metadata["instanceType"]
84
+ self.region = metadata["region"]
85
+ rescue HTTP::TimeoutError, HTTP::ConnectionError
86
+ nil
87
+ end
88
+
89
+ def fetch_gcp
90
+ resp = @client.headers("Metadata-Flavor" => "Google").get(GCP_URI)
91
+
92
+ return unless resp.status === 200
93
+ return unless (metadata = JSON.parse(resp.body))
94
+
95
+ zone = metadata["instance"]["zone"]&.split("/")&.at(-1)
96
+
97
+ self.provider = "gcp"
98
+ self.instance_id = metadata["instance"]["id"]
99
+ self.instance_name = metadata["instance"]["name"]
100
+ self.project_id = metadata["project"]["numericProjectId"]
101
+ self.project_name = metadata["project"]["projectId"]
102
+ self.availability_zone = zone
103
+ self.region = zone.split("-")[0..-2].join("-")
104
+ self.machine_type = metadata["instance"]["machineType"]
105
+ rescue HTTP::TimeoutError, HTTP::ConnectionError
106
+ nil
107
+ end
108
+
109
+ def fetch_azure
110
+ resp = @client.headers("Metadata" => "true").get(AZURE_URI)
111
+
112
+ return unless resp.status === 200
113
+ return unless (metadata = JSON.parse(resp.body))
114
+
115
+ self.provider = 'azure'
116
+ self.account_id = metadata["subscriptionId"]
117
+ self.instance_id = metadata["vmId"]
118
+ self.instance_name = metadata["name"]
119
+ self.project_name = metadata["resourceGroupName"]
120
+ self.availability_zone = metadata["zone"]
121
+ self.machine_type = metadata["vmSize"]
122
+ self.region = metadata["location"]
123
+ rescue HTTP::TimeoutError, HTTP::ConnectionError
124
+ nil
125
+ end
126
+ end
127
+ end
128
+ end