-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathrack.rb
89 lines (79 loc) · 2.98 KB
/
rack.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
require 'rack/request'
require 'aws-xray-sdk'
require 'aws-xray-sdk/facets/helper'
module XRay
module Rack
# Rack middleware that generates a segment for each request/response cycle.
class Middleware
include XRay::Facets::Helper
X_FORWARD = 'HTTP_X_FORWARDED_FOR'.freeze
SCHEME_SEPARATOR = "://".freeze
def initialize(app, recorder: nil)
@app = app
@recorder = recorder || XRay.recorder
end
def call(env)
header = construct_header(headers: env)
req = ::Rack::Request.new(env)
# params required for path based sampling
host = req.host
url_path = req.path
method = req.request_method
# get segment name from host header if applicable
seg_name = @recorder.segment_naming.provide_name(host: req.host)
# get sampling decision
sampled = should_sample?(
header_obj: header, recorder: @recorder, sampling_req:
{ host: host, http_method: method, url_path: url_path, service: seg_name }
)
# begin the segment
segment = @recorder.begin_segment seg_name, trace_id: header.root, parent_id: header.parent_id,
sampled: sampled
# add neccessary http request metadata to the segment
req_meta = extract_request_meta(req)
segment.merge_http_request request: req_meta unless req_meta.empty?
begin
status, headers, body = @app.call env
resp_meta = {}
resp_meta[:status] = status
# Don't set content_length if it is not available on headers.
resp_obj = ::Rack::Response.new body: body, status: status, headers: headers
if len = resp_obj.content_length
resp_meta[:content_length] = len
end
segment.merge_http_response response: resp_meta
trace_header = {TRACE_HEADER => TraceHeader.from_entity(entity: segment).root_string}
headers.merge!(trace_header)
[status, headers, body]
rescue Exception => e
segment.apply_status_code status: 500
segment.add_exception exception: e
raise e
ensure
@recorder.end_segment
end
end
private
def extract_request_meta(req)
req_meta = {}
req_meta[:url] = req.scheme + SCHEME_SEPARATOR if req.scheme
req_meta[:url] += req.host_with_port if req.host_with_port
req_meta[:url] += req.path if req.path
req_meta[:user_agent] = req.user_agent if req.user_agent
req_meta[:method] = req.request_method if req.request_method
if req.has_header?(X_FORWARD)
req_meta[:client_ip] = get_ip(req.get_header(X_FORWARD))
req_meta[:x_forwarded_for] = true
elsif v = req.ip
req_meta[:client_ip] = v
end
req_meta
end
# get the last ip from header string
def get_ip(v)
ips = v.split(',')
ips[ips.length - 1]
end
end
end
end