request-tracer 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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