request-tracer 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZjEzN2Y3NGVjYTgzOGIwYzhlZDBiMjk4MDk1Y2M0ZjI2YThhZDU2MA==
5
+ data.tar.gz: !binary |-
6
+ ZWYzMDRiYjliZjk2MGJiOGM5Yzc4MTA2YzAxOGVmNWJlNDM0OWZiMA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YjJhZjU5MjRhYzg2MDY1MjNhMzkxNThkYTgyYTUyMDNmOGQ3MDU2NDQ2Y2U3
10
+ Y2ZjNjE5ZTQzNTYzMTVmNmE4ZDdkMmRjYjNjN2JmNDAyYWJlZTlkNzE4YmUy
11
+ NTRiYjc5ODY5ZjMxNzk3MDM3NjljZmEzNzE2MTI5MmRjYWU1MDA=
12
+ data.tar.gz: !binary |-
13
+ NDA1YjVhMmVhY2UwOWUxYTYwODE1Nzc4ZGFmNDZjNGMwZGU5MjEwOTZmYmE2
14
+ ZTQ5YTAzOTM5MmU0MWZjYTFhMjMyNDQyZDgwNGRhOTBjZmQ0NWNkMjlhMmM2
15
+ NTcxZTA0Y2FhMzM4NDljZWMyYzEwNGZhNjE1ZDJjMmMwYzQzZjI=
data/.gemrelease ADDED
@@ -0,0 +1,2 @@
1
+ bump:
2
+ tag: true
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,22 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.2.3
5
+ - 2.3.0
6
+ - jruby-head
7
+ - rbx
8
+ before_install:
9
+ - gem install bundler
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: rbx
13
+ - rvm: jruby-head
14
+ sudo: false
15
+ deploy:
16
+ provider: rubygems
17
+ api_key:
18
+ secure: hUcjWlgTDJWwJyIx17z28TWjPOIoul9EvbcpBUFU5S87GKx6tysz+YPbsxVivF6pBKfvg3t3KpROKX7mZbO0/5TXXylY2nSLKa0SoVmbSbwIKtwkcYqEi8Hc77JRWHm5XOnqtYhC2UzzDUIOT/8MFacXq+D+06ZcFnB4jrndS66ZvTo6T81nWYS8rOBY+YDz5snwvbUNNAvXE/AdhnkSLBdPDE68AGEUzH9CT+x38UnN+ajXs+CqWDcvTSZVXSRhUqvH73SH5Ow+lApQfSZoxnvl70C9FShxIl18F9o1ax0q312si+p/1Q/x2Hq6C6PowncAwkP1qbDORp86uANUaspDfchXpsW6MSq0/a0jumN5gLTXB2pSRSxXWFFKv9wtOXAsO6+ig48NjqyczGsp02nZCOSHumw6xkoP4Bjg2zqk0OVd0dHsXDFa5r68nJsFeA7szYQI5/6GbTN3aqm5iCcTBGbVG/pQ9SEmvz9bcSeKoSGcIcTbb11QTj1rRPlsZ0L7Li0pN46/AwCniFMPD5nTTgKqHq1GfM6ot9IN7rVl7XbaQCHMedcpcrwjj2/hzKHhOdp4VjXm2Oc98dXxaQY3xziSKxpnMmYKHpg0nbUa4JNpYzuM9ZfnpMNri4WNdc2vE+p3TgNvNP2BFgpUQJGg1g5lTLe2w0Yo8MtNVFk=
19
+ gem: request-tracer
20
+ on:
21
+ tags: true
22
+ repo: crealytics/request-tracer
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in request-tracer.gemspec
4
+ gemspec
5
+
6
+ platform :mri do
7
+ gem 'pry-byebug'
8
+ end
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ guard :bundler do
2
+ require 'guard/bundler'
3
+ require 'guard/bundler/verify'
4
+ helper = Guard::Bundler::Verify.new
5
+
6
+ files = ['Gemfile']
7
+ files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
8
+
9
+ # Assume files are symlinked from somewhere
10
+ files.each { |file| watch(helper.real_path(file)) }
11
+ end
12
+
13
+ guard :rspec, cmd: "bundle exec rspec -t focus" do
14
+ require "guard/rspec/dsl"
15
+ dsl = Guard::RSpec::Dsl.new(self)
16
+
17
+ rspec = dsl.rspec
18
+ watch(rspec.spec_helper) { rspec.spec_dir }
19
+ watch(rspec.spec_support) { rspec.spec_dir }
20
+ watch(rspec.spec_files)
21
+
22
+ ruby = dsl.ruby
23
+ dsl.watch_spec_files_for(ruby.lib_files)
24
+ end
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2016 crealytics GmbH
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ Request Tracer
2
+ ==============
3
+ [![Build Status](https://travis-ci.org/crealytics/request-tracer.svg)](https://travis-ci.org/crealytics/request-tracer)
4
+
5
+ Request Tracer is a Ruby gem that helps tracing requests through a chain of services.
6
+ It is based on [ZipkinTracer](https://github.com/openzipkin/zipkin-tracer) but doesn't force you to use Zipkin.
7
+
8
+ One possible use case is to use your logger to log traces and spans and reuse your
9
+ existing log aggregation tool of choice (e.g. ELK) to get all logs across all services
10
+ that were involved in a client's service call.
11
+
12
+ How it works
13
+ ------------
14
+ Request Tracer integrates with various other gems in order to transparently
15
+ read incoming trace headers and add trace headers to outgoing service calls.
16
+ A good introduction into Zipkin terminology [can be found here](http://www.slideshare.net/johanoskarsson/zipkin-strangeloop/25).
17
+
18
+ Reading trace headers
19
+ ---------------------
20
+ In your `config.ru` add the RackHandler middleware like this:
21
+ ```ruby
22
+ require 'request_tracer'
23
+ require 'request_tracer/integration/rack_handler'
24
+
25
+ use RequestTracer::Integration::RackHandler
26
+ run MyApp.new
27
+ ```
28
+
29
+ Writing trace headers
30
+ ---------------------
31
+ Somewhere in your code (e.g. in an initializer under `config/initializers/request-tracing.rb`)
32
+ add the following call:
33
+ ```ruby
34
+ RequestTracer.integrate_with(:rest_client)
35
+ ```
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ require 'rake'
5
+
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ begin
9
+ require 'rspec/core/rake_task'
10
+
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
13
+ task :default => :spec
14
+ rescue LoadError
15
+ # no rspec available
16
+ end
@@ -0,0 +1,21 @@
1
+ module RequestTracer
2
+ module Integration
3
+ module Base
4
+ B3_REQUIRED_FIELDS = %w(trace_id parent_span_id span_id)
5
+ B3_REQUIRED_FIELDS_FROM_SHORT_NAMES = B3_REQUIRED_FIELDS.map {|f| [f.gsub("_", ""), f] }.to_h
6
+ B3_REQUIRED_HEADERS = B3_REQUIRED_FIELDS.map {|f| "HTTP_X_B3_#{f.gsub("_", "").upcase}" }
7
+ B3_REQUIRED_FIELD_HEADER_MAP = B3_REQUIRED_FIELDS.zip(B3_REQUIRED_HEADERS).to_h
8
+ B3_REQUIRED_HEADER_FIELD_MAP = B3_REQUIRED_HEADERS.zip(B3_REQUIRED_FIELDS).to_h
9
+ B3_OPT_HEADERS = %w[HTTP_X_B3_FLAGS]
10
+ def extract_fields_from_headers(header_hash)
11
+ header_hash.map do |k,v|
12
+ special_header = /HTTP_X_B3_(.*)/.match(k)
13
+ special_header && [B3_REQUIRED_FIELDS_FROM_SHORT_NAMES[special_header[1].downcase], v]
14
+ end.compact.to_h
15
+ end
16
+ def extract_headers_from_fields(field_hash)
17
+ B3_REQUIRED_FIELDS.map {|f| ["X_B3_" + f.gsub("_", "").upcase, field_hash[f]]}.to_h
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module RequestTracer
4
+ module Integration
5
+ class RackHandler
6
+ include Base
7
+ def initialize(app, config={})
8
+ @app = app
9
+ @tracer = config[:tracer] || Trace
10
+ end
11
+ def call(env)
12
+ @tracer.record(extract_fields_from_headers(env)) do
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'base'
2
+ module RequestTracer
3
+ module Integration
4
+ module RestClientHandler
5
+ include Base
6
+ extend self
7
+ def activate
8
+ require 'rest-client'
9
+ RestClient.add_before_execution_proc do |req, params|
10
+ extract_headers_from_fields(Trace.latest).each {|h, v| req[h] = v}
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,159 @@
1
+ module RequestTracer
2
+ module Trace
3
+ extend self
4
+ TRACE_ID_UPPER_BOUND = 2 ** 64
5
+ TRACE_STACK = :trace_stack
6
+
7
+ class Annotation
8
+ attr_reader :name, :time
9
+ def initialize(name, time = DateTime.now)
10
+ @name = name
11
+ @time = time
12
+ end
13
+ end
14
+
15
+ # A span represents one specific method call
16
+ class SpanId
17
+ HEX_REGEX = /^[a-f0-9]{16}$/i
18
+ MAX_SIGNED_I64 = 9223372036854775807
19
+ MASK = (2 ** 64) - 1
20
+
21
+ def self.from_value(v)
22
+ if v.is_a?(String) && v =~ HEX_REGEX
23
+ new(v.hex)
24
+ elsif v.is_a?(Numeric)
25
+ new(v)
26
+ elsif v.is_a?(SpanId)
27
+ v
28
+ end
29
+ end
30
+
31
+ def initialize(value)
32
+ @value = value
33
+ @i64 = if @value > MAX_SIGNED_I64
34
+ -1 * ((@value ^ MASK) + 1)
35
+ else
36
+ @value
37
+ end
38
+ end
39
+
40
+ def to_s; "%016x" % @value; end
41
+ def to_i; @i64; end
42
+ end
43
+
44
+ # A trace is a set of spans that are associated with the same request
45
+ class TraceId
46
+ attr_reader :trace_id, :parent_id, :span_id
47
+ def self.spawn_from_hash(h)
48
+ span_id = Trace.generate_id
49
+ self.new(h["trace_id"] || span_id, h["span_id"], Trace.generate_id)
50
+ end
51
+ def initialize(trace_id, parent_id, span_id)
52
+ @trace_id = SpanId.from_value(trace_id)
53
+ @parent_id = parent_id && SpanId.from_value(parent_id)
54
+ @span_id = SpanId.from_value(span_id)
55
+ end
56
+
57
+ def next_id
58
+ TraceId.new(@trace_id, @span_id, Trace.generate_id)
59
+ end
60
+
61
+ def to_s
62
+ "TraceId(trace_id = #{@trace_id.to_s}, parent_id = #{@parent_id.to_s}, span_id = #{@span_id.to_s}"
63
+ end
64
+
65
+ def to_h
66
+ {"trace_id" => @trace_id.to_s, "parent_span_id" => (@parent_id || "").to_s, "span_id" => @span_id.to_s}
67
+ end
68
+ def [](key)
69
+ to_h[key]
70
+ end
71
+ def to_json
72
+ to_h.to_json
73
+ end
74
+ end
75
+
76
+
77
+ def latest
78
+ if stack.empty?
79
+ span_id = generate_id
80
+ trace_id = TraceId.new(span_id, nil, span_id)
81
+ stack.push(trace_id)
82
+ end
83
+ stack.last
84
+ end
85
+
86
+ def push(trace_info)
87
+ stack.push(TraceId.spawn_from_hash(trace_info))
88
+ if block_given?
89
+ begin
90
+ yield
91
+ ensure
92
+ pop
93
+ end
94
+ end
95
+ end
96
+
97
+ def pop
98
+ stack.pop
99
+ end
100
+
101
+ def unwind
102
+ if block_given?
103
+ begin
104
+ saved_stack = stack.dup
105
+ yield
106
+ ensure
107
+ stack = saved_stack
108
+ end
109
+ end
110
+ end
111
+
112
+ def record(annotation, &block)
113
+ tracer.record(latest, annotation, &block)
114
+ end
115
+
116
+ def set_rpc_name(name)
117
+ tracer.set_rpc_name(latest, name) unless stack.empty?
118
+ end
119
+
120
+ def tracer=(tracer)
121
+ @tracer = tracer
122
+ end
123
+
124
+ def generate_id
125
+ rand(TRACE_ID_UPPER_BOUND)
126
+ end
127
+
128
+
129
+ private
130
+
131
+ # "stack" acts as a thread local variable and cannot be shared between
132
+ # threads.
133
+ def stack=(stack)
134
+ Thread.current[TRACE_STACK] = stack
135
+ end
136
+
137
+ def stack
138
+ Thread.current[TRACE_STACK] ||= []
139
+ end
140
+
141
+ def tracer
142
+ @tracer ||= DefaultTracer.new
143
+ end
144
+
145
+ end
146
+ class NullTracer
147
+ def record(*args, &block)
148
+ block.call
149
+ end
150
+ end
151
+
152
+ class DefaultTracer
153
+ def record(*args, &block)
154
+ Trace.push(args[1].to_h) do
155
+ block.call
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,3 @@
1
+ module RequestTracer
2
+ VERSION = "0.5.2"
3
+ end
@@ -0,0 +1,10 @@
1
+ module RequestTracer
2
+ def self.integrate_with(*services)
3
+ services.each do |service|
4
+ require_relative "request_tracer/integration/#{service}_handler"
5
+ class_name = service.to_s.split('_').collect(&:capitalize).join + 'Handler'
6
+ integration_module = RequestTracer::Integration.const_get(class_name)
7
+ integration_module.activate
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/request_tracer/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "request-tracer"
6
+ spec.version = RequestTracer::VERSION
7
+ spec.authors = ["Martin Mauch"]
8
+ spec.email = ["martin.mauch@crealytics.com"]
9
+ spec.summary = %q{Traces requests using the Zipkin HTTP headers}
10
+ spec.description = %q{This is a tracer that hooks into several components to allow tracing requests across services.}
11
+ spec.homepage = ""
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency 'rest-client'
20
+ spec.add_development_dependency 'bundler', '~> 1.7'
21
+ spec.add_development_dependency 'rake', '~> 10.0'
22
+ spec.add_development_dependency "rspec", "~> 3.4"
23
+ spec.add_development_dependency "rack-test", "~> 0.6"
24
+ spec.add_development_dependency "webmock"
25
+ spec.add_development_dependency "guard", "~> 2.13"
26
+ spec.add_development_dependency "guard-rspec", "~> 4.6"
27
+ spec.add_development_dependency "guard-bundler", "~> 2.1"
28
+ spec.add_development_dependency 'geminabox'
29
+ spec.add_development_dependency 'gem-release'
30
+ spec.add_development_dependency 'pry'
31
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+ require 'support/test_app'
4
+ require 'open-uri'
5
+ require 'timeout'
6
+ require 'webmock'
7
+
8
+ # In this spec we are going to run two applications and check that they are creating traces
9
+ # And that the traces created by one application are sent to the other application
10
+ RSpec::Matchers.define_negated_matcher :a_value_different_from, :eq
11
+
12
+ describe 'integrations' do
13
+ before(:all) do
14
+ WebMock.allow_net_connect!
15
+ @port1 = 4444
16
+ @port2 = 4445
17
+ ru_location = File.expand_path('../support/test_app_config.ru', File.dirname(__FILE__))
18
+ @pipe1 = IO.popen(["rackup", ru_location, "-p", @port1.to_s, err: [:child, :out]])
19
+ @pipe2 = IO.popen(["rackup", ru_location, "-p", @port2.to_s, err: [:child, :out]])
20
+ sleep(2)
21
+ if RUBY_PLATFORM == 'java'
22
+ sleep(20) #Jruby starts slow
23
+ end
24
+ end
25
+
26
+ let(:base_url1) { "http://localhost:#{@port1}" }
27
+ let(:base_url2) { "http://localhost:#{@port2}" }
28
+
29
+ after(:all) do
30
+ Process.kill("KILL", @pipe1.pid)
31
+ Process.kill("KILL", @pipe2.pid)
32
+ end
33
+
34
+ after { read_all_pipes }
35
+
36
+ def read_without_blocking(io, maxlen = 4096)
37
+ io.read_nonblock(maxlen)
38
+ rescue => e
39
+ ""
40
+ end
41
+ let(:response) { open(url) {|f| f.read } rescue(raise "Could not read from #{url}.\nOutput from services:\n#{read_all_pipes}") }
42
+ def read_all_pipes
43
+ read_without_blocking(@pipe1) + "\n" + read_without_blocking(@pipe2)
44
+ end
45
+ let(:services_output) {
46
+ response
47
+ read_all_pipes
48
+ }
49
+ let(:traces) do
50
+ all_output = services_output
51
+ all_output.split("\n").grep(/^%%%/).sort.map {|t| JSON.parse(t.gsub(/^%%% \d+/, ""))}
52
+ end
53
+ shared_examples_for "responding to a REST call without tracing headers" do
54
+ it "does not modify the original response body" do
55
+ expect(response).to eq(expected_response)
56
+ end
57
+ it "has a trace with non-empty trace_id and span_id and an empty parent_span_id" do
58
+ expect(traces[0]).to include(
59
+ 'trace_id' => a_string_matching(/.+/),
60
+ 'span_id' => a_string_matching(/.+/),
61
+ # The parent_span_id should be empty, as a 0-level trace has no parent.
62
+ 'parent_span_id' => ""
63
+ )
64
+ end
65
+ end
66
+ shared_examples_for "responding to a transitive REST call with tracing headers" do
67
+ it "has the same trace_id as the caller, the caller's span id as parent_span_id and a fresh span_id" do
68
+ expect(traces[1]).to include(
69
+ 'trace_id' => traces[0]['trace_id'],
70
+ 'parent_span_id' => traces[0]['span_id'],
71
+ 'span_id' => a_value_different_from(traces[0]['span_id'])
72
+ )
73
+ end
74
+ it { expect([traces[1]['trace_id'], traces[1]['parent_span_id']]).not_to include(traces[1]['span_id']) }
75
+ end
76
+ context "when doing a simple service call" do
77
+ let(:url) { "#{base_url1}/hello_world" }
78
+ let(:expected_response) { 'Hello World' }
79
+ it { expect(traces.size).to eq(1) }
80
+ it_behaves_like "responding to a REST call without tracing headers"
81
+ end
82
+
83
+ context "when doing a service call that calls another service" do
84
+ let(:url) { "#{base_url1}/ouroboros?out_port=#{@port2}" }
85
+ let(:expected_response) { 'Ouroboros says Hello World' }
86
+ it_behaves_like "responding to a REST call without tracing headers"
87
+ it_behaves_like "responding to a transitive REST call with tracing headers"
88
+ it { expect(traces).to satisfy {|t| t.size == 2} }
89
+ end
90
+
91
+ end
@@ -0,0 +1,45 @@
1
+ require 'rack/mock'
2
+ require 'rack/test'
3
+ require 'spec_helper'
4
+ require 'request_tracer/integration/rack_handler'
5
+ require 'logger'
6
+
7
+ describe RequestTracer::Integration::RackHandler do
8
+ include Rack::Test::Methods
9
+ include RequestTracer::Integration::Base
10
+ let(:tracer) { double("tracer") }
11
+
12
+ def middleware(service, config={})
13
+ RequestTracer::Integration::RackHandler.new(service, config.merge(tracer: tracer))
14
+ end
15
+
16
+ def app
17
+ middleware(service)
18
+ end
19
+
20
+ let(:service) do
21
+ lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['hello']] }
22
+ end
23
+
24
+ before do
25
+ allow(tracer).to receive(:record) {|&block| block.call }
26
+ end
27
+
28
+ shared_examples_for 'traces the request' do
29
+ before do
30
+ trace_headers.each {|k, v| header(k, v)}
31
+ end
32
+ it 'traces the request' do
33
+ get '/'
34
+ expect(last_response.status).to eq(200)
35
+ expect(last_response.body).to eq('hello')
36
+ expect(tracer).to have_received(:record).with(extract_fields_from_headers(trace_headers))
37
+ end
38
+ end
39
+
40
+ let(:trace_headers) { RequestTracer::Integration::RackHandler::B3_REQUIRED_HEADERS.map {|a| [a, rand(1000)] }.to_h }
41
+ context 'Zipkin headers are passed to the middleware' do
42
+ subject { middleware(service) }
43
+ it_behaves_like "traces the request"
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ require 'rack/mock'
2
+ require 'rack/test'
3
+ require 'spec_helper'
4
+ require 'request_tracer/trace'
5
+ require 'logger'
6
+ require 'webmock/rspec'
7
+ require 'rest-client'
8
+
9
+ describe RequestTracer::Integration::RestClientHandler do
10
+ include RequestTracer::Integration::Base
11
+ RequestTracer.integrate_with(:rest_client)
12
+ before(:all) { WebMock.disable_net_connect! }
13
+ before do
14
+ stub_request(:any, "www.example.com")
15
+ end
16
+
17
+ let(:trace) { RequestTracer::Trace.latest }
18
+ it "should have set the headers on the outgoing call" do
19
+ RestClient.get("www.example.com")
20
+ expect(WebMock).to have_requested(:get, "www.example.com").
21
+ with(headers: extract_headers_from_fields(trace.to_h))
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ require 'request_tracer'
2
+ require 'pry'
3
+
4
+ RSpec.configure do |config|
5
+ config.order = :random
6
+ config.run_all_when_everything_filtered = true
7
+ end
@@ -0,0 +1,27 @@
1
+ require 'json'
2
+ require 'faraday'
3
+ require 'request_tracer'
4
+ require 'request_tracer/trace'
5
+ require 'rest-client'
6
+
7
+ class TestApp
8
+ RequestTracer.integrate_with(:rest_client)
9
+ def call(env)
10
+ store_current_trace_info # store so tests can look at historical data
11
+
12
+ req = Rack::Request.new(env)
13
+ if req.path == '/hello_world'
14
+ [ 200, {'Content-Type' => 'application/json'}, ['Hello World'] ]
15
+ elsif req.path == '/ouroboros' # this path will cause the TestApp to call the helloworld path of the app in certain port
16
+ port = Rack::Utils.parse_query(env['QUERY_STRING'], "&")['out_port']
17
+ response = RestClient.get("http://localhost:#{port}/hello_world")
18
+ [ 200, {'Content-Type' => 'application/json'}, ["Ouroboros says #{response}"]]
19
+ else
20
+ [ 500, {'Content-Type' => "text/txt"}, ["Unrecognized path #{req.path}"]]
21
+ end
22
+ end
23
+
24
+ def store_current_trace_info
25
+ $stderr.puts "%%% #{(Time.now.to_f * 1000).to_i} #{RequestTracer::Trace.latest.to_json}"
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ require 'request_tracer'
2
+ require 'request_tracer/integration/rack_handler'
3
+ require 'base64'
4
+ require File.join(`pwd`.chomp, 'spec', 'support', 'test_app')
5
+
6
+ request_tracer_config = {
7
+ service_name: 'your service name here'
8
+ }
9
+ puts "Starting service"
10
+
11
+ use RequestTracer::Integration::RackHandler, request_tracer_config
12
+ run TestApp.new
metadata ADDED
@@ -0,0 +1,240 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: request-tracer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.2
5
+ platform: ruby
6
+ authors:
7
+ - Martin Mauch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '2.13'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '2.13'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '4.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '4.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-bundler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '2.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '2.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: geminabox
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: gem-release
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pry
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ! '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: This is a tracer that hooks into several components to allow tracing
182
+ requests across services.
183
+ email:
184
+ - martin.mauch@crealytics.com
185
+ executables: []
186
+ extensions: []
187
+ extra_rdoc_files: []
188
+ files:
189
+ - .gemrelease
190
+ - .gitignore
191
+ - .travis.yml
192
+ - Gemfile
193
+ - Guardfile
194
+ - LICENSE
195
+ - README.md
196
+ - Rakefile
197
+ - lib/request_tracer.rb
198
+ - lib/request_tracer/integration/base.rb
199
+ - lib/request_tracer/integration/rack_handler.rb
200
+ - lib/request_tracer/integration/rest_client_handler.rb
201
+ - lib/request_tracer/trace.rb
202
+ - lib/request_tracer/version.rb
203
+ - request-tracer.gemspec
204
+ - spec/integration/integration_spec.rb
205
+ - spec/lib/request_tracer/integration/rack_handler_spec.rb
206
+ - spec/lib/request_tracer/integration/rest_client_handler_spec.rb
207
+ - spec/spec_helper.rb
208
+ - spec/support/test_app.rb
209
+ - spec/support/test_app_config.ru
210
+ homepage: ''
211
+ licenses:
212
+ - MIT
213
+ metadata: {}
214
+ post_install_message:
215
+ rdoc_options: []
216
+ require_paths:
217
+ - lib
218
+ required_ruby_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ! '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ required_rubygems_version: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - ! '>='
226
+ - !ruby/object:Gem::Version
227
+ version: '0'
228
+ requirements: []
229
+ rubyforge_project:
230
+ rubygems_version: 2.4.5
231
+ signing_key:
232
+ specification_version: 4
233
+ summary: Traces requests using the Zipkin HTTP headers
234
+ test_files:
235
+ - spec/integration/integration_spec.rb
236
+ - spec/lib/request_tracer/integration/rack_handler_spec.rb
237
+ - spec/lib/request_tracer/integration/rest_client_handler_spec.rb
238
+ - spec/spec_helper.rb
239
+ - spec/support/test_app.rb
240
+ - spec/support/test_app_config.ru