aws-xray-sdk 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/aws-xray-sdk.rb +10 -0
- data/lib/aws-xray-sdk/configuration.rb +158 -0
- data/lib/aws-xray-sdk/context/context.rb +26 -0
- data/lib/aws-xray-sdk/context/default_context.rb +81 -0
- data/lib/aws-xray-sdk/emitter/default_emitter.rb +53 -0
- data/lib/aws-xray-sdk/emitter/emitter.rb +24 -0
- data/lib/aws-xray-sdk/exceptions.rb +31 -0
- data/lib/aws-xray-sdk/facets/aws_sdk.rb +127 -0
- data/lib/aws-xray-sdk/facets/helper.rb +61 -0
- data/lib/aws-xray-sdk/facets/net_http.rb +61 -0
- data/lib/aws-xray-sdk/facets/rack.rb +87 -0
- data/lib/aws-xray-sdk/facets/rails/active_record.rb +66 -0
- data/lib/aws-xray-sdk/facets/rails/ex_middleware.rb +24 -0
- data/lib/aws-xray-sdk/facets/rails/railtie.rb +23 -0
- data/lib/aws-xray-sdk/facets/resources/aws_params_whitelist.rb +340 -0
- data/lib/aws-xray-sdk/facets/resources/aws_services_whitelist.rb +147 -0
- data/lib/aws-xray-sdk/logger.rb +19 -0
- data/lib/aws-xray-sdk/model/annotations.rb +97 -0
- data/lib/aws-xray-sdk/model/cause.rb +70 -0
- data/lib/aws-xray-sdk/model/dummy_entities.rb +72 -0
- data/lib/aws-xray-sdk/model/entity.rb +187 -0
- data/lib/aws-xray-sdk/model/metadata.rb +77 -0
- data/lib/aws-xray-sdk/model/segment.rb +63 -0
- data/lib/aws-xray-sdk/model/subsegment.rb +67 -0
- data/lib/aws-xray-sdk/model/trace_header.rb +54 -0
- data/lib/aws-xray-sdk/patcher.rb +21 -0
- data/lib/aws-xray-sdk/plugins/ec2.rb +39 -0
- data/lib/aws-xray-sdk/plugins/ecs.rb +23 -0
- data/lib/aws-xray-sdk/plugins/elastic_beanstalk.rb +25 -0
- data/lib/aws-xray-sdk/recorder.rb +209 -0
- data/lib/aws-xray-sdk/sampling/default_sampler.rb +105 -0
- data/lib/aws-xray-sdk/sampling/reservoir.rb +35 -0
- data/lib/aws-xray-sdk/sampling/sampler.rb +27 -0
- data/lib/aws-xray-sdk/sampling/sampling_rule.rb +57 -0
- data/lib/aws-xray-sdk/search_pattern.rb +82 -0
- data/lib/aws-xray-sdk/segment_naming/dynamic_naming.rb +26 -0
- data/lib/aws-xray-sdk/segment_naming/segment_naming.rb +10 -0
- data/lib/aws-xray-sdk/streaming/default_streamer.rb +53 -0
- data/lib/aws-xray-sdk/streaming/streamer.rb +17 -0
- data/lib/aws-xray-sdk/version.rb +3 -0
- metadata +224 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78007efa0d29f0f16fa12ee0437cb6214a64c7d43d6cd1bde7ca9286d44d110b
|
4
|
+
data.tar.gz: e9fe587611d3f346b98e632ab88772769246d351b06ce46cc42f015fb15899e2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bb2ed43b514b1b50278c370c32b159f8f58bed0cd3e105b91f9ff0afb74a6ba66f184f515a294c2520cca7ad9b102506534f58fd4f3a778daeec02688900b437
|
7
|
+
data.tar.gz: 5ce0c0474f40d316dfa1ec0eddc13d156886c93b211bebd7963ae795c7b1eeca72fbc696d3a0bb948d3ad8ad106eab60d1b0774602217a794c2f92f42bac2938
|
data/lib/aws-xray-sdk.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'aws-xray-sdk/exceptions'
|
2
|
+
require 'aws-xray-sdk/patcher'
|
3
|
+
require 'aws-xray-sdk/emitter/default_emitter'
|
4
|
+
require 'aws-xray-sdk/context/default_context'
|
5
|
+
require 'aws-xray-sdk/sampling/default_sampler'
|
6
|
+
require 'aws-xray-sdk/streaming/default_streamer'
|
7
|
+
require 'aws-xray-sdk/segment_naming/dynamic_naming'
|
8
|
+
require 'aws-xray-sdk/plugins/ec2'
|
9
|
+
require 'aws-xray-sdk/plugins/ecs'
|
10
|
+
require 'aws-xray-sdk/plugins/elastic_beanstalk'
|
11
|
+
require 'aws-xray-sdk/logger'
|
12
|
+
|
13
|
+
module XRay
|
14
|
+
# This class stores all configurations for X-Ray recorder
|
15
|
+
# and should be initialized only once.
|
16
|
+
class Configuration
|
17
|
+
include Patcher
|
18
|
+
|
19
|
+
SEGMENT_NAME_KEY = 'AWS_XRAY_TRACING_NAME'.freeze
|
20
|
+
CONFIG_KEY = %I[logger name sampling plugins daemon_address segment_naming
|
21
|
+
naming_pattern emitter streamer context context_missing
|
22
|
+
sampling_rules stream_threshold patch].freeze
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@name = ENV[SEGMENT_NAME_KEY]
|
26
|
+
@sampling = true
|
27
|
+
@emitter = DefaultEmitter.new
|
28
|
+
@context = DefaultContext.new
|
29
|
+
@sampler = DefaultSampler.new
|
30
|
+
@streamer = DefaultStreamer.new
|
31
|
+
@segment_naming = DynamicNaming.new fallback: @name
|
32
|
+
@plugins = []
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [String] v The default segment name.
|
36
|
+
# Environment vairable takes higher precedence.
|
37
|
+
def name=(v)
|
38
|
+
@name = ENV[SEGMENT_NAME_KEY] || v
|
39
|
+
end
|
40
|
+
|
41
|
+
# proxy method to the emitter's daemon_address config.
|
42
|
+
def daemon_address=(v)
|
43
|
+
emitter.daemon_address = v
|
44
|
+
end
|
45
|
+
|
46
|
+
# proxy method to the context's context_missing config.
|
47
|
+
def context_missing=(v)
|
48
|
+
context.context_missing = v
|
49
|
+
end
|
50
|
+
|
51
|
+
# proxy method to the sampler's sampling rule config.
|
52
|
+
def sampling_rules=(v)
|
53
|
+
sampler.sampling_rules = v
|
54
|
+
end
|
55
|
+
|
56
|
+
# proxy method to the streamer's stream threshold config.
|
57
|
+
def stream_threshold=(v)
|
58
|
+
streamer.stream_threshold = v
|
59
|
+
end
|
60
|
+
|
61
|
+
# proxy method to the dynamic naming's pattern config.
|
62
|
+
def naming_pattern=(v)
|
63
|
+
segment_naming.pattern = v
|
64
|
+
end
|
65
|
+
|
66
|
+
# makes a sampling decision based on internal configure, e.g.
|
67
|
+
# if sampling enabled and the default sampling rule.
|
68
|
+
def sample?
|
69
|
+
return true unless sampling
|
70
|
+
sampler.sample?
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [Hash] user_config The user configuration overrides.
|
74
|
+
def configure(user_config)
|
75
|
+
raise InvalidConfigurationError.new('User config must be a Hash.') unless user_config.is_a?(Hash)
|
76
|
+
return if user_config.empty?
|
77
|
+
|
78
|
+
user_config.each_key do |key|
|
79
|
+
case key
|
80
|
+
when :logger
|
81
|
+
XRay::Logging.logger = user_config[key]
|
82
|
+
when :name
|
83
|
+
self.name = user_config[key]
|
84
|
+
when :context
|
85
|
+
self.context = user_config[key]
|
86
|
+
when :context_missing
|
87
|
+
self.context_missing = user_config[key]
|
88
|
+
when :sampler
|
89
|
+
self.sampler = user_config[key]
|
90
|
+
when :sampling_rules
|
91
|
+
self.sampling_rules = user_config[key]
|
92
|
+
when :sampling
|
93
|
+
self.sampling = user_config[key]
|
94
|
+
when :emitter
|
95
|
+
self.emitter = user_config[key]
|
96
|
+
when :daemon_address
|
97
|
+
self.daemon_address = user_config[key]
|
98
|
+
when :segment_naming
|
99
|
+
self.segment_naming = user_config[key]
|
100
|
+
when :naming_pattern
|
101
|
+
self.naming_pattern = user_config[key]
|
102
|
+
when :streamer
|
103
|
+
self.streamer = user_config[key]
|
104
|
+
when :stream_threshold
|
105
|
+
self.stream_threshold = user_config[key]
|
106
|
+
when :plugins
|
107
|
+
self.plugins = load_plugins(user_config[key])
|
108
|
+
when :patch
|
109
|
+
patch(user_config[key])
|
110
|
+
else
|
111
|
+
raise InvalidConfigurationError.new(%(Invalid config key #{key}.))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
attr_accessor :emitter
|
117
|
+
|
118
|
+
attr_accessor :context
|
119
|
+
|
120
|
+
attr_accessor :sampler
|
121
|
+
|
122
|
+
attr_accessor :streamer
|
123
|
+
|
124
|
+
attr_accessor :segment_naming
|
125
|
+
|
126
|
+
attr_accessor :plugins
|
127
|
+
|
128
|
+
attr_accessor :sampling
|
129
|
+
|
130
|
+
# @return [String] The default segment name.
|
131
|
+
attr_reader :name
|
132
|
+
|
133
|
+
# The global logger used across the X-Ray SDK.
|
134
|
+
# @return [Logger]
|
135
|
+
attr_reader :logger
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def load_plugins(symbols)
|
140
|
+
plugins = []
|
141
|
+
symbols.each do |symbol|
|
142
|
+
case symbol
|
143
|
+
when :ec2
|
144
|
+
plugins << XRay::Plugins::EC2
|
145
|
+
when :ecs
|
146
|
+
plugins << XRay::Plugins::ECS
|
147
|
+
when :elastic_beanstalk
|
148
|
+
plugins << XRay::Plugins::ElasticBeanstalk
|
149
|
+
else
|
150
|
+
raise InvalidConfigurationError.new(%(Unsupported plugin #{symbol}.))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# eager loads aws metadata to eliminate impact on first incoming request
|
154
|
+
plugins.each(&:aws)
|
155
|
+
plugins
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module XRay
|
2
|
+
# The interface of context management for the X-Ray recorder.
|
3
|
+
module Context
|
4
|
+
# @param [Entity] entity The entity to be stored in the context.
|
5
|
+
def store_entity(entity:)
|
6
|
+
raise 'Not implemented'
|
7
|
+
end
|
8
|
+
|
9
|
+
def current_entity
|
10
|
+
raise 'Not implemented'
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear!
|
14
|
+
raise 'Not implemented'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Put current active entity to the new context storage.
|
18
|
+
def inject_context(entity, target_ctx: nil)
|
19
|
+
raise 'Not implemented'
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_context_missing
|
23
|
+
raise 'Not implemented'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'aws-xray-sdk/logger'
|
2
|
+
require 'aws-xray-sdk/context/context'
|
3
|
+
require 'aws-xray-sdk/exceptions'
|
4
|
+
|
5
|
+
module XRay
|
6
|
+
# The default context storage management used by
|
7
|
+
# the X-Ray recorder. It uses thread local to store
|
8
|
+
# segments and subsegments.
|
9
|
+
class DefaultContext
|
10
|
+
include Context
|
11
|
+
include Logging
|
12
|
+
|
13
|
+
LOCAL_KEY = '_aws_xray_entity'.freeze
|
14
|
+
CONTEXT_MISSING_KEY = 'AWS_XRAY_CONTEXT_MISSING'.freeze
|
15
|
+
SUPPORTED_STRATEGY = %w[RUNTIME_ERROR LOG_ERROR].freeze
|
16
|
+
DEFAULT_STRATEGY = SUPPORTED_STRATEGY[0]
|
17
|
+
|
18
|
+
attr_reader :context_missing
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
strategy = ENV[CONTEXT_MISSING_KEY] || DEFAULT_STRATEGY
|
22
|
+
@context_missing = sanitize_strategy(strategy)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param [Entity] entity The entity to be stored in the context.
|
26
|
+
def store_entity(entity:)
|
27
|
+
Thread.current[LOCAL_KEY] = entity
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Entity] The current active entity(could be segment or subsegment).
|
31
|
+
def current_entity
|
32
|
+
if entity = Thread.current[LOCAL_KEY]
|
33
|
+
entity
|
34
|
+
else
|
35
|
+
handle_context_missing
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Clear the current thread local storage on X-Ray related entities.
|
40
|
+
def clear!
|
41
|
+
Thread.current[LOCAL_KEY] = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Entity] entity The entity to inject.
|
45
|
+
# @param [Thread] target_ctx Put the provided entity to the new thread.
|
46
|
+
def inject_context(entity, target_ctx: nil)
|
47
|
+
target_ctx ||= Thread.current
|
48
|
+
target_ctx[LOCAL_KEY] = entity if entity
|
49
|
+
end
|
50
|
+
|
51
|
+
# When the current entity needs to be accessed but there is none,
|
52
|
+
# it handles the missing context based on the configuration.
|
53
|
+
# On `RUNTIME_ERROR` it raises `ContextMissingError`.
|
54
|
+
# On 'LOG_ERROR' it logs an error message and return `nil`.
|
55
|
+
def handle_context_missing
|
56
|
+
case context_missing
|
57
|
+
when 'RUNTIME_ERROR'
|
58
|
+
raise ContextMissingError
|
59
|
+
when 'LOG_ERROR'
|
60
|
+
logger.error %(can not find the current context.)
|
61
|
+
end
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def context_missing=(v)
|
66
|
+
strategy = ENV[CONTEXT_MISSING_KEY] || v
|
67
|
+
@context_missing = sanitize_strategy(strategy)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def sanitize_strategy(v)
|
73
|
+
if SUPPORTED_STRATEGY.include?(v)
|
74
|
+
v
|
75
|
+
else
|
76
|
+
logger.warn %(context missing #{v} is not supported, switch to default #{DEFAULT_STRATEGY}.)
|
77
|
+
DEFAULT_STRATEGY
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'aws-xray-sdk/logger'
|
3
|
+
require 'aws-xray-sdk/emitter/emitter'
|
4
|
+
require 'aws-xray-sdk/exceptions'
|
5
|
+
|
6
|
+
module XRay
|
7
|
+
# The default emitter the X-Ray recorder uses to send segments/subsegments
|
8
|
+
# to the X-Ray daemon over UDP using a non-blocking socket.
|
9
|
+
class DefaultEmitter
|
10
|
+
include Emitter
|
11
|
+
include Logging
|
12
|
+
|
13
|
+
attr_reader :address
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@socket = UDPSocket.new
|
17
|
+
@address = ENV[DAEMON_ADDRESS_KEY] || '127.0.0.1:2000'
|
18
|
+
configure_socket(@address)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Serializes a segment/subsegment and sends it to the X-Ray daemon
|
22
|
+
# over UDP. It is no-op for non-sampled entity.
|
23
|
+
# @param [Entity] entity The entity to send
|
24
|
+
def send_entity(entity:)
|
25
|
+
return nil unless entity.sampled
|
26
|
+
begin
|
27
|
+
payload = %(#{@@protocol_header}#{@@protocol_delimiter}#{entity.to_json})
|
28
|
+
logger.debug %(sending payload #{payload} to daemon at #{address}.)
|
29
|
+
@socket.send payload, 0
|
30
|
+
rescue StandardError => e
|
31
|
+
logger.warn %(failed to send payload due to #{e.message})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def daemon_address=(v)
|
36
|
+
v = ENV[DAEMON_ADDRESS_KEY] || v
|
37
|
+
@address = v
|
38
|
+
configure_socket(v)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def configure_socket(v)
|
44
|
+
begin
|
45
|
+
addr = v.split(':')
|
46
|
+
host, ip = addr[0], addr[1].to_i
|
47
|
+
@socket.connect(host, ip)
|
48
|
+
rescue StandardError
|
49
|
+
raise InvalidDaemonAddressError, %(Invalid X-Ray daemon address specified: #{v}.)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module XRay
|
4
|
+
# The emitter interface the X-Ray recorder uses to send segments/subsegments
|
5
|
+
# to the X-Ray daemon over UDP.
|
6
|
+
module Emitter
|
7
|
+
DAEMON_ADDRESS_KEY = 'AWS_XRAY_DAEMON_ADDRESS'.freeze
|
8
|
+
|
9
|
+
@@protocol_header = {
|
10
|
+
format: 'json',
|
11
|
+
version: 1
|
12
|
+
}.to_json
|
13
|
+
@@protocol_delimiter = "\n"
|
14
|
+
|
15
|
+
# @param [Entity] entity Entity to send.
|
16
|
+
def send_entity(entity:)
|
17
|
+
raise 'Not implemented'
|
18
|
+
end
|
19
|
+
|
20
|
+
def daemon_address=(v)
|
21
|
+
raise 'Not implemented'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module XRay
|
2
|
+
# All custom exception thrown by the SDK should subclass AwsXRayError.
|
3
|
+
class AwsXRaySdkError < ::StandardError; end
|
4
|
+
|
5
|
+
class EntityClosedError < AwsXRaySdkError
|
6
|
+
def initialize
|
7
|
+
super('Segment or subsegment already ended.')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ContextMissingError < AwsXRaySdkError
|
12
|
+
def initialize
|
13
|
+
super('Can not find any active segment or subsegment.')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SegmentNameMissingError < AwsXRaySdkError
|
18
|
+
end
|
19
|
+
|
20
|
+
class InvalidDaemonAddressError < AwsXRaySdkError
|
21
|
+
end
|
22
|
+
|
23
|
+
class InvalidSamplingConfigError < AwsXRaySdkError
|
24
|
+
end
|
25
|
+
|
26
|
+
class InvalidConfigurationError < AwsXRaySdkError
|
27
|
+
end
|
28
|
+
|
29
|
+
class UnsupportedPatchingTargetError < AwsXRaySdkError
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
require 'aws-xray-sdk/facets/helper'
|
3
|
+
require 'aws-xray-sdk/facets/resources/aws_params_whitelist'
|
4
|
+
require 'aws-xray-sdk/facets/resources/aws_services_whitelist'
|
5
|
+
|
6
|
+
module XRay
|
7
|
+
class AwsSDKPlugin < Seahorse::Client::Plugin
|
8
|
+
option :xray_recorder, default: XRay.recorder
|
9
|
+
|
10
|
+
def add_handlers(handlers, config)
|
11
|
+
# run before Seahorse::Client::Plugin::ParamValidator (priority 50)
|
12
|
+
handlers.add Handler, step: :validate, priority: 49
|
13
|
+
end
|
14
|
+
|
15
|
+
# Handler to capture AWS API calls as subsegments
|
16
|
+
class Handler < Seahorse::Client::Handler
|
17
|
+
include XRay::Facets::Helper
|
18
|
+
|
19
|
+
def call(context)
|
20
|
+
recorder = Aws.config[:xray_recorder]
|
21
|
+
operation = context.operation_name
|
22
|
+
service_name = context.client.class.api.metadata['serviceAbbreviation'] ||
|
23
|
+
context.client.class.to_s.split('::')[1]
|
24
|
+
recorder.capture service_name, namespace: 'aws' do |subsegment|
|
25
|
+
# inject header string before calling downstream AWS services
|
26
|
+
context.http_request.headers[TRACE_HEADER] = prep_header_str entity: subsegment
|
27
|
+
response = @handler.call(context)
|
28
|
+
http_response = context.http_response
|
29
|
+
resp_meta = {
|
30
|
+
status: http_response.status_code,
|
31
|
+
content_length: http_response.headers['content-length'].to_i
|
32
|
+
}
|
33
|
+
aws = {
|
34
|
+
# XRay back-end right now has strict operation name matching
|
35
|
+
operation: sanitize_op_name(operation),
|
36
|
+
region: context.client.config.region,
|
37
|
+
retries: context.retries,
|
38
|
+
request_id: http_response.headers['x-amzn-requestid']
|
39
|
+
}
|
40
|
+
# S3 returns special request id in response headers
|
41
|
+
if service_name == 'S3'
|
42
|
+
aws[:id_2] = http_response.headers['x-amz-id-2']
|
43
|
+
end
|
44
|
+
|
45
|
+
operation_h = AwsParams.whitelist[:services]
|
46
|
+
.fetch(service_name.to_sym, {})
|
47
|
+
.fetch(:operations, {})[operation]
|
48
|
+
unless operation_h.nil?
|
49
|
+
params_capture req_params: context.params, resp_params: response.to_h,
|
50
|
+
capture: operation_h, meta: aws
|
51
|
+
end
|
52
|
+
subsegment.aws = aws
|
53
|
+
if err = response.error
|
54
|
+
subsegment.add_exception exception: err, remote: true
|
55
|
+
end
|
56
|
+
subsegment.merge_http_response response: resp_meta
|
57
|
+
response
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def inject_headers(request:, entity:)
|
64
|
+
request.headers[TRACE_HEADER] = prep_header_str entity: entity
|
65
|
+
end
|
66
|
+
|
67
|
+
def sanitize_op_name(opname)
|
68
|
+
opname.to_s.split('_').collect(&:capitalize).join if opname
|
69
|
+
end
|
70
|
+
|
71
|
+
def params_capture(req_params:, resp_params:, capture:, meta:)
|
72
|
+
if norm = capture[:request_parameters]
|
73
|
+
capture_normal params: req_params, capture: norm, meta: meta
|
74
|
+
end
|
75
|
+
|
76
|
+
if norm = capture[:response_parameters]
|
77
|
+
capture_normal params: resp_params, capture: norm, meta: meta
|
78
|
+
end
|
79
|
+
|
80
|
+
if spec = capture[:request_descriptors]
|
81
|
+
capture_special params: req_params, capture: spec, meta: meta
|
82
|
+
end
|
83
|
+
|
84
|
+
if spec = capture[:response_descriptors]
|
85
|
+
capture_special params: resp_params, capture: spec, meta: meta
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def capture_normal(params:, capture:, meta:)
|
90
|
+
params.each_key do |key|
|
91
|
+
meta[key] = params[key] if capture.include?(key)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def capture_special(params:, capture:, meta:)
|
96
|
+
params.each_key do |key|
|
97
|
+
process_descriptor(target: params[key], descriptor: capture[key], meta: meta) if capture.include?(key)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def process_descriptor(target:, descriptor:, meta:)
|
102
|
+
# "get_count" = true
|
103
|
+
v = target.length if descriptor[:get_count]
|
104
|
+
# "get_keys" = true
|
105
|
+
v = target.keys if descriptor[:get_keys]
|
106
|
+
meta[descriptor[:rename_to]] = v
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Add X-Ray plugin to AWS SDK clients
|
112
|
+
module AwsSDKPatcher
|
113
|
+
def self.patch(services: nil, recorder: XRay.recorder)
|
114
|
+
force = services.nil?
|
115
|
+
services ||= AwsServices.whitelist
|
116
|
+
services.each do |s|
|
117
|
+
begin
|
118
|
+
Aws.const_get(%(#{s}::Client)).add_plugin XRay::AwsSDKPlugin
|
119
|
+
Aws.config.update xray_recorder: recorder
|
120
|
+
rescue NameError
|
121
|
+
# swallow the error if no explicit user config
|
122
|
+
raise unless force
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|