honeycomb-beeline 1.1.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6af6ff636f882a61957e48a0fe6fb50794d82b237f75009f5f2cc1308dbdafb
4
- data.tar.gz: cb2e735d0bb798150f7232739a9aced2dc372ce8dde81414925cf61b4259be3b
3
+ metadata.gz: 579452ea20fce15d631f43ca535105440ec154e23964e0639ab11d9f81ca6e3d
4
+ data.tar.gz: 2497fda72bbbc1f9b0957e17a551677989a2b0b50e30a3356218632b64f47fc8
5
5
  SHA512:
6
- metadata.gz: 0fb178a760b813ff7f26aa4a60650b7d9a1556041366fc65162b3132ec8926126aa066056329f49eaacbafacf5e33b559e740464a7957c48e54ecb071433536a
7
- data.tar.gz: 29c941bffdcdc5766de32665b87ad6d705f57f17c86dbdb75581519f480c2d47bfdba57a5640531b7ab95bf28730c33fd0f65b168e18295b3a9848bc5e954ba6
6
+ metadata.gz: 8b72e001d1217f09608754912114f7d82d0d712fccf1366da8bf299108f408b2fde3721f061975311768732e98693381ce0c0228fec3230ebecb2c7f2ee01313
7
+ data.tar.gz: 2179d51cdaab95f132dde4d2570071b0042bb9c7472e2b1de3243db89b54329c99a4fcd7207c226e398742712b6c868854ce5566997597ffcafeed9798ef41e5
data/.circleci/config.yml CHANGED
@@ -45,6 +45,14 @@ commands:
45
45
  - run: BUNDLE_GEMFILE=<< parameters.gemfile >> << parameters.command >>
46
46
 
47
47
  gemfiles:
48
+ aws-two: &aws-two
49
+ steps:
50
+ - ruby:
51
+ gemfile: gemfiles/aws_2.gemfile
52
+ aws-three: &aws-three
53
+ steps:
54
+ - ruby:
55
+ gemfile: gemfiles/aws_3.gemfile
48
56
  faraday: &faraday
49
57
  steps:
50
58
  - ruby:
@@ -105,6 +113,30 @@ jobs:
105
113
  steps:
106
114
  - ruby:
107
115
  command: bundle exec rake rubocop
116
+ aws-two-ruby-two-three:
117
+ <<: *aws-two
118
+ executor: ruby-two-three
119
+ aws-two-ruby-two-four:
120
+ <<: *aws-two
121
+ executor: ruby-two-four
122
+ aws-two-ruby-two-five:
123
+ <<: *aws-two
124
+ executor: ruby-two-five
125
+ aws-two-ruby-two-six:
126
+ <<: *aws-two
127
+ executor: ruby-two-six
128
+ aws-three-ruby-two-three:
129
+ <<: *aws-three
130
+ executor: ruby-two-three
131
+ aws-three-ruby-two-four:
132
+ <<: *aws-three
133
+ executor: ruby-two-four
134
+ aws-three-ruby-two-five:
135
+ <<: *aws-three
136
+ executor: ruby-two-five
137
+ aws-three-ruby-two-six:
138
+ <<: *aws-three
139
+ executor: ruby-two-six
108
140
  faraday-ruby-two-three:
109
141
  <<: *faraday
110
142
  executor: ruby-two-three
@@ -243,6 +275,38 @@ workflows:
243
275
  beeline:
244
276
  jobs:
245
277
  - lint: *tag_filters
278
+ - aws-two-ruby-two-three:
279
+ <<: *tag_filters
280
+ requires:
281
+ - lint
282
+ - aws-two-ruby-two-four:
283
+ <<: *tag_filters
284
+ requires:
285
+ - lint
286
+ - aws-two-ruby-two-five:
287
+ <<: *tag_filters
288
+ requires:
289
+ - lint
290
+ - aws-two-ruby-two-six:
291
+ <<: *tag_filters
292
+ requires:
293
+ - lint
294
+ - aws-three-ruby-two-three:
295
+ <<: *tag_filters
296
+ requires:
297
+ - lint
298
+ - aws-three-ruby-two-four:
299
+ <<: *tag_filters
300
+ requires:
301
+ - lint
302
+ - aws-three-ruby-two-five:
303
+ <<: *tag_filters
304
+ requires:
305
+ - lint
306
+ - aws-three-ruby-two-six:
307
+ <<: *tag_filters
308
+ requires:
309
+ - lint
246
310
  - faraday-ruby-two-three:
247
311
  <<: *tag_filters
248
312
  requires:
@@ -407,6 +471,14 @@ workflows:
407
471
  ignore: /.*/
408
472
  requires:
409
473
  - lint
474
+ - aws-two-ruby-two-three
475
+ - aws-two-ruby-two-four
476
+ - aws-two-ruby-two-five
477
+ - aws-two-ruby-two-six
478
+ - aws-three-ruby-two-three
479
+ - aws-three-ruby-two-four
480
+ - aws-three-ruby-two-five
481
+ - aws-three-ruby-two-six
410
482
  - faraday-ruby-two-three
411
483
  - faraday-ruby-two-four
412
484
  - faraday-ruby-two-five
data/Appraisals CHANGED
@@ -1,5 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ appraise "aws-2" do
4
+ gem "aws-sdk", "~> 2"
5
+ end
6
+
7
+ appraise "aws-3" do
8
+ gem "aws-sdk", "~> 3"
9
+ end
10
+
3
11
  appraise "faraday" do
4
12
  gem "faraday"
5
13
  end
data/CONTRIBUTORS.md CHANGED
@@ -1,3 +1,4 @@
1
1
  # Contributors
2
2
 
3
- Sergio Mira
3
+ * Sergio Mira
4
+ * Alex Vondrak - [@ajvondrak](https://github.com/ajvondrak)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- honeycomb-beeline (1.1.1)
4
+ honeycomb-beeline (1.2.0)
5
5
  libhoney (~> 1.8)
6
6
 
7
7
  GEM
@@ -27,16 +27,20 @@ GEM
27
27
  domain_name (0.5.20190701)
28
28
  unf (>= 0.0.5, < 1.0.0)
29
29
  ffi (1.11.1)
30
+ ffi-compiler (1.0.1)
31
+ ffi (>= 1.0.0)
32
+ rake
30
33
  hashdiff (0.4.0)
31
- http (4.1.1)
34
+ http (4.2.0)
32
35
  addressable (~> 2.3)
33
36
  http-cookie (~> 1.0)
34
37
  http-form_data (~> 2.0)
35
- http_parser.rb (~> 0.6.0)
38
+ http-parser (~> 1.2.0)
36
39
  http-cookie (1.0.3)
37
40
  domain_name (~> 0.5)
38
41
  http-form_data (2.1.1)
39
- http_parser.rb (0.6.0)
42
+ http-parser (1.2.1)
43
+ ffi-compiler (>= 1.0, < 2.0)
40
44
  iniparse (1.4.4)
41
45
  jaro_winkler (1.5.3)
42
46
  json (2.2.0)
data/README.md CHANGED
@@ -16,6 +16,7 @@ Requires Ruby version 2.3 or later
16
16
  Built in instrumentation for:
17
17
 
18
18
  - Active Support
19
+ - AWS (v2 and v3)
19
20
  - Faraday
20
21
  - Rack
21
22
  - Rails (tested on versions 4.1 and up)
@@ -10,6 +10,7 @@ require "honeycomb/trace"
10
10
  module Honeycomb
11
11
  INTEGRATIONS = %i[
12
12
  active_support
13
+ aws
13
14
  faraday
14
15
  rack
15
16
  rails
@@ -3,7 +3,7 @@
3
3
  module Honeycomb
4
4
  module Beeline
5
5
  NAME = "honeycomb-beeline".freeze
6
- VERSION = "1.1.1".freeze
6
+ VERSION = "1.2.0".freeze
7
7
  USER_AGENT_SUFFIX = "#{NAME}/#{VERSION}".freeze
8
8
  end
9
9
  end
@@ -0,0 +1,396 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-core"
4
+
5
+ module Honeycomb
6
+ module Aws
7
+ # The version of the aws-sdk-core gem.
8
+ #
9
+ # Aws::VERSION was removed in aws-sdk-core v3.2.1 in favor of
10
+ # Aws::CORE_GEM_VERSION. However, it's still present in aws-sdk v2.
11
+ #
12
+ # @see https://github.com/aws/aws-sdk-ruby/blob/d0c5f6e5a3e83eeda2d1c81f5dd80e5ac562a6dc/gems/aws-sdk-core/CHANGELOG.md#321-2017-09-06
13
+ # @see https://github.com/aws/aws-sdk-ruby/blob/4c40f6e67e763a0f392ba5b1449254426b68a600/aws-sdk-core/lib/aws-sdk-core/version.rb#L2
14
+ SDK_VERSION =
15
+ defined?(::Aws::VERSION) ? ::Aws::VERSION : ::Aws::CORE_GEM_VERSION
16
+
17
+ # Instruments AWS clients with Honeycomb events.
18
+ #
19
+ # This plugin is automatically added to any aws-sdk client class your app
20
+ # uses. It uses {SdkHandler} to wrap a Honeycomb span around each
21
+ # invocation of a client object method. Within that span, there is
22
+ # typically at least one actual HTTP API call to Amazon, so each API call
23
+ # is wrapped in a separate span by {ApiHandler}.
24
+ #
25
+ # This plugin adds the following options which you can use to configure
26
+ # your aws-sdk clients:
27
+ #
28
+ # * `:honeycomb` - Boolean indicating whether to enable Honeycomb
29
+ # instrumentation. Defaults to `true`.
30
+ #
31
+ # * `:honeycomb_client` - Allows you to set a custom Honeycomb client
32
+ # object. Defaults to the global {Honeycomb.client}.
33
+ #
34
+ # @example Disable the Honeycomb AWS integration globally.
35
+ # Aws.config.update(honeycomb: false)
36
+ #
37
+ # @example Disable the Honeycomb AWS integration locally.
38
+ # s3 = Aws::S3::Client.new(honeycomb: false)
39
+ #
40
+ # @example Use a different client globally.
41
+ # Aws.config.update(honeycomb_client: custom)
42
+ #
43
+ # @example Use a different client locally.
44
+ # dynamodb = Aws::DynamoDB::Client.new(honeycomb_client: custom)
45
+ #
46
+ # @see https://docs.aws.amazon.com/sdk-for-ruby/v3/api/index.html#Configuration_Options
47
+ # @see SdkHandler
48
+ # @see ApiHandler
49
+ class Plugin < Seahorse::Client::Plugin
50
+ option(
51
+ :honeycomb,
52
+ default: true,
53
+ doc_type: "Boolean",
54
+ docstring: "When `true`, emit Honeycomb events for every SDK/API call.",
55
+ )
56
+
57
+ option(
58
+ :honeycomb_client,
59
+ doc_type: Honeycomb::Client,
60
+ docstring: "The Honeycomb client used for sending SDK/API call events.",
61
+ ) { Honeycomb.client }
62
+
63
+ def add_handlers(handlers, config)
64
+ return unless config.honeycomb && config.honeycomb_client
65
+
66
+ handlers.add(SdkHandler, step: :initialize)
67
+ handlers.add(ApiHandler, step: :sign, priority: 39)
68
+ end
69
+ end
70
+
71
+ # An AWS plugin handler that creates spans around SDK calls.
72
+ #
73
+ # Each aws-sdk client provides a one-to-one mapping of methods to logical
74
+ # API operations. {SdkHandler} is responsible for starting the root level
75
+ # AWS span for the SDK method being called.
76
+ #
77
+ # {Plugin} accomplishes this by adding the handler early in the process,
78
+ # around the initialization step. This doesn't necessarily represent the
79
+ # network latency of the API requests being made to Amazon, since SDK calls
80
+ # might involve several underlying operations: request signing, response
81
+ # parsing, retries, redirects, etc. Thus, {ApiHandler} is responsible for
82
+ # creating child spans around individual HTTP API calls. The span created
83
+ # by {SdkHandler} represents the overall result of the method call you made
84
+ # to the aws-sdk client.
85
+ class SdkHandler < Seahorse::Client::Handler
86
+ def call(context)
87
+ setup(context)
88
+ response = @handler.call(context)
89
+ teardown(context, response.error)
90
+ response
91
+ rescue StandardError => e
92
+ teardown(context, e)
93
+ raise e
94
+ ensure
95
+ finish(context)
96
+ end
97
+
98
+ private
99
+
100
+ def setup(context)
101
+ span = context.config.honeycomb_client.start_span(name: "aws-sdk")
102
+ context[:honeycomb_aws_sdk_span] = span
103
+ context[:honeycomb_aws_sdk_data] = {
104
+ "meta.package" => context[:gem_name] || "aws-sdk",
105
+ "meta.package_version" => context[:gem_version] || SDK_VERSION,
106
+ "aws.region" => context.config.region,
107
+ "aws.service" => context.client.class.identifier,
108
+ "aws.operation" => context.operation_name,
109
+ "aws.params" => context.params,
110
+ }
111
+ span.add context[:honeycomb_aws_sdk_data]
112
+ end
113
+
114
+ def teardown(context, error)
115
+ span = context[:honeycomb_aws_sdk_span]
116
+ span.add_field "aws.request_id", context[:request_id]
117
+ span.add_field "aws.retries", context.retries
118
+ span.add_field "aws.retry_limit", context.config.retry_limit
119
+ span.add_field "aws.error", error.class.name if error
120
+ span.add_field "aws.error_detail", error.message if error
121
+ end
122
+
123
+ def finish(context)
124
+ span = context.metadata.delete(:honeycomb_aws_sdk_span)
125
+ span.send
126
+ end
127
+ end
128
+
129
+ # An AWS plugin handler that creates spans around API calls.
130
+ #
131
+ # Each aws-sdk client provides a one-to-one mapping of methods to API
132
+ # operations. However, this doesn't mean that each method results in only
133
+ # one HTTP request to Amazon's servers. There may be request errors,
134
+ # retries, redirects, etc. So whereas {SdkHandler} wraps the logical
135
+ # operation in a span, {ApiHandler} wraps the individual API requests in
136
+ # separate child spans.
137
+ #
138
+ # {Plugin} accomplishes this by adding {ApiHandler} as close to sending as
139
+ # possible, before the client retries requests, follows redirects, or even
140
+ # parses out response errors. That way, a new span is created for every
141
+ # literal HTTP request. But it also means we have to take care to propagate
142
+ # error information to the span correctly, since the stock AWS error
143
+ # handlers are upstream from this one.
144
+ #
145
+ # @see https://github.com/aws/aws-sdk-ruby/blob/767a96db5cb98424a78249dca3f0be802148372e/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/s3_signer.rb#L36
146
+ # @see https://github.com/aws/aws-sdk-ruby/blob/767a96db5cb98424a78249dca3f0be802148372e/gems/aws-sdk-core/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb#L9-L11
147
+ # @see https://github.com/aws/aws-sdk-ruby/blob/97b28ccf18558fc908fd56f52741cf3329de9869/gems/aws-sdk-core/lib/seahorse/client/plugins/raise_response_errors.rb
148
+ class ApiHandler < Seahorse::Client::Handler
149
+ def call(context)
150
+ context.config.honeycomb_client.start_span(name: "aws-api") do |span|
151
+ instrument(span, context)
152
+ @handler.call(context)
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def instrument(span, context)
159
+ context[:honeycomb_aws_api_span] = span
160
+ handle_request(context)
161
+ handle_response(context)
162
+ end
163
+
164
+ def handle_request(context)
165
+ span = context[:honeycomb_aws_api_span]
166
+ add_aws_api_fields(span, context)
167
+ add_request_fields(span, context)
168
+ end
169
+
170
+ def add_aws_api_fields(span, context)
171
+ span.add context[:honeycomb_aws_sdk_data]
172
+ span.add_field "aws.attempt", context.retries + 1
173
+ add_credentials(span, context) if context.config.credentials
174
+ handle_redirect(span, context) if context[:redirect_region]
175
+ end
176
+
177
+ def add_credentials(span, context)
178
+ credentials = context.config.credentials.credentials
179
+ span.add_field "aws.access_key_id", credentials.access_key_id
180
+ span.add_field "aws.session_token", credentials.session_token
181
+ end
182
+
183
+ def handle_redirect(span, context)
184
+ span.add_field "aws.region", context[:redirect_region]
185
+ end
186
+
187
+ def add_request_fields(span, context)
188
+ request = context.http_request
189
+ span.add_field "request.method", request.http_method
190
+ span.add_field "request.scheme", request.endpoint.scheme
191
+ span.add_field "request.host", request.endpoint.host
192
+ span.add_field "request.path", request.endpoint.path
193
+ span.add_field "request.query", request.endpoint.query
194
+ span.add_field "request.user_agent", request.headers["user-agent"]
195
+ end
196
+
197
+ def handle_response(context)
198
+ on_headers(context)
199
+ on_error(context)
200
+ on_done(context)
201
+ end
202
+
203
+ def on_headers(context)
204
+ context.http_response.on_headers do |status_code, headers|
205
+ span = context[:honeycomb_aws_api_span]
206
+ span.add_field "response.status_code", status_code
207
+ headers.each do |header, value|
208
+ if header.start_with?("x-amz-", "x-amzn-")
209
+ field = "response.#{header.tr('-', '_')}"
210
+ span.add_field(field, value)
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ def on_error(context)
217
+ context.http_response.on_error do |error|
218
+ span = context[:honeycomb_aws_api_span]
219
+ span.add_field "response.error", error.class.name
220
+ span.add_field "response.error_detail", error.message
221
+ end
222
+ end
223
+
224
+ def on_done(context)
225
+ context.http_response.on_done(300..599) do
226
+ process_api_error(context)
227
+ process_s3_region(context)
228
+ end
229
+ end
230
+
231
+ def process_api_error(context)
232
+ span = context[:honeycomb_aws_api_span]
233
+ error = parse_api_error_from(context)
234
+ add_api_error_fields(span, error) if error
235
+ end
236
+
237
+ def add_api_error_fields(span, error)
238
+ span.add_field "response.error", error.code
239
+ span.add_field "response.error_detail", error.message
240
+ end
241
+
242
+ # Runs a limited subset of response parsing for AWS-specific errors.
243
+ #
244
+ # Because XML/JSON error handlers are inserted at priority 50 of the
245
+ # :sign step, they're upstream from {ApiHandler} (at priority 39), so we
246
+ # won't have access to the error saved in Seahorse::Client::Response yet.
247
+ # We only have the error in the Seahorse::Client::Http::Response object.
248
+ # But Seahorse::Client::NetHttp::Handler only triggers an HTTP response
249
+ # error for rescued exceptions (e.g., timeouts). We might still get back
250
+ # successful HTTP 3xx, 4xx, or 5xx responses that should be interpreted
251
+ # as aws-api errors.
252
+ #
253
+ # So we have to duplicate the logic of either Aws::Xml::ErrorHandler or
254
+ # Aws::Json::ErrorHandler depending on which one is being used by the
255
+ # current client. We can determine this by their "protocol" metadata.
256
+ #
257
+ # Note that there are still a few straggling errors that might occur from
258
+ # HTTP 2xx responses. Since those aren't really API call failures, we
259
+ # won't worry about parsing them out for the aws-api span. Once the
260
+ # upstream handlers process those errors, they'll be propagated to the
261
+ # aws-sdk span anyway (since {SdkHandler} will actually have access to
262
+ # the Seahorse::Client::Response#error).
263
+ #
264
+ # @see https://github.com/aws/aws-sdk-ruby/blob/d0c5f6e5a3e83eeda2d1c81f5dd80e5ac562a6dc/gems/aws-sdk-core/lib/aws-sdk-core/client_stubs.rb#L298-L307
265
+ # @see https://github.com/aws/aws-sdk-ruby/tree/b0ade445ce18b24c53a4548074b214e732b8b627/gems/aws-sdk-core/lib/aws-sdk-core/plugins/protocols
266
+ # @see https://github.com/aws/aws-sdk-ruby/blob/354d36792e47f2e81b4889f322928e848e062818/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/http_200_errors.rb
267
+ # @see https://github.com/aws/aws-sdk-ruby/blob/354d36792e47f2e81b4889f322928e848e062818/gems/aws-sdk-dynamodb/lib/aws-sdk-dynamodb/plugins/crc32_validation.rb
268
+ def parse_api_error_from(context)
269
+ case context.config.api.metadata["protocol"]
270
+ when "query", "rest-xml", "ec2"
271
+ XmlError.new(context)
272
+ when "json", "rest-json"
273
+ JsonError.new(context)
274
+ end
275
+ end
276
+
277
+ # @private
278
+ # @see https://github.com/aws/aws-sdk-ruby/blob/d0c5f6e5a3e83eeda2d1c81f5dd80e5ac562a6dc/gems/aws-sdk-core/lib/aws-sdk-core/xml/error_handler.rb
279
+ class XmlError < ::Aws::Xml::ErrorHandler
280
+ attr_reader :code, :message
281
+
282
+ def initialize(context)
283
+ body = context.http_response.body_contents
284
+ @code = error_code(body, context)
285
+ @message = error_message(body)
286
+ end
287
+ end
288
+
289
+ # @private
290
+ # @see https://github.com/aws/aws-sdk-ruby/blob/d0c5f6e5a3e83eeda2d1c81f5dd80e5ac562a6dc/gems/aws-sdk-core/lib/aws-sdk-core/json/error_handler.rb
291
+ class JsonError < ::Aws::Json::ErrorHandler
292
+ attr_reader :code, :message
293
+
294
+ def initialize(context)
295
+ body = context.http_response.body_contents
296
+ json = ::Aws::Json.load(body) || {}
297
+ @code = error_code(json, context)
298
+ @message = error_message(code, json)
299
+ rescue ::Aws::Json::ParseError
300
+ @code = http_status_error_code(context)
301
+ @message = ""
302
+ end
303
+ end
304
+
305
+ # Propagates S3 region redirect information to the next aws-api span.
306
+ #
307
+ # When the AWS S3 client is configured with the wrong region, Amazon
308
+ # responds to API requests with an HTTP 400 indicating the correct region
309
+ # for the bucket.
310
+ #
311
+ # This error is normally caught upstream by stock plugins that trigger a
312
+ # new API request with the right region, which will create another
313
+ # aws-api span after this one. However, since the aws.region field set by
314
+ # {#add_aws_api_fields} comes from the aws-sdk configuration, its value
315
+ # would continue being wrong in the next aws-api span. Instead, we want
316
+ # this span to have the wrong region (that triggered the error) and the
317
+ # next span to have the right region (which won't come from the config).
318
+ #
319
+ # To update aws.region to the right value, {#handle_redirect} looks for a
320
+ # value stashed in the Seahorse::Client::Context#metadata. This is set by
321
+ # aws-sdk v3 (via the aws-sdk-s3 gem) but not by aws-sdk v2. So, we have
322
+ # to duplicate some of the upstream v3 logic in order to propagate the
323
+ # redirected region in the v2 case. We only do this in the v2 case in the
324
+ # hopes that eventually we don't have to maintain the duplicated logic.
325
+ #
326
+ # @see https://github.com/aws/aws-sdk-ruby/blob/379d338406873b0f4b53f118c83fe40761e297ab/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/s3_signer.rb#L151
327
+ def process_s3_region(context)
328
+ return unless SDK_VERSION.start_with?("2.")
329
+
330
+ redirect = S3Redirect.new(context)
331
+ context[:redirect_region] = redirect.region if redirect.happening?
332
+ end
333
+
334
+ # @private
335
+ # @see https://github.com/aws/aws-sdk-ruby/blob/379d338406873b0f4b53f118c83fe40761e297ab/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/s3_signer.rb#L102-L182
336
+ # @see https://github.com/aws/aws-sdk-ruby/blob/4c40f6e67e763a0f392ba5b1449254426b68a600/aws-sdk-core/lib/aws-sdk-core/plugins/s3_request_signer.rb#L81-L153
337
+ class S3Redirect
338
+ REGION_TAG = %r{<Region>(.+?)</Region>}.freeze
339
+
340
+ def initialize(context)
341
+ @context = context
342
+ end
343
+
344
+ def original_host
345
+ @context.http_request.endpoint.host
346
+ end
347
+
348
+ def status
349
+ @context.http_response.status_code
350
+ end
351
+
352
+ def happening?
353
+ status == 400 && region && !original_host.include?("fips")
354
+ end
355
+
356
+ def region
357
+ @region ||= region_from_headers || region_from_body
358
+ end
359
+
360
+ def region_from_headers
361
+ @context.http_response.headers["x-amz-bucket-region"]
362
+ end
363
+
364
+ def region_from_body
365
+ body = @context.http_response.body_contents
366
+ body.match(REGION_TAG) { |tag| tag[1] }
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
372
+
373
+ # Add the plugin to all aws-sdk client classes.
374
+ #
375
+ # Since client classes are dynamically created at load time by
376
+ # Seahorse::Client::Base.define, it's necessary to call .add_plugin on each
377
+ # class individually. For example, say we required aws-sdk-s3 before loading
378
+ # honeycomb-beeline. Then Aws::S3::Client would have already been defined
379
+ # without knowing about our plugin. So adding Honeycomb::Aws::Plugin to just
380
+ # Seahorse::Client::Base is insufficent. We have to call
381
+ # Aws::S3::Client.add_plugin as well.
382
+ #
383
+ # This loop will still add the plugin to Seahorse::Client::Base, which covers
384
+ # us if/when any future aws-sdk client classes get defined.
385
+ #
386
+ # This loop will *not* patch any instances of client objects that were created
387
+ # prior to loading honeycomb-beeline. While we could loop through
388
+ # ObjectSpace.each_object(Seahorse::Client::Base), it's much more awkward to
389
+ # reinitialize an existing instance. E.g., at the time the client instance was
390
+ # created, its configuration wouldn't have responded to the options defined by
391
+ # Honeycomb::Aws::Plugin, so we can't retroactively configure the plugin. In
392
+ # practice, this probably isn't a big deal: you'll likely load aws-sdk +
393
+ # honeycomb-beeline via bundler before ever instantiating an AWS client object.
394
+ ObjectSpace.each_object(Seahorse::Client::Base.singleton_class) do |client|
395
+ client.add_plugin(Honeycomb::Aws::Plugin)
396
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeycomb-beeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Holman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-10 00:00:00.000000000 Z
11
+ date: 2019-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: libhoney
@@ -227,6 +227,7 @@ files:
227
227
  - lib/honeycomb/context.rb
228
228
  - lib/honeycomb/deterministic_sampler.rb
229
229
  - lib/honeycomb/integrations/active_support.rb
230
+ - lib/honeycomb/integrations/aws.rb
230
231
  - lib/honeycomb/integrations/faraday.rb
231
232
  - lib/honeycomb/integrations/rack.rb
232
233
  - lib/honeycomb/integrations/rails.rb