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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 44943f3ac93283072875bfa94985b9aa76828628
4
- data.tar.gz: 7c58541a4ba68f4b7968505029229b1f2abb0c76
3
+ metadata.gz: 7205283919522f3fa51c16bc8e5f11136ba04a9c
4
+ data.tar.gz: 0fa4f411671929e4c436939d190afa7fd48e181e
5
5
  SHA512:
6
- metadata.gz: e266ce6f924d71c447e1ca64775efbf55de67523965b3c805eb8fac5e9c99f936590857765156a8a8333ccf4d32a6cbcd0a04519220fcd5a7cd67315ff06f0b4
7
- data.tar.gz: 1988b22141c57f19b2bb3963b2f691dbbcd8ecb6a08bdeb3037e4dfee0a20193d28c8f6899a82f7257d762eeb5a89113b382dbf1d97e9b7ab976a2c4a24221d4
6
+ metadata.gz: 9c4aea978c59e664b39d10ca7df5c57c8537069fff4df2196b7e3213fa71c990a66e05cd6e0c816a95311d03e9ace2614ecddcad036e5b04c892f78ca51b1e1e
7
+ data.tar.gz: 6519acd350a5c0a6ceddad31bdd54db472466cf35bc4d5e044404e4290475607296e9b820c64e40d1099307b715fb927ccf53c5a029b249f69531ee2cacf9a4d
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Aws::Xray
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
- ## Current status
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
@@ -5,3 +5,4 @@ gem 'rack'
5
5
  gem 'aws-xray', path: File.expand_path('../', __dir__)
6
6
 
7
7
  gem 'foreman'
8
+ gem 'pry-byebug'
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
- ['200', {'Content-Type' => 'text/plain'}, ['0']]
13
+ if rand(0..1) == 0
14
+ raise DbConnectionError
15
+ else
16
+ ['200', {'Content-Type' => 'text/plain'}, ['0']]
17
+ end
7
18
  }
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'faraday'
2
3
  require 'aws-xray'
3
4
 
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'faraday'
2
3
  require 'aws-xray'
3
4
 
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'aws-xray'
2
3
 
3
4
  use Aws::Xray::Rack, name: 'user-app'
@@ -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
@@ -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
- @options = { host: host, port: port }
11
- @sock = sock || Addrinfo.udp(host, port).connect
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
@@ -14,7 +14,7 @@ module Aws
14
14
  end
15
15
 
16
16
  def current
17
- Thread.current[VAR_NAME] || raise(NotSetError)
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[VAR_NAME] = Context.new(name, client, trace_header)
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[VAR_NAME] = nil
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
@@ -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
- # XXX: excluded_paths, included_paths
11
- # XXX: document about client_options
12
- def initialize(app, name:, client_options: {})
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,11 @@
1
+ require 'aws/xray'
2
+
3
+ module Aws
4
+ module Xray
5
+ class Railtie < ::Rails::Railtie
6
+ initializer 'aws-xray.rack_middleware' do |app|
7
+ app.middleware.use Aws::Xray::Rack
8
+ end
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,6 @@
1
+ module Aws
2
+ module Xray
3
+ class Response < Struct.new(:status, :length)
4
+ end
5
+ end
6
+ end
@@ -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 [Hash] env A Rack env
30
- def set_http_request(env)
36
+ # @param [Aws::Xray::Request] request
37
+ def set_http_request(request)
38
+ @http_request = request
31
39
  end
32
40
 
33
- # @param [Array] res A Rack response
34
- def set_http_response(res)
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
- def set_error(e)
38
- # TODO: Set error object
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
@@ -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
@@ -45,8 +45,7 @@ module Aws
45
45
  !!@parent
46
46
  end
47
47
 
48
- def copy(parent: nil)
49
- parent = parent.nil? ? @parent : parent
48
+ def copy(parent:)
50
49
  self.class.new(root: @root, sampled: @sampled, parent: parent)
51
50
  end
52
51
  end
@@ -1,5 +1,5 @@
1
1
  module Aws
2
2
  module Xray
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -0,0 +1,13 @@
1
+ module Aws
2
+ module Xray
3
+ class VersionDetector
4
+ REVISION_PATH = 'REVISION'
5
+
6
+ def call
7
+ if File.exist?(REVISION_PATH)
8
+ File.read(REVISION_PATH)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
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.2.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