/
zipkin-tracer.rb
63 lines (53 loc) · 2.01 KB
/
zipkin-tracer.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
require 'rack'
require 'zipkin-tracer/config'
require 'zipkin-tracer/tracer_factory'
require 'zipkin-tracer/rack/zipkin_env'
module ZipkinTracer
# This middleware reads Zipkin headers from the request and sets/creates a Trace.id usable by the rest of the app
# It will also send the trace to the Zipkin service using one of the methods configured.
class RackHandler
# the following constants are defined only from rack 1.6
PATH_INFO = Rack::PATH_INFO rescue 'PATH_INFO'.freeze
REQUEST_METHOD = Rack::REQUEST_METHOD rescue 'REQUEST_METHOD'.freeze
def initialize(app, config = nil)
@app = app
@config = Config.new(app, config).freeze
@tracer = TracerFactory.new.tracer(@config)
end
def call(env)
zipkin_env = ZipkinEnv.new(env, @config)
trace_id = zipkin_env.trace_id
TraceContainer.with_trace_id(trace_id) do
if !trace_id.sampled?
@app.call(env)
else
@tracer.with_new_span(trace_id, span_name(env)) do |span|
span.kind = Trace::Span::Kind::SERVER
trace!(span, zipkin_env) { @app.call(env) }
end
end
end
end
private
SERVER_RECV_TAGS = {
Trace::Span::Tag::PATH => PATH_INFO,
Trace::Span::Tag::METHOD => REQUEST_METHOD
}.freeze
def span_name(env)
"#{env[REQUEST_METHOD].to_s.downcase} #{Application.route(env)}".strip
end
def annotate_plugin(span, env, status, response_headers, response_body)
@config.annotate_plugin.call(span, env, status, response_headers, response_body) if @config.annotate_plugin
end
def trace!(span, zipkin_env, &block)
status, headers, body = yield
ensure
trace_server_information(span, zipkin_env, status)
annotate_plugin(span, zipkin_env.env, status, headers, body)
end
def trace_server_information(span, zipkin_env, status)
span.record_status(status)
SERVER_RECV_TAGS.each { |annotation_key, env_key| span.record_tag(annotation_key, zipkin_env.env[env_key]) }
end
end
end