zipkin 1.3.0 → 1.4.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: 4226e47ea8224eeffa7ed8cd4e48e61cc26da790
4
- data.tar.gz: f7ab917023ea03c1660d3f218b1e6f56147da8be
3
+ metadata.gz: 57c74dfca283ccf9531225d1765bd897a53dd527
4
+ data.tar.gz: e3ac03480369442405e7ffdbb7988e9fa7e32f16
5
5
  SHA512:
6
- metadata.gz: 7ad6f2ce25802dfd4fca0191a52ef6653887894571f2571663c6ccfa559a9f7241581acd7ceae158040e8056cf95c4016db83883b880077956e45caee9fca109
7
- data.tar.gz: 5165e5c4d02358d9a8a996baa398450975fb04d542e961464730cb1c58ec287fcf2a66676a1661311f4b4190f50d52f2f0df0dc6b4933fcab0642d79ab777132
6
+ metadata.gz: 981f0408f902b0a88f856eeefea27bee2032ab4712a63e499c2ebc001e286b351dd3d4209e2eb6ad176eeb880f4dac4d0e48010fbe135425a59bbc9e53d59644
7
+ data.tar.gz: 69e2ec0aa4e2c385c9e8944c8154714b2aa1f6744fef02a2b36ca5a391a8f55508a310680bad702c73bb86ed7633e192b877c9cd4ba84b68055917e248a9cb68
data/.rubocop.yml CHANGED
@@ -24,8 +24,20 @@ Metrics/MethodLength:
24
24
  Metrics/AbcSize:
25
25
  Enabled: no
26
26
 
27
+ Metrics/ClassLength:
28
+ Enabled: no
29
+
30
+ Metrics/ParameterLists:
31
+ Enabled: no
32
+
27
33
  Lint/UnusedMethodArgument:
28
34
  Enabled: no
29
35
 
36
+ Style/FrozenStringLiteralComment:
37
+ Enabled: yes
38
+ EnforcedStyle: always
39
+ Include:
40
+ - 'lib/**/*'
41
+
30
42
  Metrics/LineLength:
31
43
  Max: 120
data/README.md CHANGED
@@ -20,10 +20,17 @@ gem 'zipkin'
20
20
  require 'zipkin/tracer'
21
21
  OpenTracing.global_tracer = Zipkin::Tracer.build(url: 'http://localhost:9411', service_name: 'echo')
22
22
 
23
- span = OpenTracing.start_span('span name')
24
- span.finish
23
+ OpenTracing.start_active_span('span name') do
24
+ # do something
25
+
26
+ OpenTracing.start_active_span('inner span name') do
27
+ # do something else
28
+ end
29
+ end
25
30
  ```
26
31
 
32
+ See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more examples.
33
+
27
34
  ## Development
28
35
 
29
36
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/lib/zipkin.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './zipkin/tracer'
2
4
 
3
5
  module Zipkin
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  # Carriers are used for inject and extract operations. A carrier should be a
3
5
  # Hash or hash-like object. At a minimum, it should implement `[]`, `[]=`, and
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
 
3
5
  require_relative './collector/timestamp'
@@ -5,6 +7,13 @@ require_relative './collector/log_annotations'
5
7
 
6
8
  module Zipkin
7
9
  class Collector
10
+ OT_KIND_TO_ZIPKIN_KIND = {
11
+ 'server' => 'SERVER',
12
+ 'client' => 'CLIENT',
13
+ 'producer' => 'PRODUCER',
14
+ 'consumer' => 'CONSUMER'
15
+ }.freeze
16
+
8
17
  def initialize(local_endpoint)
9
18
  @buffer = Buffer.new
10
19
  @local_endpoint = local_endpoint
@@ -18,13 +27,14 @@ module Zipkin
18
27
  finish_ts = Timestamp.create(end_time)
19
28
  start_ts = Timestamp.create(span.start_time)
20
29
  duration = finish_ts - start_ts
30
+ return unless span.context.sampled?
21
31
 
22
32
  @buffer << {
23
33
  traceId: span.context.trace_id,
24
34
  id: span.context.span_id,
25
35
  parentId: span.context.parent_id,
26
36
  name: span.operation_name,
27
- kind: (span.tags['span.kind'] || 'SERVER').upcase,
37
+ kind: OT_KIND_TO_ZIPKIN_KIND[span.tags[:'span.kind'] || 'server'],
28
38
  timestamp: start_ts,
29
39
  duration: duration,
30
40
  debug: false,
@@ -32,16 +42,10 @@ module Zipkin
32
42
  localEndpoint: @local_endpoint,
33
43
  remoteEndpoint: Endpoint.remote_endpoint(span),
34
44
  annotations: LogAnnotations.build(span),
35
- tags: build_tags(span)
45
+ tags: span.tags
36
46
  }
37
47
  end
38
48
 
39
- private
40
-
41
- def build_tags(span)
42
- span.tags.map { |key, value| [key.to_s, value.to_s] }.to_h
43
- end
44
-
45
49
  class Buffer
46
50
  def initialize
47
51
  @buffer = []
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  class Collector
3
5
  module LogAnnotations
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  class Collector
3
5
  module Timestamp
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'socket'
2
4
 
3
5
  module Zipkin
@@ -15,10 +17,10 @@ module Zipkin
15
17
  end
16
18
 
17
19
  module PeerInfo
18
- SERVICE = 'peer.service'.freeze
19
- IPV4 = 'peer.ipv4'.freeze
20
- IPV6 = 'peer.ipv6'.freeze
21
- PORT = 'peer.port'.freeze
20
+ SERVICE = :'peer.service'
21
+ IPV4 = :'peer.ipv4'
22
+ IPV6 = :'peer.ipv6'
23
+ PORT = :'peer.port'
22
24
 
23
25
  def self.keys
24
26
  [SERVICE, IPV4, IPV6, PORT]
@@ -34,7 +36,7 @@ module Zipkin
34
36
 
35
37
  def self.remote_endpoint(span)
36
38
  tags = span.tags
37
- kind = tags['span.kind'] || SpanKind::SERVER
39
+ kind = tags[:'span.kind'] || SpanKind::SERVER
38
40
 
39
41
  case kind
40
42
  when SpanKind::SERVER, SpanKind::CLIENT
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'uri'
3
5
  require 'json'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zipkin
4
+ # Scope represents an OpenTracing Scope
5
+ #
6
+ # See http://www.opentracing.io for more information.
7
+ class Scope
8
+ def initialize(span, scope_stack, finish_on_close:)
9
+ @span = span
10
+ @scope_stack = scope_stack
11
+ @finish_on_close = finish_on_close
12
+ @closed = false
13
+ end
14
+
15
+ # Return the Span scoped by this Scope
16
+ #
17
+ # @return [Span]
18
+ attr_reader :span
19
+
20
+ # Close scope
21
+ #
22
+ # Mark the end of the active period for the current thread and Scope,
23
+ # updating the ScopeManager#active in the process.
24
+ def close
25
+ raise "Tried to close already closed span: #{inspect}" if @closed
26
+ @closed = true
27
+
28
+ @span.finish if @finish_on_close
29
+ removed_scope = @scope_stack.pop
30
+
31
+ if removed_scope != self # rubocop:disable Style/GuardClause
32
+ raise 'Removed non-active scope, ' \
33
+ "removed: #{removed_scope.inspect}, "\
34
+ "expected: #{inspect}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'scope_manager/scope_stack'
4
+ require_relative 'scope_manager/scope_identifier'
5
+
6
+ module Zipkin
7
+ # ScopeManager represents an OpenTracing ScopeManager
8
+ #
9
+ # See http://www.opentracing.io for more information.
10
+ #
11
+ # The ScopeManager interface abstracts both the activation of Span instances
12
+ # via ScopeManager#activate and access to an active Span/Scope via
13
+ # ScopeManager#active
14
+ #
15
+ class ScopeManager
16
+ def initialize
17
+ @scope_stack = ScopeStack.new
18
+ end
19
+
20
+ # Make a span instance active
21
+ #
22
+ # @param span [Span] the Span that should become active
23
+ # @param finish_on_close [Boolean] whether the Span should automatically be
24
+ # finished when Scope#close is called
25
+ # @return [Scope] instance to control the end of the active period for the
26
+ # Span. It is a programming error to neglect to call Scope#close on the
27
+ # returned instance.
28
+ def activate(span, finish_on_close: true)
29
+ return active if active && active.span == span
30
+ scope = Scope.new(span, @scope_stack, finish_on_close: finish_on_close)
31
+ @scope_stack.push(scope)
32
+ scope
33
+ end
34
+
35
+ # Return active scope
36
+ #
37
+ # If there is a non-null Scope, its wrapped Span becomes an implicit parent
38
+ # (as Reference#CHILD_OF) of any newly-created Span at
39
+ # Tracer#start_active_span or Tracer#start_span time.
40
+ #
41
+ # @return [Scope] the currently active Scope which can be used to access the
42
+ # currently active Span.
43
+ def active
44
+ @scope_stack.peek
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zipkin
4
+ class ScopeManager
5
+ # @api private
6
+ class ScopeIdentifier
7
+ def self.generate
8
+ # 65..90.chr are characters between A and Z
9
+ "opentracing_#{(0...8).map { rand(65..90).chr }.join}".to_sym
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zipkin
4
+ class ScopeManager
5
+ # @api private
6
+ class ScopeStack
7
+ def initialize
8
+ # Generate a random identifier to use as the Thread.current key. This is
9
+ # needed so that it would be possible to create multiple tracers in one
10
+ # thread (mostly useful for testing purposes)
11
+ @scope_identifier = ScopeIdentifier.generate
12
+ end
13
+
14
+ def push(scope)
15
+ store << scope
16
+ end
17
+
18
+ def pop
19
+ store.pop
20
+ end
21
+
22
+ def peek
23
+ store.last
24
+ end
25
+
26
+ private
27
+
28
+ def store
29
+ Thread.current[@scope_identifier] ||= []
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/zipkin/span.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  class Span
3
5
  attr_accessor :operation_name
@@ -26,7 +28,8 @@ module Zipkin
26
28
  # @param value [String, Numeric, Boolean] the value of the tag. If it's not
27
29
  # a String, Numeric, or Boolean it will be encoded with to_s
28
30
  def set_tag(key, value)
29
- @tags = @tags.merge(key => value)
31
+ sanitized_value = valid_tag_value?(value) ? value : value.to_s
32
+ @tags = @tags.merge(key.to_sym => sanitized_value)
30
33
  end
31
34
 
32
35
  # Set a baggage item on the span
@@ -69,5 +72,14 @@ module Zipkin
69
72
  def finish(end_time: Time.now)
70
73
  @collector.send_span(self, end_time)
71
74
  end
75
+
76
+ private
77
+
78
+ def valid_tag_value?(value)
79
+ value.is_a?(String) ||
80
+ value.is_a?(Numeric) ||
81
+ value.is_a?(TrueClass) ||
82
+ value.is_a?(FalseClass)
83
+ end
72
84
  end
73
85
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  # SpanContext holds the data for a span that gets inherited to child spans
3
5
  class SpanContext
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zipkin
2
4
  module TraceId
3
5
  TRACE_ID_UPPER_BOUND = 2**64
data/lib/zipkin/tracer.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'opentracing'
2
4
  require 'logger'
3
5
 
@@ -8,6 +10,8 @@ require_relative 'trace_id'
8
10
  require_relative 'json_client'
9
11
  require_relative 'endpoint'
10
12
  require_relative 'collector'
13
+ require_relative 'scope_manager'
14
+ require_relative 'scope'
11
15
 
12
16
  module Zipkin
13
17
  class Tracer
@@ -29,30 +33,50 @@ module Zipkin
29
33
  @collector = collector
30
34
  @sender = sender
31
35
  @logger = logger
36
+ @scope_manager = ScopeManager.new
32
37
  end
33
38
 
34
39
  def stop
35
40
  @sender.stop
36
41
  end
37
42
 
38
- # Starts a new span.
43
+ # @return [ScopeManager] the current ScopeManager, which may be a no-op but
44
+ # may not be nil.
45
+ attr_reader :scope_manager
46
+
47
+ # @return [Span, nil] the active span. This is a shorthand for
48
+ # `scope_manager.active.span`, and nil will be returned if
49
+ # Scope#active is nil.
50
+ def active_span
51
+ scope = scope_manager.active
52
+ scope.span if scope
53
+ end
54
+
55
+ # Starts a new span
56
+ #
57
+ # This is similar to #start_active_span, but the returned Span will not be
58
+ # registered via the ScopeManager.
39
59
  #
40
60
  # @param operation_name [String] The operation name for the Span
41
61
  # @param child_of [SpanContext, Span] SpanContext that acts as a parent to
42
- # the newly-started Span. If a Span instance is provided, its
43
- # context is automatically substituted.
62
+ # the newly-started Span. If a Span instance is provided, its
63
+ # context is automatically substituted.
44
64
  # @param start_time [Time] When the Span started, if not now
45
65
  # @param tags [Hash] Tags to assign to the Span at start time
66
+ # @param ignore_active_scope [Boolean] whether to create an implicit
67
+ # References#CHILD_OF reference to the ScopeManager#active.
46
68
  #
47
69
  # @return [Span] The newly-started Span
48
- def start_span(operation_name, child_of: nil, start_time: Time.now, tags: {}, **)
49
- context =
50
- if child_of
51
- parent_context = child_of.respond_to?(:context) ? child_of.context : child_of
52
- SpanContext.create_from_parent_context(parent_context)
53
- else
54
- SpanContext.create_parent_context
55
- end
70
+ def start_span(operation_name,
71
+ child_of: nil,
72
+ start_time: Time.now,
73
+ tags: {},
74
+ ignore_active_scope: false,
75
+ **)
76
+ context = prepare_span_context(
77
+ child_of: child_of,
78
+ ignore_active_scope: ignore_active_scope
79
+ )
56
80
  Span.new(
57
81
  context,
58
82
  operation_name,
@@ -62,6 +86,61 @@ module Zipkin
62
86
  )
63
87
  end
64
88
 
89
+ # Creates a newly started and activated Scope
90
+ #
91
+ # If the Tracer's ScopeManager#active is not nil, no explicit references
92
+ # are provided, and `ignore_active_scope` is false, then an inferred
93
+ # References#CHILD_OF reference is created to the ScopeManager#active's
94
+ # SpanContext when start_active is invoked.
95
+ #
96
+ # @param operation_name [String] The operation name for the Span
97
+ # @param child_of [SpanContext, Span] SpanContext that acts as a parent to
98
+ # the newly-started Span. If a Span instance is provided, its
99
+ # context is automatically substituted. See [Reference] for more
100
+ # information.
101
+ #
102
+ # If specified, the `references` parameter must be omitted.
103
+ # @param references [Array<Reference>] An array of reference
104
+ # objects that identify one or more parent SpanContexts.
105
+ # @param start_time [Time] When the Span started, if not now
106
+ # @param tags [Hash] Tags to assign to the Span at start time
107
+ # @param ignore_active_scope [Boolean] whether to create an implicit
108
+ # References#CHILD_OF reference to the ScopeManager#active.
109
+ # @param finish_on_close [Boolean] whether span should automatically be
110
+ # finished when Scope#close is called
111
+ # @yield [Scope] If an optional block is passed to start_active it will
112
+ # yield the newly-started Scope. If `finish_on_close` is true then the
113
+ # Span will be finished automatically after the block is executed.
114
+ # @return [Scope] The newly-started and activated Scope
115
+ def start_active_span(operation_name,
116
+ child_of: nil,
117
+ references: nil,
118
+ start_time: Time.now,
119
+ tags: nil,
120
+ ignore_active_scope: false,
121
+ finish_on_close: true,
122
+ **)
123
+ span = start_span(
124
+ operation_name,
125
+ child_of: child_of,
126
+ references: references,
127
+ start_time: start_time,
128
+ tags: tags,
129
+ ignore_active_scope: ignore_active_scope
130
+ )
131
+ scope = @scope_manager.activate(span, finish_on_close: finish_on_close)
132
+
133
+ if block_given?
134
+ begin
135
+ yield scope
136
+ ensure
137
+ scope.close
138
+ end
139
+ end
140
+
141
+ scope
142
+ end
143
+
65
144
  # Inject a SpanContext into the given carrier
66
145
  #
67
146
  # @param span_context [SpanContext]
@@ -123,5 +202,21 @@ module Zipkin
123
202
  sampled: sampled
124
203
  )
125
204
  end
205
+
206
+ def prepare_span_context(child_of:, ignore_active_scope:)
207
+ if child_of
208
+ parent_context = child_of.respond_to?(:context) ? child_of.context : child_of
209
+ return SpanContext.create_from_parent_context(parent_context)
210
+ end
211
+
212
+ unless ignore_active_scope
213
+ active_scope = @scope_manager.active
214
+ if active_scope
215
+ return SpanContext.create_from_parent_context(active_scope.span.context)
216
+ end
217
+ end
218
+
219
+ SpanContext.create_parent_context
220
+ end
126
221
  end
127
222
  end
data/zipkin.gemspec CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = 'zipkin'
6
- spec.version = '1.3.0'
6
+ spec.version = '1.4.0'
7
7
  spec.authors = ['SaleMove TechMovers']
8
8
  spec.email = ['techmovers@salemove.com']
9
9
 
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: 1.3.0
4
+ version: 1.4.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: 2018-05-09 00:00:00.000000000 Z
11
+ date: 2018-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -132,6 +132,10 @@ files:
132
132
  - lib/zipkin/collector/timestamp.rb
133
133
  - lib/zipkin/endpoint.rb
134
134
  - lib/zipkin/json_client.rb
135
+ - lib/zipkin/scope.rb
136
+ - lib/zipkin/scope_manager.rb
137
+ - lib/zipkin/scope_manager/scope_identifier.rb
138
+ - lib/zipkin/scope_manager/scope_stack.rb
135
139
  - lib/zipkin/span.rb
136
140
  - lib/zipkin/span_context.rb
137
141
  - lib/zipkin/trace_id.rb