aws-xray 0.2.0 → 0.3.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 +4 -4
- data/README.md +57 -8
- data/TODO.md +25 -0
- data/example/Gemfile +1 -0
- data/example/REVISION +1 -0
- data/example/campain_app_config.ru +12 -1
- data/example/fron_app_config.ru +1 -0
- data/example/recipe_app_config.ru +1 -0
- data/example/user_app_config.ru +1 -0
- data/lib/aws/xray/annotation_validator.rb +16 -0
- data/lib/aws/xray/cause.rb +46 -0
- data/lib/aws/xray/client.rb +3 -3
- data/lib/aws/xray/configuration.rb +57 -0
- data/lib/aws/xray/context.rb +16 -7
- data/lib/aws/xray/error.rb +60 -0
- data/lib/aws/xray/faraday.rb +17 -3
- data/lib/aws/xray/rack.rb +19 -6
- data/lib/aws/xray/rails.rb +11 -0
- data/lib/aws/xray/request.rb +28 -0
- data/lib/aws/xray/response.rb +6 -0
- data/lib/aws/xray/segment.rb +50 -6
- data/lib/aws/xray/sub_segment.rb +13 -0
- data/lib/aws/xray/trace_header.rb +1 -2
- data/lib/aws/xray/version.rb +1 -1
- data/lib/aws/xray/version_detector.rb +13 -0
- data/lib/aws/xray.rb +6 -0
- metadata +11 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7205283919522f3fa51c16bc8e5f11136ba04a9c
|
4
|
+
data.tar.gz: 0fa4f411671929e4c436939d190afa7fd48e181e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c4aea978c59e664b39d10ca7df5c57c8537069fff4df2196b7e3213fa71c990a66e05cd6e0c816a95311d03e9ace2614ecddcad036e5b04c892f78ca51b1e1e
|
7
|
+
data.tar.gz: 6519acd350a5c0a6ceddad31bdd54db472466cf35bc4d5e044404e4290475607296e9b820c64e40d1099307b715fb927ccf53c5a029b249f69531ee2cacf9a4d
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# aws-xray
|
2
2
|
[](https://travis-ci.org/taiki45/aws-xray)
|
3
3
|
[](https://badge.fury.io/rb/aws-xray)
|
4
4
|
|
@@ -7,18 +7,13 @@ It enables you to capture in-coming HTTP requests and out-going HTTP requests an
|
|
7
7
|
|
8
8
|
AWS X-Ray is a ditributed tracing system. See more detail about AWS X-Ray at [official document](http://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html).
|
9
9
|
|
10
|
-
##
|
11
|
-
Implemented:
|
12
|
-
|
10
|
+
## Features
|
13
11
|
- Rack middleware.
|
14
12
|
- Faraday middleware.
|
15
13
|
- Propagatin support limited in single thread environment.
|
16
|
-
|
17
|
-
Not yet:
|
18
|
-
|
19
14
|
- Tracing HTTP request/response.
|
20
|
-
- Multi thread support.
|
21
15
|
- Tracing errors.
|
16
|
+
- Annotation and metadata support.
|
22
17
|
|
23
18
|
## Installation
|
24
19
|
|
@@ -33,10 +28,32 @@ And then execute:
|
|
33
28
|
$ bundle
|
34
29
|
|
35
30
|
## Usage
|
31
|
+
### Rails app
|
32
|
+
Insert Rack middleware by yourself:
|
33
|
+
|
34
|
+
```
|
35
|
+
# config/initializers/aws_xray.rb
|
36
|
+
Aws::Xray.config.name = 'my-app'
|
37
|
+
Rails.application.config.middleware.use Aws::Xray::Rack
|
38
|
+
```
|
39
|
+
|
40
|
+
Or just require `aws/xray/rails`:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Gemfile
|
44
|
+
gem 'aws-xray', require: 'aws/xray/rails'
|
45
|
+
|
46
|
+
# config/initializers/aws_xray.rb
|
47
|
+
Aws::Xray.config.name = 'my-app'
|
48
|
+
```
|
49
|
+
|
50
|
+
To trace out-going HTTP requests, see below.
|
51
|
+
|
36
52
|
### Rack app
|
37
53
|
```ruby
|
38
54
|
# config.ru
|
39
55
|
require 'aws-xray'
|
56
|
+
Aws::Xray.config.name = 'my-app'
|
40
57
|
use Aws::Xray::Rack
|
41
58
|
```
|
42
59
|
|
@@ -62,6 +79,9 @@ end
|
|
62
79
|
|
63
80
|
### non-Rack app (like background jobs)
|
64
81
|
```ruby
|
82
|
+
require 'aws-xray'
|
83
|
+
Aws::Xray.config.name = 'my-app'
|
84
|
+
|
65
85
|
# Build HTTP client with Faraday builder.
|
66
86
|
# You can set the down stream app id to Host header as well.
|
67
87
|
client = Faraday.new('...') do |builder|
|
@@ -81,6 +101,35 @@ Aws::Xray::Context.with_new_context('test-app', xray_client, trace_header) do
|
|
81
101
|
end
|
82
102
|
```
|
83
103
|
|
104
|
+
## Configurations
|
105
|
+
### Recording pplication version
|
106
|
+
aws-xray automatically tries to set application version by reading `app_root/REVISION` file.
|
107
|
+
If you want to set another version, set it with:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# In initialization phase.
|
111
|
+
Aws::Xray.config.version = 'deadbeef'
|
112
|
+
```
|
113
|
+
|
114
|
+
### Default annotation and metadata
|
115
|
+
aws-xray records hostname by default.
|
116
|
+
|
117
|
+
If you want to record specific annotation in all of your segments, configure like:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
Aws::Xray.config.default_annotation = Aws::Xray.config.default_annotation.merge(key: 'value')
|
121
|
+
```
|
122
|
+
|
123
|
+
Keys must be alphanumeric characters with underscore and values must be one of String or Integer or Boolean values.
|
124
|
+
|
125
|
+
For meta data:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Aws::Xray.config.default_metadata = Aws::Xray.config.default_metadata.merge(key: ['some', 'meaningful', 'value'])
|
129
|
+
```
|
130
|
+
|
131
|
+
Note: See official document to know what annotation and metadata are in AWS X-Ray.
|
132
|
+
|
84
133
|
## Development
|
85
134
|
|
86
135
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/TODO.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Enbed user information to segment:
|
2
|
+
|
3
|
+
```ruby
|
4
|
+
# In configuration phase
|
5
|
+
use Aws::Xray::Rack, capture_user_data: ->(env) { env['X-User-Id'] }
|
6
|
+
|
7
|
+
# Implementation image:
|
8
|
+
class Rack
|
9
|
+
def call(env)
|
10
|
+
@app.call(env)
|
11
|
+
capture_user_data.call(env)
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
---
|
16
|
+
|
17
|
+
`aws` field. Especially EC2 and ECS field.
|
18
|
+
|
19
|
+
---
|
20
|
+
|
21
|
+
Send in_progress segment.
|
22
|
+
|
23
|
+
---
|
24
|
+
|
25
|
+
`precursor_ids`.
|
data/example/Gemfile
CHANGED
data/example/REVISION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
deadbeef
|
@@ -1,7 +1,18 @@
|
|
1
|
+
require 'pry'
|
1
2
|
require 'aws-xray'
|
2
3
|
|
3
4
|
use Aws::Xray::Rack, name: 'campain-app'
|
4
5
|
|
6
|
+
class DbConnectionError < StandardError
|
7
|
+
def initialize
|
8
|
+
super('Could not connect to DB')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
5
12
|
run Proc.new {|env|
|
6
|
-
|
13
|
+
if rand(0..1) == 0
|
14
|
+
raise DbConnectionError
|
15
|
+
else
|
16
|
+
['200', {'Content-Type' => 'text/plain'}, ['0']]
|
17
|
+
end
|
7
18
|
}
|
data/example/fron_app_config.ru
CHANGED
data/example/user_app_config.ru
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Aws
|
2
|
+
module Xray
|
3
|
+
module AnnotationValidator
|
4
|
+
extend self
|
5
|
+
|
6
|
+
# @param [Hash] h annotation hash.
|
7
|
+
# @raise RuntimeError
|
8
|
+
def call(h)
|
9
|
+
invalid_keys = h.keys.reject {|k| k.to_s.match(/\A[A-Za-z0-9_]+\z/) }
|
10
|
+
raise 'Keys must be alphanumeric and underscore string' unless invalid_keys.empty?
|
11
|
+
invalid_values = h.values.reject {|v| v.is_a?(String) || v.is_a?(Integer) || (v == true || v == false) }
|
12
|
+
raise 'Values must be one of String or Integer or Boolean values' unless invalid_values.empty?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Aws
|
2
|
+
module Xray
|
3
|
+
class Cause
|
4
|
+
MAX_BACKTRACE_SIZE = 10
|
5
|
+
|
6
|
+
def initialize(stack: [], message: nil, type: nil)
|
7
|
+
@id = SecureRandom.hex(8)
|
8
|
+
@working_directory = Dir.pwd
|
9
|
+
@stack = stack
|
10
|
+
@message = message
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_h(remote: false)
|
15
|
+
truncated, stack = build_stack(@stack, @working_directory)
|
16
|
+
{
|
17
|
+
working_directory: @working_directory,
|
18
|
+
paths: [],
|
19
|
+
exceptions: [
|
20
|
+
{
|
21
|
+
id: @id,
|
22
|
+
message: @message,
|
23
|
+
type: @type,
|
24
|
+
remote: remote,
|
25
|
+
truncated: truncated,
|
26
|
+
stack: stack,
|
27
|
+
},
|
28
|
+
],
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_stack(stack, dir)
|
33
|
+
truncated = [stack.size - MAX_BACKTRACE_SIZE, 0].max
|
34
|
+
stack = stack[0..MAX_BACKTRACE_SIZE - 1].map do |s|
|
35
|
+
file, line, method_name = s.split(':')
|
36
|
+
{
|
37
|
+
path: file.sub(dir, ''),
|
38
|
+
line: line,
|
39
|
+
label: method_name,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
return truncated, stack
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/aws/xray/client.rb
CHANGED
@@ -7,15 +7,15 @@ module Aws
|
|
7
7
|
#
|
8
8
|
# XXX: keep options for implmenting copying later.
|
9
9
|
def initialize(host: '127.0.0.1', port: 2000, sock: nil)
|
10
|
-
@
|
11
|
-
@sock = sock ||
|
10
|
+
@host, @port = host, port
|
11
|
+
@sock = sock || UDPSocket.new
|
12
12
|
end
|
13
13
|
|
14
14
|
# @param [Aws::Xray::Segment] segment
|
15
15
|
def send_segment(segment)
|
16
16
|
segment.finish
|
17
17
|
payload = %!{"format": "json", "version": 1}\n#{segment.to_json}\n!
|
18
|
-
len = @sock.send(payload, 0)
|
18
|
+
len = @sock.send(payload, 0, @host, @port)
|
19
19
|
# TODO: retry
|
20
20
|
if payload.size != len
|
21
21
|
$stderr.puts("Can not send all bytes: #{len} sent")
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'aws/xray/annotation_validator'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module Xray
|
6
|
+
# thread-unsafe, suppose to be used only in initialization phase.
|
7
|
+
class Configuration
|
8
|
+
# @return [String] name Logical service name for this application.
|
9
|
+
attr_accessor :name
|
10
|
+
|
11
|
+
# @return [Hash] client_options For xray-agent client.
|
12
|
+
# - host: e.g. '127.0.0.1'
|
13
|
+
# - port: e.g. 2000
|
14
|
+
# - sock: test purpose.
|
15
|
+
def client_options
|
16
|
+
@client_options ||= { host: '127.0.0.1', port: 2000 }
|
17
|
+
end
|
18
|
+
attr_writer :client_options
|
19
|
+
|
20
|
+
# @return [String]
|
21
|
+
def version
|
22
|
+
@version ||= VersionDetector.new.call
|
23
|
+
end
|
24
|
+
# @param [String,Proc] version A String or callable object which returns application version.
|
25
|
+
# Default version detection tries to solve with `app_root/REVISION` file.
|
26
|
+
def version=(v)
|
27
|
+
@version = v.respond_to?(:call) ? v.call : v
|
28
|
+
end
|
29
|
+
|
30
|
+
DEFAULT_ANNOTATION = {
|
31
|
+
hostname: Socket.gethostname,
|
32
|
+
}.freeze
|
33
|
+
# @return [Hash] default annotation with key-value format.
|
34
|
+
def default_annotation
|
35
|
+
@default_annotation ||= DEFAULT_ANNOTATION
|
36
|
+
end
|
37
|
+
# @param [Hash] h default annotation Hash.
|
38
|
+
def default_annotation=(annotation)
|
39
|
+
AnnotationValidator.call(annotation)
|
40
|
+
@default_annotation = annotation
|
41
|
+
end
|
42
|
+
|
43
|
+
DEFAULT_METADATA = {
|
44
|
+
tracing_sdk: {
|
45
|
+
name: 'aws-xray',
|
46
|
+
version: Aws::Xray::VERSION,
|
47
|
+
}
|
48
|
+
}.freeze
|
49
|
+
# @return [Hash] Default metadata.
|
50
|
+
def default_metadata
|
51
|
+
@default_metadata ||= DEFAULT_METADATA
|
52
|
+
end
|
53
|
+
# @param [Hash] metadata Default metadata.
|
54
|
+
attr_writer :default_metadata
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/aws/xray/context.rb
CHANGED
@@ -14,7 +14,7 @@ module Aws
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def current
|
17
|
-
Thread.current
|
17
|
+
Thread.current.thread_variable_get(VAR_NAME) || raise(NotSetError)
|
18
18
|
end
|
19
19
|
|
20
20
|
def with_new_context(name, client, trace_header)
|
@@ -27,12 +27,11 @@ module Aws
|
|
27
27
|
private
|
28
28
|
|
29
29
|
def build_current(name, client, trace_header)
|
30
|
-
Thread.current
|
30
|
+
Thread.current.thread_variable_set(VAR_NAME, Context.new(name, client, trace_header))
|
31
31
|
end
|
32
32
|
|
33
|
-
# XXX: Use delete API if exists
|
34
33
|
def remove_current
|
35
|
-
Thread.current
|
34
|
+
Thread.current.thread_variable_set(VAR_NAME, nil)
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
@@ -45,25 +44,35 @@ module Aws
|
|
45
44
|
@base_segment = Segment.build(@name, trace_header)
|
46
45
|
end
|
47
46
|
|
47
|
+
# Rescue standard errors and record the error to the segment.
|
48
|
+
# Then re-raise the error.
|
49
|
+
#
|
50
|
+
# @yield [Aws::Xray::Segment]
|
51
|
+
# @return [Object] A value which given block returns.
|
48
52
|
def base_trace
|
49
|
-
res = yield
|
53
|
+
res = yield @base_segment
|
50
54
|
@client.send_segment(@base_segment)
|
51
55
|
res
|
52
56
|
rescue => e
|
53
|
-
@base_segment.set_error(e)
|
57
|
+
@base_segment.set_error(fault: true, e: e)
|
54
58
|
@client.send_segment(@base_segment)
|
55
59
|
raise e
|
56
60
|
end
|
57
61
|
|
62
|
+
# Rescue standard errors and record the error to the sub segment.
|
63
|
+
# Then re-raise the error.
|
64
|
+
#
|
58
65
|
# @param [Boolean] remote
|
66
|
+
# @param [String] name Arbitrary name of the sub segment. e.g. "funccall_f".
|
59
67
|
# @yield [Aws::Xray::SubSegment]
|
68
|
+
# @return [Object] A value which given block returns.
|
60
69
|
def child_trace(remote:, name:)
|
61
70
|
sub = SubSegment.build(@trace_header, @base_segment, remote: remote, name: name)
|
62
71
|
res = yield sub
|
63
72
|
@client.send_segment(sub)
|
64
73
|
res
|
65
74
|
rescue => e
|
66
|
-
sub.set_error(e)
|
75
|
+
sub.set_error(fault: true, e: e)
|
67
76
|
@client.send_segment(sub)
|
68
77
|
raise e
|
69
78
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'aws/xray/cause'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Xray
|
5
|
+
class Error < Struct.new(:error, :throttle, :fault, :e, :remote, :cause)
|
6
|
+
MAX_BACKTRACE_SIZE = 10
|
7
|
+
|
8
|
+
def to_h
|
9
|
+
h = {
|
10
|
+
error: error,
|
11
|
+
throttle: throttle,
|
12
|
+
fault: fault
|
13
|
+
}
|
14
|
+
if cause
|
15
|
+
h[:cause] = cause.to_h(remote: remote)
|
16
|
+
end
|
17
|
+
# Overwrite cause because recording exception is more important.
|
18
|
+
if e
|
19
|
+
h[:cause] = build_cause_from_exception(e, remote)
|
20
|
+
end
|
21
|
+
h
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# TODO: Setting cause API. Downstream API's exception?
|
27
|
+
# TODO: paths.
|
28
|
+
def build_cause_from_exception(e, remote)
|
29
|
+
truncated, stack = build_stack(e, Dir.pwd + '/')
|
30
|
+
{
|
31
|
+
working_directory: Dir.pwd,
|
32
|
+
paths: [],
|
33
|
+
exceptions: [
|
34
|
+
id: SecureRandom.hex(8),
|
35
|
+
message: e.message,
|
36
|
+
type: e.class.to_s,
|
37
|
+
remote: remote,
|
38
|
+
truncated: truncated,
|
39
|
+
skipped: 0,
|
40
|
+
cause: nil,
|
41
|
+
stack: stack,
|
42
|
+
],
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_stack(e, dir)
|
47
|
+
truncated = [e.backtrace.size - MAX_BACKTRACE_SIZE, 0].max
|
48
|
+
stack = e.backtrace[0..MAX_BACKTRACE_SIZE - 1].map do |b|
|
49
|
+
file, line, method_name = b.split(':')
|
50
|
+
{
|
51
|
+
path: file.sub(dir, ''),
|
52
|
+
line: line,
|
53
|
+
label: method_name,
|
54
|
+
}
|
55
|
+
end
|
56
|
+
return truncated, stack
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/aws/xray/faraday.rb
CHANGED
@@ -3,22 +3,36 @@ require 'faraday'
|
|
3
3
|
module Aws
|
4
4
|
module Xray
|
5
5
|
class Faraday < ::Faraday::Middleware
|
6
|
+
# @param [Object] app Faraday app.
|
7
|
+
# @param [String] name Logical service name for downstream API.
|
6
8
|
def initialize(app, name = nil)
|
7
9
|
super(app)
|
8
10
|
@name = name
|
9
11
|
end
|
10
12
|
|
11
|
-
# XXX: use host header?
|
12
13
|
def call(req_env)
|
13
14
|
name = @name || req_env.request_headers['Host'] || "unknown-request-from-#{Context.current.name}"
|
14
15
|
|
15
16
|
Context.current.child_trace(remote: true, name: name) do |sub|
|
16
17
|
propagate_trace_header = sub.generate_trace_header
|
17
18
|
req_env.request_headers[TRACE_HEADER] = propagate_trace_header.to_header_value
|
18
|
-
sub.set_http_request(req_env)
|
19
|
+
sub.set_http_request(Request.build_from_faraday_env(req_env))
|
19
20
|
|
20
21
|
@app.call(req_env).on_complete do |res_env|
|
21
|
-
sub.set_http_response(res_env)
|
22
|
+
sub.set_http_response(res_env.status, res_env.response_headers['Content-Length'])
|
23
|
+
case res_env.status
|
24
|
+
when 499
|
25
|
+
cause = Cause.new(stack: caller, message: 'Got 499', type: 'http_request_error')
|
26
|
+
sub.set_error(error: true, throttle: true, cause: cause)
|
27
|
+
when 400..498
|
28
|
+
cause = Cause.new(stack: caller, message: 'Got 4xx', type: 'http_request_error')
|
29
|
+
sub.set_error(error: true, cause: cause)
|
30
|
+
when 500..599
|
31
|
+
cause = Cause.new(stack: caller, message: 'Got 5xx', type: 'http_request_error')
|
32
|
+
sub.set_error(fault: true, remote: true, cause: cause)
|
33
|
+
else
|
34
|
+
# pass
|
35
|
+
end
|
22
36
|
end
|
23
37
|
end
|
24
38
|
end
|
data/lib/aws/xray/rack.rb
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
require 'aws/xray/trace_header'
|
2
2
|
require 'aws/xray/client'
|
3
3
|
require 'aws/xray/context'
|
4
|
+
require 'aws/xray/version_detector'
|
4
5
|
|
5
6
|
module Aws
|
6
7
|
module Xray
|
7
8
|
class Rack
|
8
9
|
TRACE_ENV = 'HTTP_X_AMZN_TRACE_ID'.freeze
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
class MissingNameError < ::StandardError
|
12
|
+
def initialize
|
13
|
+
super("`name` is empty. Configure this with `Aws::Xray.config.name = 'my-app'`.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: excluded_paths, included_paths
|
18
|
+
#
|
19
|
+
# @param [Hash] client_options For xray-agent client.
|
20
|
+
# - host: e.g. '127.0.0.1'
|
21
|
+
# - port: e.g. 2000
|
22
|
+
# - sock: test purpose.
|
23
|
+
def initialize(app, client_options: {})
|
13
24
|
@app = app
|
14
|
-
@name = name
|
15
|
-
@client = Client.new(client_options)
|
25
|
+
@name = Aws::Xray.config.name || raise(MissingNameError)
|
26
|
+
@client = Client.new(Aws::Xray.config.client_options.merge(client_options))
|
16
27
|
end
|
17
28
|
|
18
29
|
def call(env)
|
@@ -24,8 +35,10 @@ module Aws
|
|
24
35
|
end
|
25
36
|
|
26
37
|
Context.with_new_context(@name, @client, trace_header) do
|
27
|
-
Context.current.base_trace do
|
38
|
+
Context.current.base_trace do |seg|
|
39
|
+
seg.set_http_request(Request.build_from_rack_env(env))
|
28
40
|
status, headers, body = @app.call(env)
|
41
|
+
seg.set_http_response(status, headers['Content-Length'])
|
29
42
|
headers[TRACE_HEADER] = trace_header.to_header_value
|
30
43
|
[status, headers, body]
|
31
44
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Aws
|
2
|
+
module Xray
|
3
|
+
attrs = [:method, :url, :user_agent, :client_ip, :x_forwarded_for, :traced]
|
4
|
+
class Request < Struct.new(*attrs)
|
5
|
+
def self.build_from_rack_env(env)
|
6
|
+
new(
|
7
|
+
env['REQUEST_METHOD'], # method
|
8
|
+
env['REQUEST_URI'], # url
|
9
|
+
env['HTTP_USER_AGENT'], # user_agent
|
10
|
+
env['X-Forwarded-For'], # client_ip
|
11
|
+
!!env['X-Forwarded-For'], # x_forwarded_for
|
12
|
+
false, # traced
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build_from_faraday_env(env)
|
17
|
+
new(
|
18
|
+
env.method.to_s.upcase, # method
|
19
|
+
env.url.to_s, # url
|
20
|
+
env.request_headers['User-Agent'], # user_agent
|
21
|
+
nil, # client_ip
|
22
|
+
false, # x_forwarded_for
|
23
|
+
false, # traced
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/aws/xray/segment.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'securerandom'
|
3
|
+
require 'aws/xray/request'
|
4
|
+
require 'aws/xray/response'
|
5
|
+
require 'aws/xray/error'
|
6
|
+
require 'aws/xray/annotation_validator'
|
3
7
|
|
4
8
|
module Aws
|
5
9
|
module Xray
|
@@ -19,23 +23,45 @@ module Aws
|
|
19
23
|
@id = SecureRandom.hex(8)
|
20
24
|
@trace_id = trace_id
|
21
25
|
@parent_id = parent_id
|
26
|
+
@version = Aws::Xray.config.version
|
22
27
|
start
|
23
28
|
@end_time = nil
|
24
29
|
@http_request = nil
|
25
30
|
@http_response = nil
|
26
31
|
@error = nil
|
32
|
+
@annotation = Aws::Xray.config.default_annotation
|
33
|
+
@metadata = Aws::Xray.config.default_metadata
|
27
34
|
end
|
28
35
|
|
29
|
-
# @param [
|
30
|
-
def set_http_request(
|
36
|
+
# @param [Aws::Xray::Request] request
|
37
|
+
def set_http_request(request)
|
38
|
+
@http_request = request
|
31
39
|
end
|
32
40
|
|
33
|
-
# @param [
|
34
|
-
|
41
|
+
# @param [Integer] status HTTP status
|
42
|
+
# @param [Integer] length Size of HTTP response body
|
43
|
+
def set_http_response(status, length)
|
44
|
+
@http_response = Response.new(status, length)
|
35
45
|
end
|
36
46
|
|
37
|
-
|
38
|
-
|
47
|
+
# @param [Boolean] error Indicating that a client error occurred (response status code was 4XX Client Error).
|
48
|
+
# @param [Boolean] throttle Indicating that a request was throttled (response status code was 429 Too Many Requests).
|
49
|
+
# @param [Boolean] fault Indicating that a server error occurred (response status code was 5XX Server Error).
|
50
|
+
# @param [Exception] e An Exception object
|
51
|
+
def set_error(error: false, throttle: false, fault: false, e: nil, remote: false, cause: nil)
|
52
|
+
@error = Error.new(error, throttle, fault, e, remote, cause)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [Hash] annotation Keys must consist of only alphabets and underscore.
|
56
|
+
# Values must be one of String or Integer or Boolean values.
|
57
|
+
def set_annotation(annotation)
|
58
|
+
AnnotationValidator.call(h)
|
59
|
+
@annotation = @annotation.merge(annotation)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param [Hash] metadata
|
63
|
+
def set_metadata(metadata)
|
64
|
+
@metadata = @metadata.merge(metadata)
|
39
65
|
end
|
40
66
|
|
41
67
|
def finish(now = Time.now)
|
@@ -52,12 +78,30 @@ module Aws
|
|
52
78
|
id: @id,
|
53
79
|
trace_id: @trace_id,
|
54
80
|
start_time: @start_time,
|
81
|
+
annotation: @annotation,
|
82
|
+
metadata: @metadata,
|
55
83
|
}
|
84
|
+
if @version
|
85
|
+
h[:service] = { version: @version }
|
86
|
+
end
|
87
|
+
if @http_request
|
88
|
+
request_hash = @http_request.to_h
|
89
|
+
# traced is SubSegment only
|
90
|
+
request_hash.delete(:traced)
|
91
|
+
h[:http] = { request: request_hash }
|
92
|
+
end
|
93
|
+
if @http_response
|
94
|
+
h[:http] ||= {}
|
95
|
+
h[:http][:response] = @http_response.to_h
|
96
|
+
end
|
56
97
|
if @end_time.nil?
|
57
98
|
h[:in_progress] = true
|
58
99
|
else
|
59
100
|
h[:end_time] = @end_time
|
60
101
|
end
|
102
|
+
if @error
|
103
|
+
h.merge!(@error.to_h)
|
104
|
+
end
|
61
105
|
h[:parent_id] = @parent_id if @parent_id
|
62
106
|
h
|
63
107
|
end
|
data/lib/aws/xray/sub_segment.rb
CHANGED
@@ -17,8 +17,21 @@ module Aws
|
|
17
17
|
@remote = !!remote
|
18
18
|
end
|
19
19
|
|
20
|
+
# Set traced=false if the downstream call is not traced app.
|
21
|
+
# e.g. Third-party Web API call.
|
22
|
+
# http://docs.aws.amazon.com/xray/latest/devguide/xray-api-segmentdocuments.html
|
23
|
+
def set_http_request(env, traced: false)
|
24
|
+
super(env)
|
25
|
+
@http_request.traced = traced
|
26
|
+
end
|
27
|
+
|
20
28
|
def to_h
|
21
29
|
h = super
|
30
|
+
# x_forwarded_for is Segment only.
|
31
|
+
if h[:http] && h[:http][:request]
|
32
|
+
h[:http][:request].delete(:x_forwarded_for)
|
33
|
+
h[:http][:request][:traced] = @http_request.traced
|
34
|
+
end
|
22
35
|
h[:type] = TYPE_NAME
|
23
36
|
h[:namespace] = 'remote' if @remote
|
24
37
|
h
|
data/lib/aws/xray/version.rb
CHANGED
data/lib/aws/xray.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'aws/xray/version'
|
2
2
|
require 'aws/xray/rack'
|
3
3
|
require 'aws/xray/faraday'
|
4
|
+
require 'aws/xray/configuration'
|
4
5
|
|
5
6
|
module Aws
|
6
7
|
module Xray
|
7
8
|
TRACE_HEADER = 'X-Amzn-Trace-Id'.freeze
|
9
|
+
|
10
|
+
@config = Configuration.new
|
11
|
+
class << self
|
12
|
+
attr_reader :config
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-xray
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taiki Ono
|
@@ -94,27 +94,37 @@ files:
|
|
94
94
|
- LICENSE.txt
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
|
+
- TODO.md
|
97
98
|
- aws-xray.gemspec
|
98
99
|
- bin/console
|
99
100
|
- bin/setup
|
100
101
|
- example/Gemfile
|
101
102
|
- example/Procfile
|
102
103
|
- example/README.md
|
104
|
+
- example/REVISION
|
103
105
|
- example/campain_app_config.ru
|
104
106
|
- example/fron_app_config.ru
|
105
107
|
- example/recipe_app_config.ru
|
106
108
|
- example/user_app_config.ru
|
107
109
|
- lib/aws-xray.rb
|
108
110
|
- lib/aws/xray.rb
|
111
|
+
- lib/aws/xray/annotation_validator.rb
|
112
|
+
- lib/aws/xray/cause.rb
|
109
113
|
- lib/aws/xray/client.rb
|
114
|
+
- lib/aws/xray/configuration.rb
|
110
115
|
- lib/aws/xray/context.rb
|
116
|
+
- lib/aws/xray/error.rb
|
111
117
|
- lib/aws/xray/faraday.rb
|
112
118
|
- lib/aws/xray/header_parser.rb
|
113
119
|
- lib/aws/xray/rack.rb
|
120
|
+
- lib/aws/xray/rails.rb
|
121
|
+
- lib/aws/xray/request.rb
|
122
|
+
- lib/aws/xray/response.rb
|
114
123
|
- lib/aws/xray/segment.rb
|
115
124
|
- lib/aws/xray/sub_segment.rb
|
116
125
|
- lib/aws/xray/trace_header.rb
|
117
126
|
- lib/aws/xray/version.rb
|
127
|
+
- lib/aws/xray/version_detector.rb
|
118
128
|
homepage: https://github.com/taiki45/aws-xray
|
119
129
|
licenses:
|
120
130
|
- MIT
|