inject and extract for http requests and rack requests

This commit is contained in:
Nick Gauthier 2016-11-10 10:28:41 -05:00
Родитель e7b3e1b3a5
Коммит 492c0eaa5b
4 изменённых файлов: 129 добавлений и 2 удалений

Просмотреть файл

@ -7,6 +7,7 @@ test:
bundle exec rake spec
ruby example.rb
ruby examples/fork_children/main.rb
ruby examples/rack/inject_extract.rb
benchmark:
ruby benchmark/bench.rb

Просмотреть файл

@ -0,0 +1,66 @@
require 'bundler/setup'
require 'lightstep'
require 'rack'
require 'rack/server'
$token = '{your_access_token}'
$request_id = 'abc123'
class Router
def initialize
@tracer = LightStep::Tracer.new(component_name: 'router', access_token: $token)
end
def call(env)
span = @tracer.start_span("router_call").set_baggage_item("request-id", $request_id)
span.log(event: "router_request", env: env)
puts "parent #{span.trace_id}"
client = Net::HTTP.new("localhost", "9002")
req = Net::HTTP::Post.new("/")
@tracer.inject(span, LightStep::Tracer::FORMAT_HTTP, req)
res = client.request(req)
span.log(event: "application_response", response: res.to_s)
span.finish
@tracer.flush
puts "----> https://app.lightstep.com/#{$token}/trace?span_guid=#{span.id}&at_micros=#{span.start_micros} <----"
[200, {}, [res.body]]
end
end
class App
def initialize
@tracer = LightStep::Tracer.new(component_name: 'app', access_token: $token)
end
def call(env)
span = @tracer.extract("app_call", LightStep::Tracer::FORMAT_HTTP, env)
puts "child #{span.to_h[:trace_guid]}"
span.log(event: "application", env: env)
sleep 0.05
span.finish
@tracer.flush
[200, {}, ["application"]]
end
end
router_thread = Thread.new do
Thread.abort_on_exception = true
Rack::Server.start(app: Router.new, Port: 9001)
end
app_thread = Thread.new do
Thread.abort_on_exception = true
Rack::Server.start(app: App.new, Port: 9002)
end
loop do
begin
p Net::HTTP.get(URI("http://localhost:9001/"))
break
rescue Errno::ECONNREFUSED
sleep 0.05
end
end

Просмотреть файл

@ -11,6 +11,7 @@ module LightStep
class Tracer
FORMAT_TEXT_MAP = 1
FORMAT_BINARY = 2
FORMAT_HTTP = 3
class Error < LightStep::Error; end
class ConfigurationError < LightStep::Tracer::Error; end
@ -89,13 +90,15 @@ module LightStep
# Inject a span into the given carrier
# @param span [Span]
# @param format [LightStep::Tracer::FORMAT_TEXT_MAP, LightStep::Tracer::FORMAT_BINARY]
# @param carrier [Hash-like]
# @param carrier [Hash, Net::HTTP::Request]
def inject(span, format, carrier)
case format
when LightStep::Tracer::FORMAT_TEXT_MAP
inject_to_text_map(span, carrier)
when LightStep::Tracer::FORMAT_BINARY
warn 'Binary inject format not yet implemented'
when LightStep::Tracer::FORMAT_HTTP
inject_to_http_headers(span, carrier)
else
warn 'Unknown inject format'
end
@ -104,7 +107,9 @@ module LightStep
# Extract a span from a carrier
# @param operation_name [String]
# @param format [LightStep::Tracer::FORMAT_TEXT_MAP, LightStep::Tracer::FORMAT_BINARY]
# @param carrier [Hash-like]
# @param carrier [Hash] This can be either a normal hash of http headers (uppercase and
# separated by underscores) or a Rack environment header. The Rack `HTTP_` prefix
# will automatically be stripped.
# @return [Span]
def extract(operation_name, format, carrier)
case format
@ -113,6 +118,8 @@ module LightStep
when LightStep::Tracer::FORMAT_BINARY
warn 'Binary join format not yet implemented'
nil
when LightStep::Tracer::FORMAT_HTTP
extract_from_rack_env(operation_name, carrier)
else
warn 'Unknown join format'
nil
@ -175,6 +182,8 @@ module LightStep
CARRIER_TRACER_STATE_PREFIX = 'ot-tracer-'.freeze
CARRIER_BAGGAGE_PREFIX = 'ot-baggage-'.freeze
CARRIER_RACK_HTTP_TRACER_STATE_PREFIX = "#{CARRIER_TRACER_STATE_PREFIX.gsub("-", "_").upcase}"
CARRIER_RACK_HTTP_BAGGAGE_PREFIX = "#{CARRIER_BAGGAGE_PREFIX.gsub("-", "_").upcase}"
DEFAULT_MAX_LOG_RECORDS = 1000
MIN_MAX_LOG_RECORDS = 1
@ -213,5 +222,27 @@ module LightStep
span
end
def inject_to_http_headers(span, carrier)
carrier[CARRIER_RACK_HTTP_TRACER_STATE_PREFIX + 'SPANID'] = span.id
carrier[CARRIER_RACK_HTTP_TRACER_STATE_PREFIX + 'TRACEID'] = span.trace_id unless span.trace_id.nil?
carrier[CARRIER_RACK_HTTP_TRACER_STATE_PREFIX + 'SAMPLED'] = 'true'
span.baggage.each do |key, value|
carrier[CARRIER_RACK_HTTP_BAGGAGE_PREFIX + key.gsub("-", "_").upcase.gsub(/[^A-Z0-9_]/, '')] = value
end
end
def extract_from_rack_env(operation_name, env)
extract_from_text_map(operation_name, env.reduce({}){|memo, tuple|
raw_header, value = tuple
header = raw_header.gsub(/^HTTP_/, '')
if header.start_with?(CARRIER_RACK_HTTP_TRACER_STATE_PREFIX) ||
header.start_with?(CARRIER_RACK_HTTP_BAGGAGE_PREFIX)
memo[header.gsub("_", "-").downcase] = value
end
memo
})
end
end
end

Просмотреть файл

@ -283,6 +283,35 @@ describe LightStep do
span2.finish
end
it 'should handle inject/extract for http requests and rack' do
tracer = init_test_tracer
span1 = tracer.start_span('test_span')
span1.set_baggage_item('footwear', 'cleats')
span1.set_baggage_item('umbrella', 'golf')
span1.set_baggage_item('unsafe!@#$%$^&header', 'value')
carrier = {}
tracer.inject(span1, LightStep::Tracer::FORMAT_HTTP, carrier)
expect(carrier['OT_TRACER_TRACEID']).to eq(span1.trace_id)
expect(carrier['OT_TRACER_SPANID']).to eq(span1.id)
expect(carrier['OT_BAGGAGE_FOOTWEAR']).to eq('cleats')
expect(carrier['OT_BAGGAGE_UMBRELLA']).to eq('golf')
expect(carrier['OT_BAGGAGE_UNSAFEHEADER']).to eq('value')
span2 = tracer.extract('test_span_2', LightStep::Tracer::FORMAT_HTTP, carrier)
expect(span2.trace_id).to eq(span1.trace_id)
expect(span2.tags[:parent_span_guid]).to eq(span1.id)
expect(span2.get_baggage_item('footwear')).to eq('cleats')
expect(span2.get_baggage_item('umbrella')).to eq('golf')
span3 = tracer.extract('test_span_3', LightStep::Tracer::FORMAT_HTTP, {'HTTP_OT_TRACER_TRACEID' => 'abc123'})
expect(span3.trace_id).to eq('abc123')
span1.finish
span2.finish
span3.finish
end
it 'should handle concurrent spans' do
result = nil
tracer = init_callback_tracer(proc { |obj|; result = obj; })