zipkin 1.3.0 → 1.4.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: 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