lhc 8.0.0 → 8.1.0

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 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