aws-xray 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/taiki45/aws-xray.svg?branch=master)](https://travis-ci.org/taiki45/aws-xray)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/aws-xray.svg)](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
|