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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e896a6247a34efa8fb35b9ba8cdf51ad68b8a00
4
- data.tar.gz: f5d30a0736bbb74ea0cb4b62e060c4edeb9cc48e
3
+ metadata.gz: '059dd1e79e371a3df375a6a565b4797c11bf71da'
4
+ data.tar.gz: b2a5925b099b34812d6cb1aef256290d0cace0e5
5
5
  SHA512:
6
- metadata.gz: 06f42cbc9182070e2d89c325a261095ea66665aa27ae3b61f6e3206158b1f960f9939997001b9f8db087c5ff439c89b059548d54eaceb44ae7f106d73ae931a3
7
- data.tar.gz: 663cfcbe61d6e9b220dc6073c1c1c9e4c576981984c304f60945fd30d01ca7c2c14e6aa040270439e15134b2178d8deba39d4c9141d65d214979e9382a47d99b
6
+ metadata.gz: aff5120baa514889103791b6681e4776bbf8e5055db5c8b126fae5580487f72da833d3a472fd15b8c930807a1500d58e4a1c3c7c7c332ed47b8f9d460d2ac36d
7
+ data.tar.gz: a9959d2b3c84fd4125fe682eb172d6e06b81c225758931a0b493a7dadfa6a6b0faf4460e6a5ae7424482351a4fc8596312b22d6cabffe74e3de5952d16472303
data/.rubocop.yml CHANGED
@@ -41,3 +41,6 @@ Style/RedundantReturn:
41
41
 
42
42
  RSpec/InstanceVariable:
43
43
  Enabled: false
44
+
45
+ Style/FrozenStringLiteralComment:
46
+ Enabled: false
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,3 +1,3 @@
1
1
  module LHC
2
- VERSION ||= '8.0.0'
2
+ VERSION ||= '8.1.0'
3
3
  end
@@ -1,9 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe LHC do
4
- context 'request' do
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(NoMethodError)
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.0.0
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-08 00:00:00.000000000 Z
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.12
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