zipkin 0.1.0 → 0.2.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: 8361e78533130479672a85ad8d5273035cdd261d
4
- data.tar.gz: 21ec14ab24345d5f4a320efa33570df8bee51b4a
3
+ metadata.gz: 504536eebfe1f9f6ce03dd1c9bb1ef0d2c0d870f
4
+ data.tar.gz: 9e7638f5c9b6cfc0a1061955f3475ad1c5f352d8
5
5
  SHA512:
6
- metadata.gz: b63f0b37631dea5cd999f24c83ce688946244bd6b5e5aebf1201d75ea3e3d050a3f1daa0d46d8253ed2c4e314c9c1aa98707e32b03b26bf0a17cf4fe903c477f
7
- data.tar.gz: ca8ae8cfff2d1b302967652e57c7c1d0039d035c3e006a8e004e30eef3505c4409407c224af3c9f992567106b147570eea2a7b092e0ef8855edf8817a1ee6198
6
+ metadata.gz: 0fff4fc9878ad37a878968c8805a755f110ac98418dcd88f4229fca5ceb41642c3f66df02a2aad9a0d1903e9dfbd824a359dff77d870a33b5de936b53fe04bfe
7
+ data.tar.gz: 31b4d916668c882181a08aeb1026557e42051a5ea6b7c91074085ff83ade66153ea3df616ca001ef67a48e804f114cedc45faacffa02441621c58fe477b36135
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Zipkin
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/zipkin`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ OpenTracing Tracer implementation for Zipkin in Ruby
6
4
 
7
5
  ## Installation
8
6
 
@@ -12,17 +10,15 @@ Add this line to your application's Gemfile:
12
10
  gem 'zipkin'
13
11
  ```
14
12
 
15
- And then execute:
16
-
17
- $ bundle
18
-
19
- Or install it yourself as:
20
-
21
- $ gem install zipkin
22
-
23
13
  ## Usage
24
14
 
25
- TODO: Write usage instructions here
15
+ ```ruby
16
+ require 'zipkin/tracer'
17
+ OpenTracing.global_tracer = Zipkin::Tracer.build(url: 'http://localhost:9411', service_name: 'echo')
18
+
19
+ span = OpenTracing.start_span('span name')
20
+ span.finish
21
+ ```
26
22
 
27
23
  ## Development
28
24
 
@@ -32,7 +28,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
28
 
33
29
  ## Contributing
34
30
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/Indrek Juhkam/zipkin.
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/salemove/zipkin-ruby-opentracing
36
32
 
37
33
 
38
34
  ## License
@@ -0,0 +1,12 @@
1
+ module Zipkin
2
+ class Endpoint
3
+ LOCAL_IP = Socket.ip_address_list.detect(&:ipv4_private?).ip_address
4
+
5
+ def self.local_endpoint(service_name)
6
+ {
7
+ serviceName: service_name,
8
+ ipv4: LOCAL_IP
9
+ }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'sucker_punch'
4
+
5
+ module Zipkin
6
+ class JsonClient
7
+ def initialize(url)
8
+ @faraday = Faraday.new(url: url) do |faraday|
9
+ faraday.request :json
10
+ faraday.request :retry, max: 3, interval: 10, backoff_factor: 2
11
+ faraday.adapter Faraday.default_adapter
12
+ end
13
+ end
14
+
15
+ def send_span(payload)
16
+ SpanSender.perform_async(payload: payload, faraday: @faraday)
17
+ end
18
+
19
+ class SpanSender
20
+ include SuckerPunch::Job
21
+ workers 4
22
+
23
+ def perform(payload:, faraday:)
24
+ response = faraday.post '/api/v1/spans' do |req|
25
+ req.body = [payload]
26
+ end
27
+
28
+ if response.status != 202
29
+ STDERR.puts(response.body)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/zipkin/span.rb CHANGED
@@ -6,13 +6,18 @@ module Zipkin
6
6
 
7
7
  # Creates a new {Span}
8
8
  #
9
- # @param tracer [Tracer] the tracer that created this span
10
9
  # @param context [SpanContext] the context of the span
10
+ # @param context [String] the operation name
11
+ # @param client [Faraday] faraday instace for making http requests
11
12
  #
12
13
  # @return [Span] a new Span
13
- def initialize(tracer, context)
14
- @tracer = tracer
14
+ def initialize(context, operation_name, client, start_time: Time.now, tags: {}, local_endpoint:)
15
15
  @context = context
16
+ @operation_name = operation_name
17
+ @client = client
18
+ @start_time = start_time
19
+ @tags = tags
20
+ @local_endpoint = local_endpoint
16
21
  end
17
22
 
18
23
  # Set a tag value on this span
@@ -21,7 +26,7 @@ module Zipkin
21
26
  # @param value [String, Numeric, Boolean] the value of the tag. If it's not
22
27
  # a String, Numeric, or Boolean it will be encoded with to_s
23
28
  def set_tag(key, value)
24
- self
29
+ @tags = @tags.merge(key => value)
25
30
  end
26
31
 
27
32
  # Set a baggage item on the span
@@ -54,7 +59,40 @@ module Zipkin
54
59
  #
55
60
  # @param end_time [Time] custom end time, if not now
56
61
  def finish(end_time: Time.now)
57
- nil
62
+ finish_ts = (end_time.to_f * 1_000_000).to_i
63
+ start_ts = (@start_time.to_f * 1_000_000).to_i
64
+ duration = finish_ts - start_ts
65
+ is_server = ['server', 'consumer'].include?(@tags['span.kind'] || 'server')
66
+
67
+ @client.send_span(
68
+ traceId: @context.trace_id,
69
+ id: @context.span_id,
70
+ parentId: @context.parent_id,
71
+ name: @operation_name,
72
+ timestamp: start_ts,
73
+ duration: duration,
74
+ annotations: [
75
+ {
76
+ timestamp: start_ts,
77
+ value: is_server ? 'sr' : 'cs',
78
+ endpoint: @local_endpoint
79
+ },
80
+ {
81
+ timestamp: finish_ts,
82
+ value: is_server ? 'ss': 'cr',
83
+ endpoint: @local_endpoint
84
+ }
85
+ ],
86
+ binaryAnnotations: build_binary_annotations
87
+ )
88
+ end
89
+
90
+ private
91
+
92
+ def build_binary_annotations
93
+ @tags.map do |name, value|
94
+ {key: name, value: value.to_s}
95
+ end
58
96
  end
59
97
  end
60
98
  end
@@ -2,14 +2,14 @@ module Zipkin
2
2
  # SpanContext holds the data for a span that gets inherited to child spans
3
3
  class SpanContext
4
4
  def self.create_parent_context
5
+ trace_id = TraceId.generate
5
6
  span_id = TraceId.generate
6
- trace_id = span_id
7
- new(span_id: span_id, trace_id: trace_id)
7
+ new(trace_id: trace_id, span_id: span_id)
8
8
  end
9
9
 
10
- def self.create_from_parent(parent_span)
11
- trace_id = parent_span.context.trace_id
12
- parent_id = parent_span.context.span_id
10
+ def self.create_from_parent_context(span_context)
11
+ trace_id = span_context.trace_id
12
+ parent_id = span_context.span_id
13
13
  span_id = TraceId.generate
14
14
  new(span_id: span_id, parent_id: parent_id, trace_id: trace_id)
15
15
  end
@@ -3,7 +3,7 @@ module Zipkin
3
3
  TRACE_ID_UPPER_BOUND = 2 ** 64
4
4
 
5
5
  def self.generate
6
- rand(TRACE_ID_UPPER_BOUND)
6
+ rand(TRACE_ID_UPPER_BOUND).to_s(16)
7
7
  end
8
8
  end
9
9
  end
data/lib/zipkin/tracer.rb CHANGED
@@ -1,71 +1,96 @@
1
+ require 'opentracing'
2
+
3
+ require_relative 'span'
4
+ require_relative 'span_context'
5
+ require_relative 'carrier'
6
+ require_relative 'trace_id'
7
+ require_relative 'json_client'
8
+ require_relative 'endpoint'
9
+
1
10
  module Zipkin
2
11
  class Tracer
3
- def self.build(host:, port:, service_name:)
12
+ def self.build(url:, service_name:)
13
+ client = JsonClient.new(url)
14
+ new(client, service_name)
4
15
  end
5
16
 
6
- def initialize(client)
17
+ def initialize(client, service_name)
7
18
  @client = client
19
+ @local_endpoint = Endpoint.local_endpoint(service_name)
8
20
  end
9
21
 
10
- # Start a new span
22
+ # Starts a new span.
11
23
  #
12
- # @param operation_name [String]
13
- # The operation name for the Span
14
- # @param child_of [SpanContext]
15
- # SpanContext that acts as a parent to the newly-started Span. If a Span
16
- # instance is provided, its #context is automatically substituted.
17
- # @param start_time [Time]
18
- # The time when the Span started, if not now
19
- # @param tags [Hash]
20
- # Tags to assign to the Span at start time
24
+ # @param operation_name [String] The operation name for the Span
25
+ # @param child_of [SpanContext, Span] SpanContext that acts as a parent to
26
+ # the newly-started Span. If a Span instance is provided, its
27
+ # context is automatically substituted.
28
+ # @param start_time [Time] When the Span started, if not now
29
+ # @param tags [Hash] Tags to assign to the Span at start time
21
30
  #
22
- # @return [Span]
23
- # The newly-started Span
24
- def start_span(operation_name, child_of: nil, start_time: Time.now, tags: nil)
31
+ # @return [Span] The newly-started Span
32
+ def start_span(operation_name, child_of: nil, start_time: Time.now, tags: {}, **)
25
33
  context =
26
34
  if child_of
27
- SpanContext.create_from_parent(child_of)
35
+ parent_context = child_of.respond_to?(:context) ? child_of.context : child_of
36
+ SpanContext.create_from_parent_context(parent_context)
28
37
  else
29
38
  SpanContext.create_parent_context
30
39
  end
31
- span = Span.new(self, context)
32
- span.operation_name = operation_name
33
- span
40
+ Span.new(context, operation_name, @client, start_time: start_time, tags: tags, local_endpoint: @local_endpoint)
34
41
  end
35
42
 
36
43
  # Inject a SpanContext into the given carrier
37
44
  #
38
45
  # @param span_context [SpanContext]
39
46
  # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
40
- #
41
- # @param carrier [Carrier]
42
- # A carrier object of the type dictated by the specified `format`
47
+ # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
43
48
  def inject(span_context, format, carrier)
44
49
  case format
45
- when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK
46
- return nil
50
+ when OpenTracing::FORMAT_TEXT_MAP
51
+ carrier['trace-id'] = span_context.trace_id
52
+ carrier['parent-id'] = span_context.parent_id
53
+ carrier['span-id'] = span_context.span_id
54
+ when OpenTracing::FORMAT_RACK
55
+ carrier['X-Trace-Id'] = span_context.trace_id
56
+ carrier['X-Trace-Parent-Id'] = span_context.parent_id
57
+ carrier['X-Trace-Span-Id'] = span_context.span_id
47
58
  else
48
- warn 'Unknown inject format'
59
+ STDERR.puts "Logasm::Tracer with format #{format} is not supported yet"
49
60
  end
50
61
  end
51
62
 
52
63
  # Extract a SpanContext in the given format from the given carrier.
53
64
  #
54
65
  # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
55
- # @param carrier [Carrier]
56
- # A carrier object of the type dictated by the specified `format`
57
- #
58
- # @return [SpanContext]
59
- # the extracted SpanContext or nil if none could be found
66
+ # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
67
+ # @return [SpanContext] the extracted SpanContext or nil if none could be found
60
68
  def extract(format, carrier)
61
69
  case format
62
- when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK
63
- return SpanContext::NOOP_INSTANCE
70
+ when OpenTracing::FORMAT_TEXT_MAP
71
+ trace_id = carrier['trace-id']
72
+ parent_id = carrier['parent-id']
73
+ span_id = carrier['span-id']
74
+
75
+ if trace_id && span_id
76
+ SpanContext.new(trace_id: trace_id, parent_id: parent_id, span_id: span_id)
77
+ else
78
+ nil
79
+ end
80
+ when OpenTracing::FORMAT_RACK
81
+ trace_id = carrier['HTTP_X_TRACE_ID']
82
+ parent_id = carrier['HTTP_X_TRACE_PARENT_ID']
83
+ span_id = carrier['HTTP_X_TRACE_SPAN_ID']
84
+
85
+ if trace_id && span_id
86
+ SpanContext.new(trace_id: trace_id, parent_id: parent_id, span_id: span_id)
87
+ else
88
+ nil
89
+ end
64
90
  else
65
- warn 'Unknown extract format'
91
+ STDERR.puts "Logasm::Tracer with format #{format} is not supported yet"
66
92
  nil
67
93
  end
68
94
  end
69
-
70
95
  end
71
96
  end
data/lib/zipkin.rb CHANGED
@@ -1,8 +1,4 @@
1
1
  require_relative './zipkin/tracer'
2
- require_relative './zipkin/span'
3
- require_relative './zipkin/span_context'
4
- require_relative './zipkin/carrier'
5
- require_relative './zipkin/trace_id'
6
2
 
7
3
  module Zipkin
8
4
  end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler'
4
+ Bundler.setup
5
+
6
+ require 'zipkin/tracer'
7
+
8
+ url = ENV['ZIPKIN_URL'] || 'http://localhost:9411'
9
+
10
+ tracer1 = Zipkin::Tracer.build(url: url, service_name: 'test-service')
11
+ tracer2 = Zipkin::Tracer.build(url: url, service_name: 'downstream-service')
12
+
13
+ outer_span = tracer1.start_span('receive request', tags: {
14
+ 'span.kind' => 'server'
15
+ })
16
+ sleep 1
17
+
18
+ inner_span = tracer1.start_span('fetch info from downstream', child_of: outer_span, tags: {
19
+ 'span.kind' => 'client',
20
+ 'peer.service' => 'downstream-service',
21
+ 'peer.ipv4' => '6.6.6.6',
22
+ 'peer.port' => 443
23
+ })
24
+ sleep 0.3 # emulate network delay
25
+
26
+ downstream_span = tracer2.start_span('downstream operation', child_of: inner_span, tags: {
27
+ 'span.kind' => 'server'
28
+ })
29
+ sleep 0.5
30
+ downstream_span.finish
31
+
32
+ sleep 0.2 # emulate network delay
33
+
34
+ inner_span.finish
35
+
36
+ sleep 0.1 # doing something with fetched info
37
+ outer_span.finish
38
+
39
+ puts "Finishing..."
40
+ sleep 3
data/zipkin.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'zipkin'
7
- spec.version = '0.1.0'
7
+ spec.version = '0.2.0'
8
8
  spec.authors = ['SaleMove TechMovers']
9
9
  spec.email = ['techmovers@salemove.com']
10
10
 
@@ -24,4 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency 'rspec', '~> 3.0'
25
25
 
26
26
  spec.add_dependency 'opentracing', '~> 0.3'
27
+ spec.add_dependency 'faraday'
28
+ spec.add_dependency 'faraday_middleware'
29
+ spec.add_dependency 'sucker_punch', '~> 2.0'
27
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zipkin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SaleMove TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-04 00:00:00.000000000 Z
11
+ date: 2017-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,48 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday_middleware
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
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: sucker_punch
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.0'
69
111
  description: ''
70
112
  email:
71
113
  - techmovers@salemove.com
@@ -84,10 +126,13 @@ files:
84
126
  - bin/setup
85
127
  - lib/zipkin.rb
86
128
  - lib/zipkin/carrier.rb
129
+ - lib/zipkin/endpoint.rb
130
+ - lib/zipkin/json_client.rb
87
131
  - lib/zipkin/span.rb
88
132
  - lib/zipkin/span_context.rb
89
133
  - lib/zipkin/trace_id.rb
90
134
  - lib/zipkin/tracer.rb
135
+ - script/create_trace
91
136
  - zipkin.gemspec
92
137
  homepage: ''
93
138
  licenses: