lhc 8.0.0 → 8.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/docs/interceptors.md +1 -1
- data/docs/interceptors/zipkin.md +23 -0
- data/lib/lhc.rb +3 -0
- data/lib/lhc/interceptors/zipkin.rb +98 -0
- data/lib/lhc/version.rb +1 -1
- data/spec/basic_methods/request_without_rails_spec.rb +21 -2
- data/spec/interceptors/zipkin/distributed_tracing_spec.rb +52 -0
- data/spec/support/zipkin_mock.rb +113 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '059dd1e79e371a3df375a6a565b4797c11bf71da'
|
4
|
+
data.tar.gz: b2a5925b099b34812d6cb1aef256290d0cace0e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aff5120baa514889103791b6681e4776bbf8e5055db5c8b126fae5580487f72da833d3a472fd15b8c930807a1500d58e4a1c3c7c7c332ed47b8f9d460d2ac36d
|
7
|
+
data.tar.gz: a9959d2b3c84fd4125fe682eb172d6e06b81c225758931a0b493a7dadfa6a6b0faf4460e6a5ae7424482351a4fc8596312b22d6cabffe74e3de5952d16472303
|
data/.rubocop.yml
CHANGED
data/docs/interceptors.md
CHANGED
@@ -23,7 +23,7 @@ Interceptors
|
|
23
23
|
## Core Interceptors
|
24
24
|
|
25
25
|
There are some interceptors that are part of LHC already, that cover some basic usecases:
|
26
|
-
like [Caching](/docs/interceptors/caching.md), [Monitoring](/docs/interceptors/monitoring.md), [Authentication](/docs/interceptors/authentication.md), [Rollbar](/docs/interceptors/rollbar.md).
|
26
|
+
like [Caching](/docs/interceptors/caching.md), [Monitoring](/docs/interceptors/monitoring.md), [Authentication](/docs/interceptors/authentication.md), [Rollbar](/docs/interceptors/rollbar.md), [Zipkin](/docs/interceptors/zipkin.md).
|
27
27
|
|
28
28
|
## Callbacks
|
29
29
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Zipkin
|
2
|
+
|
3
|
+
Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in microservice architectures [Zipkin Distributed Tracing](https://zipkin.io/).
|
4
|
+
|
5
|
+
Add the zipkin interceptor to your basic set of LHC interceptors.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
LHC.config.interceptors = [LHC::Zipkin]
|
9
|
+
```
|
10
|
+
|
11
|
+
The following configuration needs to happen in the application that wants to run this interceptor:
|
12
|
+
|
13
|
+
1. Add `gem 'zipkin-tracer'` to your Gemfile.
|
14
|
+
2. Add the necessary Rack middleware and configuration
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
config.middleware.use ZipkinTracer::RackHandler, {
|
18
|
+
service_name: 'service-name', # name your service will be known as in zipkin
|
19
|
+
service_port: 80, # the port information that is sent along the trace
|
20
|
+
json_api_host: 'http://zipkin-collector', # the zipkin endpoint
|
21
|
+
sample_rate: 1 # sample rate, where 1 = 100% of all requests, and 0.1 is 10% of all requests
|
22
|
+
}
|
23
|
+
```
|
data/lib/lhc.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'typhoeus'
|
2
2
|
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
3
4
|
|
4
5
|
module LHC
|
5
6
|
autoload :BasicMethodsConcern,
|
@@ -117,6 +118,8 @@ module LHC
|
|
117
118
|
'lhc/response'
|
118
119
|
autoload :Rollbar,
|
119
120
|
'lhc/interceptors/rollbar'
|
121
|
+
autoload :Zipkin,
|
122
|
+
'lhc/interceptors/zipkin'
|
120
123
|
|
121
124
|
require 'lhc/railtie' if defined?(Rails)
|
122
125
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
class LHC::Zipkin < LHC::Interceptor
|
2
|
+
B3_HEADERS = {
|
3
|
+
trace_id: 'X-B3-TraceId'.freeze,
|
4
|
+
parent_id: 'X-B3-ParentSpanId'.freeze,
|
5
|
+
span_id: 'X-B3-SpanId'.freeze,
|
6
|
+
sampled: 'X-B3-Sampled'.freeze,
|
7
|
+
flags: 'X-B3-Flags'.freeze
|
8
|
+
}.freeze
|
9
|
+
TRUE = '1'.freeze # true in binary annotation
|
10
|
+
|
11
|
+
def before_request
|
12
|
+
return unless dependencies?
|
13
|
+
ZipkinTracer::TraceContainer.with_trace_id(trace_id) do
|
14
|
+
B3_HEADERS.each { |method, header| request.headers[header] = trace_id.send(method).to_s }
|
15
|
+
start_trace! if ::Trace.tracer && trace_id.sampled?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_response
|
20
|
+
return unless dependencies?
|
21
|
+
end_trace!
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def start_trace!
|
27
|
+
record_path
|
28
|
+
record_remote_endpoint
|
29
|
+
record_local_endpoint
|
30
|
+
end
|
31
|
+
|
32
|
+
def end_trace!
|
33
|
+
record_status
|
34
|
+
record_error if !response.success?
|
35
|
+
record_end
|
36
|
+
end
|
37
|
+
|
38
|
+
def trace_id
|
39
|
+
@trace_id ||= ZipkinTracer::TraceGenerator.new.next_trace_id
|
40
|
+
end
|
41
|
+
|
42
|
+
def span
|
43
|
+
@span ||= ::Trace.tracer.start_span(trace_id, url.path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def url
|
47
|
+
@url ||= URI(request.raw.url)
|
48
|
+
end
|
49
|
+
|
50
|
+
def status
|
51
|
+
@status ||= response.code.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def service_name
|
55
|
+
@service_name ||= url.host
|
56
|
+
end
|
57
|
+
|
58
|
+
def record_local_endpoint
|
59
|
+
span.record(::Trace::Annotation::CLIENT_SEND, local_endpoint)
|
60
|
+
end
|
61
|
+
|
62
|
+
def record_remote_endpoint
|
63
|
+
span.record_tag(::Trace::BinaryAnnotation::SERVER_ADDRESS, TRUE, ::Trace::BinaryAnnotation::Type::BOOL, remote_endpoint)
|
64
|
+
end
|
65
|
+
|
66
|
+
def record_path
|
67
|
+
span.record_tag(::Trace::BinaryAnnotation::PATH, url.path, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
|
68
|
+
end
|
69
|
+
|
70
|
+
def record_end
|
71
|
+
span.record(::Trace::Annotation::CLIENT_RECV, local_endpoint)
|
72
|
+
::Trace.tracer.end_span(span)
|
73
|
+
end
|
74
|
+
|
75
|
+
def record_error
|
76
|
+
span.record_tag(::Trace::BinaryAnnotation::ERROR, status, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
|
77
|
+
end
|
78
|
+
|
79
|
+
def record_status
|
80
|
+
span.record_tag(::Trace::BinaryAnnotation::STATUS, status, ::Trace::BinaryAnnotation::Type::STRING, local_endpoint)
|
81
|
+
end
|
82
|
+
|
83
|
+
def local_endpoint
|
84
|
+
@local_endpoint ||= ::Trace.default_endpoint
|
85
|
+
end
|
86
|
+
|
87
|
+
def remote_endpoint
|
88
|
+
@remote_endpoint ||= ::Trace::Endpoint.remote_endpoint(url, service_name, local_endpoint.ip_format)
|
89
|
+
end
|
90
|
+
|
91
|
+
def dependencies?
|
92
|
+
(
|
93
|
+
defined?(ZipkinTracer::TraceContainer) &&
|
94
|
+
ZipkinTracer::TraceContainer.current &&
|
95
|
+
defined?(Trace)
|
96
|
+
) || warn('[WARNING] Zipkin interceptor is enabled but dependencies are not found. See: https://github.com/local-ch/lhc/blob/master/docs/interceptors/zipkin.md')
|
97
|
+
end
|
98
|
+
end
|
data/lib/lhc/version.rb
CHANGED
@@ -1,9 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe LHC do
|
4
|
-
context '
|
4
|
+
context 'GET' do
|
5
|
+
before do
|
6
|
+
stub_request(:get, "http://datastore/v2/feedbacks").to_return(status: 200, body: "{}")
|
7
|
+
end
|
5
8
|
it "is able to call .request without LHC raising NoMethodError: undefined method `blank?' for nil:NilClass when calling it outside of the rails context" do
|
6
|
-
expect { LHC.request(url: "http://datastore/v2/feedbacks", method: :get) }.not_to raise_error
|
9
|
+
expect { LHC.request(url: "http://datastore/v2/feedbacks", method: :get) }.not_to raise_error
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'POST' do
|
14
|
+
before do
|
15
|
+
stub_request(:post, "http://datastore/v2/feedbacks").to_return(status: 200, body: "{}")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "is able to call .request without LHC raising NoMethodError: undefined method `deep_symbolize_keys' for {}:Hash" do
|
19
|
+
options = {
|
20
|
+
url: "http://datastore/v2/feedbacks",
|
21
|
+
method: :post,
|
22
|
+
body: "{}",
|
23
|
+
headers: { 'Content-Type' => 'application/json' }
|
24
|
+
}
|
25
|
+
expect { LHC.request(options) }.not_to raise_error
|
7
26
|
end
|
8
27
|
end
|
9
28
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe LHC::Zipkin do
|
4
|
+
before(:each) do
|
5
|
+
LHC.config.interceptors = [described_class]
|
6
|
+
LHC.config.endpoint(:local, 'http://local.ch')
|
7
|
+
stub_request(:get, 'http://local.ch').to_return(status: 200, body: 'The Website')
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'with zipkin tracer integration' do
|
11
|
+
before(:all) do
|
12
|
+
::ZipkinTracer::TraceContainer.setup_mock(
|
13
|
+
trace_id: 'trace_id',
|
14
|
+
parent_id: 'parent_id',
|
15
|
+
span_id: 'span_id',
|
16
|
+
sampled: 'sampled',
|
17
|
+
flags: 'flags'
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'adds the proper X-B3 headers' do
|
22
|
+
headers = LHC.get(:local).request.headers
|
23
|
+
expect(headers['X-B3-TraceId']).to eq('trace_id')
|
24
|
+
expect(headers['X-B3-ParentSpanId']).to eq('parent_id')
|
25
|
+
expect(headers['X-B3-SpanId']).to eq('span_id')
|
26
|
+
expect(headers['X-B3-Sampled']).to eq('sampled')
|
27
|
+
expect(headers['X-B3-Flags']).to eq('flags')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'wihtout zipkin integration' do
|
32
|
+
before(:all) do
|
33
|
+
TemporaryZipkinTracer = ::ZipkinTracer
|
34
|
+
Object.send(:remove_const, :ZipkinTracer)
|
35
|
+
end
|
36
|
+
|
37
|
+
after(:all) do
|
38
|
+
::ZipkinTracer = TemporaryZipkinTracer
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'adds the proper X-B3 headers' do
|
42
|
+
headers = nil
|
43
|
+
expect { headers = LHC.get(:local).request.headers }.not_to raise_error
|
44
|
+
|
45
|
+
expect(headers['X-B3-TraceId']).to be_nil
|
46
|
+
expect(headers['X-B3-ParentSpanId']).to be_nil
|
47
|
+
expect(headers['X-B3-SpanId']).to be_nil
|
48
|
+
expect(headers['X-B3-Sampled']).to be_nil
|
49
|
+
expect(headers['X-B3-Flags']).to be_nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module ZipkinTracer
|
2
|
+
class TraceContainer
|
3
|
+
attr_reader :trace_id, :parent_id, :span_id, :sampled, :flags
|
4
|
+
class << self
|
5
|
+
attr_accessor :current
|
6
|
+
|
7
|
+
def setup_mock(trace_id:, parent_id:, span_id:, sampled:, flags:)
|
8
|
+
@current = new(trace_id: trace_id, parent_id: parent_id, span_id: span_id, sampled: sampled, flags: flags)
|
9
|
+
end
|
10
|
+
|
11
|
+
def with_trace_id(trace_id)
|
12
|
+
yield trace_id
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(trace_id:, parent_id:, span_id:, sampled:, flags:)
|
17
|
+
@trace_id = trace_id
|
18
|
+
@parent_id = parent_id
|
19
|
+
@span_id = span_id
|
20
|
+
@sampled = sampled
|
21
|
+
@flags = flags
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TraceGenerator
|
26
|
+
def next_trace_id
|
27
|
+
TraceId.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class TraceId
|
32
|
+
def trace_id
|
33
|
+
'trace_id'
|
34
|
+
end
|
35
|
+
|
36
|
+
def parent_id
|
37
|
+
'parent_id'
|
38
|
+
end
|
39
|
+
|
40
|
+
def span_id
|
41
|
+
'span_id'
|
42
|
+
end
|
43
|
+
|
44
|
+
def sampled
|
45
|
+
'sampled'
|
46
|
+
end
|
47
|
+
|
48
|
+
def flags
|
49
|
+
'flags'
|
50
|
+
end
|
51
|
+
|
52
|
+
def sampled?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Span
|
58
|
+
def record_tag(*)
|
59
|
+
end
|
60
|
+
|
61
|
+
def record(*)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Trace
|
67
|
+
def self.default_endpoint
|
68
|
+
Endpoint.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.tracer
|
72
|
+
Tracer.new
|
73
|
+
end
|
74
|
+
|
75
|
+
class Tracer
|
76
|
+
def start_span(*)
|
77
|
+
return ZipkinTracer::Span.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def end_span(*)
|
81
|
+
return ZipkinTracer::Span.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Annotation
|
86
|
+
CLIENT_SEND = 'client_send'.freeze
|
87
|
+
CLIENT_RECV = 'client_recv'.freeze
|
88
|
+
end
|
89
|
+
|
90
|
+
class BinaryAnnotation
|
91
|
+
PATH = 'path'.freeze
|
92
|
+
SERVER_ADDRESS = 'server_address'.freeze
|
93
|
+
STATUS = 'status'.freeze
|
94
|
+
ERROR = 'error'.freeze
|
95
|
+
|
96
|
+
class Type
|
97
|
+
STRING = 'string'.freeze
|
98
|
+
BOOL = 'bool'.freeze
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Endpoint
|
103
|
+
class << self
|
104
|
+
def remote_endpoint(*)
|
105
|
+
new
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def ip_format
|
110
|
+
'ipv4'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhc/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -199,6 +199,7 @@ files:
|
|
199
199
|
- docs/interceptors/prometheus.md
|
200
200
|
- docs/interceptors/retry.md
|
201
201
|
- docs/interceptors/rollbar.md
|
202
|
+
- docs/interceptors/zipkin.md
|
202
203
|
- docs/request.md
|
203
204
|
- docs/response.md
|
204
205
|
- lhc.gemspec
|
@@ -225,6 +226,7 @@ files:
|
|
225
226
|
- lib/lhc/interceptors/prometheus.rb
|
226
227
|
- lib/lhc/interceptors/retry.rb
|
227
228
|
- lib/lhc/interceptors/rollbar.rb
|
229
|
+
- lib/lhc/interceptors/zipkin.rb
|
228
230
|
- lib/lhc/railtie.rb
|
229
231
|
- lib/lhc/request.rb
|
230
232
|
- lib/lhc/response.rb
|
@@ -316,6 +318,7 @@ files:
|
|
316
318
|
- spec/interceptors/retry/main_spec.rb
|
317
319
|
- spec/interceptors/return_response_spec.rb
|
318
320
|
- spec/interceptors/rollbar/main_spec.rb
|
321
|
+
- spec/interceptors/zipkin/distributed_tracing_spec.rb
|
319
322
|
- spec/rails_helper.rb
|
320
323
|
- spec/request/encoding_spec.rb
|
321
324
|
- spec/request/error_handling_spec.rb
|
@@ -341,6 +344,7 @@ files:
|
|
341
344
|
- spec/support/fixtures/json/localina_content_ad.json
|
342
345
|
- spec/support/load_json.rb
|
343
346
|
- spec/support/reset_config.rb
|
347
|
+
- spec/support/zipkin_mock.rb
|
344
348
|
- spec/timeouts/no_signal_spec.rb
|
345
349
|
- spec/timeouts/timings_spec.rb
|
346
350
|
homepage: https://github.com/local-ch/lhc
|
@@ -364,7 +368,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
364
368
|
requirements:
|
365
369
|
- Ruby >= 2.0.0
|
366
370
|
rubyforge_project:
|
367
|
-
rubygems_version: 2.6.
|
371
|
+
rubygems_version: 2.6.14
|
368
372
|
signing_key:
|
369
373
|
specification_version: 4
|
370
374
|
summary: LocalHttpClient
|
@@ -450,6 +454,7 @@ test_files:
|
|
450
454
|
- spec/interceptors/retry/main_spec.rb
|
451
455
|
- spec/interceptors/return_response_spec.rb
|
452
456
|
- spec/interceptors/rollbar/main_spec.rb
|
457
|
+
- spec/interceptors/zipkin/distributed_tracing_spec.rb
|
453
458
|
- spec/rails_helper.rb
|
454
459
|
- spec/request/encoding_spec.rb
|
455
460
|
- spec/request/error_handling_spec.rb
|
@@ -475,5 +480,6 @@ test_files:
|
|
475
480
|
- spec/support/fixtures/json/localina_content_ad.json
|
476
481
|
- spec/support/load_json.rb
|
477
482
|
- spec/support/reset_config.rb
|
483
|
+
- spec/support/zipkin_mock.rb
|
478
484
|
- spec/timeouts/no_signal_spec.rb
|
479
485
|
- spec/timeouts/timings_spec.rb
|