zipkin 1.6.0 → 1.6.1
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 +5 -5
- data/lib/zipkin/async_reporter.rb +39 -0
- data/lib/zipkin/async_reporter/buffer.rb +27 -0
- data/lib/zipkin/encoders.rb +3 -0
- data/lib/zipkin/encoders/json_encoder.rb +104 -0
- data/lib/zipkin/encoders/json_encoder/log_annotations.rb +34 -0
- data/lib/zipkin/encoders/json_encoder/timestamp.rb +13 -0
- data/lib/zipkin/endpoint.rb +19 -15
- data/lib/zipkin/{json_client.rb → http_client.rb} +6 -26
- data/lib/zipkin/span.rb +7 -6
- data/lib/zipkin/tracer.rb +12 -19
- data/script/create_follows_from_trace +3 -5
- data/script/create_http_trace +56 -0
- data/script/create_trace +34 -20
- data/zipkin.gemspec +1 -1
- metadata +11 -7
- data/lib/zipkin/collector.rb +0 -71
- data/lib/zipkin/collector/log_annotations.rb +0 -27
- data/lib/zipkin/collector/timestamp.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3b88fff10737cc10e0da917018436f4e0085e2f8bf384605fec56e84450595d3
|
4
|
+
data.tar.gz: 51ca7b5a0e4b1fca2a9eeeb02f73c9d139fe8cfaf78165850951cbb4d59bab09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c68750c7f6758f4d81d9efd045e040b30afcc36e0679c5f0f12b8623a69f2bdc7fec0ca58ee56bbd1080f710e6449e601b3a5e486e45ea6892aaf1fce942f51
|
7
|
+
data.tar.gz: 52a89cb097adfa8ff282ae95d10a22c2c799782ad13fb356769ef2e8f66830390c2e7e18280dc8bb1de969490d090fb98a2542721a11c8d9901f910b8a5e0bae
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
require_relative './async_reporter/buffer'
|
6
|
+
|
7
|
+
module Zipkin
|
8
|
+
class AsyncReporter
|
9
|
+
def self.create(sender:, flush_interval:)
|
10
|
+
reporter = new(sender)
|
11
|
+
|
12
|
+
# start flush thread
|
13
|
+
Thread.new do
|
14
|
+
loop do
|
15
|
+
reporter.flush
|
16
|
+
sleep(flush_interval)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
reporter
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(sender)
|
24
|
+
@sender = sender
|
25
|
+
@buffer = Buffer.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def flush
|
29
|
+
spans = @buffer.retrieve
|
30
|
+
@sender.send_spans(spans) if spans.any?
|
31
|
+
spans
|
32
|
+
end
|
33
|
+
|
34
|
+
def report(span)
|
35
|
+
return unless span.context.sampled?
|
36
|
+
@buffer << span
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zipkin
|
4
|
+
class AsyncReporter
|
5
|
+
class Buffer
|
6
|
+
def initialize
|
7
|
+
@buffer = []
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(element)
|
12
|
+
@mutex.synchronize do
|
13
|
+
@buffer << element
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def retrieve
|
19
|
+
@mutex.synchronize do
|
20
|
+
elements = @buffer.dup
|
21
|
+
@buffer.clear
|
22
|
+
elements
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative 'json_encoder/timestamp'
|
6
|
+
require_relative 'json_encoder/log_annotations'
|
7
|
+
|
8
|
+
module Zipkin
|
9
|
+
module Encoders
|
10
|
+
class JsonEncoder
|
11
|
+
OT_KIND_TO_ZIPKIN_KIND = {
|
12
|
+
'server' => 'SERVER',
|
13
|
+
'client' => 'CLIENT',
|
14
|
+
'producer' => 'PRODUCER',
|
15
|
+
'consumer' => 'CONSUMER'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
CONTENT_TYPE = 'application/json'.freeze
|
19
|
+
|
20
|
+
module Fields
|
21
|
+
TRACE_ID = 'traceId'.freeze
|
22
|
+
SPAN_ID = 'id'.freeze
|
23
|
+
PARENT_ID = 'parentId'.freeze
|
24
|
+
OPERATION_NAME = 'name'.freeze
|
25
|
+
KIND = 'kind'.freeze
|
26
|
+
TIMESTAMP = 'timestamp'.freeze
|
27
|
+
DURATION = 'duration'.freeze
|
28
|
+
DEBUG = 'debug'.freeze
|
29
|
+
SHARED = 'shared'.freeze
|
30
|
+
LOCAL_ENDPOINT = 'localEndpoint'.freeze
|
31
|
+
REMOTE_ENDPOINT = 'remoteEndpoint'.freeze
|
32
|
+
ANNOTATIONS = 'annotations'.freeze
|
33
|
+
TAGS = 'tags'.freeze
|
34
|
+
|
35
|
+
module Endpoint
|
36
|
+
SERVICE_NAME = 'serviceName'.freeze
|
37
|
+
IPV4 = 'ipv4'.freeze
|
38
|
+
IPV6 = 'ipv6'.freeze
|
39
|
+
PORT = 'port'.freeze
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(local_endpoint)
|
44
|
+
@adapter = defined?(Oj) ? OjAdapter : JsonAdapter
|
45
|
+
@local_endpoint = serialize_endpoint(local_endpoint)
|
46
|
+
end
|
47
|
+
|
48
|
+
def content_type
|
49
|
+
CONTENT_TYPE
|
50
|
+
end
|
51
|
+
|
52
|
+
def encode(spans)
|
53
|
+
@adapter.dump(spans.map(&method(:serialize)))
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def serialize(span)
|
59
|
+
finish_ts = Timestamp.create(span.end_time)
|
60
|
+
start_ts = Timestamp.create(span.start_time)
|
61
|
+
duration = finish_ts - start_ts
|
62
|
+
|
63
|
+
{
|
64
|
+
Fields::TRACE_ID => span.context.trace_id,
|
65
|
+
Fields::SPAN_ID => span.context.span_id,
|
66
|
+
Fields::PARENT_ID => span.context.parent_id,
|
67
|
+
Fields::OPERATION_NAME => span.operation_name,
|
68
|
+
Fields::KIND => OT_KIND_TO_ZIPKIN_KIND[span.tags[:'span.kind'] || 'server'],
|
69
|
+
Fields::TIMESTAMP => start_ts,
|
70
|
+
Fields::DURATION => duration,
|
71
|
+
Fields::DEBUG => false,
|
72
|
+
Fields::SHARED => false,
|
73
|
+
Fields::LOCAL_ENDPOINT => @local_endpoint,
|
74
|
+
Fields::REMOTE_ENDPOINT => serialize_endpoint(Endpoint.remote_endpoint(span)),
|
75
|
+
Fields::ANNOTATIONS => LogAnnotations.build(span),
|
76
|
+
Fields::TAGS => span.tags
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def serialize_endpoint(endpoint)
|
81
|
+
return nil unless endpoint
|
82
|
+
|
83
|
+
{
|
84
|
+
Fields::Endpoint::SERVICE_NAME => endpoint.service_name,
|
85
|
+
Fields::Endpoint::IPV4 => endpoint.ipv4,
|
86
|
+
Fields::Endpoint::IPV6 => endpoint.ipv6,
|
87
|
+
Fields::Endpoint::PORT => endpoint.port
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
module OjAdapter
|
92
|
+
def self.dump(payload)
|
93
|
+
Oj.dump(payload, mode: :object)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module JsonAdapter
|
98
|
+
def self.dump(payload)
|
99
|
+
JSON.dump(payload)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zipkin
|
4
|
+
module Encoders
|
5
|
+
class JsonEncoder
|
6
|
+
module LogAnnotations
|
7
|
+
module Fields
|
8
|
+
TIMESTAMP = 'timestamp'.freeze
|
9
|
+
VALUE = 'value'.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.build(span)
|
13
|
+
span.logs.map do |log|
|
14
|
+
{
|
15
|
+
Fields::TIMESTAMP => Timestamp.create(log.fetch(:timestamp)),
|
16
|
+
Fields::VALUE => format_log_value(log)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.format_log_value(log)
|
22
|
+
if log.keys == %i[event timestamp]
|
23
|
+
log.fetch(:event)
|
24
|
+
else
|
25
|
+
log
|
26
|
+
.reject { |key, _value| key == :timestamp }
|
27
|
+
.map { |key, value| "#{key}=#{value}" }
|
28
|
+
.join(' ')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/zipkin/endpoint.rb
CHANGED
@@ -17,10 +17,10 @@ module Zipkin
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module PeerInfo
|
20
|
-
SERVICE =
|
21
|
-
IPV4 =
|
22
|
-
IPV6 =
|
23
|
-
PORT =
|
20
|
+
SERVICE = 'peer.service'.freeze
|
21
|
+
IPV4 = 'peer.ipv4'.freeze
|
22
|
+
IPV6 = 'peer.ipv6'.freeze
|
23
|
+
PORT = 'peer.port'.freeze
|
24
24
|
|
25
25
|
def self.keys
|
26
26
|
[SERVICE, IPV4, IPV6, PORT]
|
@@ -28,34 +28,38 @@ module Zipkin
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.local_endpoint(service_name)
|
31
|
-
|
32
|
-
serviceName: service_name,
|
33
|
-
ipv4: LOCAL_IP
|
34
|
-
}
|
31
|
+
new(service_name: service_name, ipv4: LOCAL_IP)
|
35
32
|
end
|
36
33
|
|
37
34
|
def self.remote_endpoint(span)
|
38
35
|
tags = span.tags
|
39
|
-
kind = tags[
|
36
|
+
kind = tags['span.kind'] || SpanKind::SERVER
|
40
37
|
|
41
38
|
case kind
|
42
39
|
when SpanKind::SERVER, SpanKind::CLIENT
|
43
40
|
return nil if (tags.keys & PeerInfo.keys).empty?
|
44
41
|
|
45
|
-
|
46
|
-
|
42
|
+
new(
|
43
|
+
service_name: tags[PeerInfo::SERVICE],
|
47
44
|
ipv4: tags[PeerInfo::IPV4],
|
48
45
|
ipv6: tags[PeerInfo::IPV6],
|
49
46
|
port: tags[PeerInfo::PORT]
|
50
|
-
|
47
|
+
)
|
51
48
|
when SpanKind::PRODUCER, SpanKind::CONSUMER
|
52
|
-
|
53
|
-
serviceName: 'broker'
|
54
|
-
}
|
49
|
+
new(service_name: 'broker')
|
55
50
|
else
|
56
51
|
warn "Unkown span kind: #{kind}"
|
57
52
|
nil
|
58
53
|
end
|
59
54
|
end
|
55
|
+
|
56
|
+
def initialize(service_name: nil, ipv4: nil, ipv6: nil, port: nil)
|
57
|
+
@service_name = service_name
|
58
|
+
@ipv4 = ipv4
|
59
|
+
@ipv6 = ipv6
|
60
|
+
@port = port
|
61
|
+
end
|
62
|
+
|
63
|
+
attr_reader :service_name, :ipv4, :ipv6, :port
|
60
64
|
end
|
61
65
|
end
|
@@ -2,43 +2,23 @@
|
|
2
2
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'uri'
|
5
|
-
require 'json'
|
6
5
|
|
7
6
|
module Zipkin
|
8
|
-
class
|
9
|
-
def initialize(url:,
|
10
|
-
@
|
11
|
-
@flush_interval = flush_interval
|
7
|
+
class HTTPClient
|
8
|
+
def initialize(url:, encoder:, logger:)
|
9
|
+
@encoder = encoder
|
12
10
|
@spans_uri = URI.parse("#{url}/api/v2/spans")
|
13
11
|
@logger = logger
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
@thread = Thread.new do
|
18
|
-
loop do
|
19
|
-
emit_batch(@collector.retrieve)
|
20
|
-
sleep @flush_interval
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def stop
|
26
|
-
@thread.terminate if @thread
|
27
|
-
emit_batch(@collector.retrieve)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def emit_batch(spans)
|
33
|
-
return if spans.empty?
|
34
|
-
|
14
|
+
def send_spans(spans)
|
35
15
|
http = Net::HTTP.new(@spans_uri.host, @spans_uri.port)
|
36
16
|
http.use_ssl = @spans_uri.scheme == 'https'
|
37
17
|
request = Net::HTTP::Post.new(
|
38
18
|
@spans_uri.request_uri,
|
39
|
-
'Content-Type' =>
|
19
|
+
'Content-Type' => @encoder.content_type
|
40
20
|
)
|
41
|
-
request.body =
|
21
|
+
request.body = @encoder.encode(spans)
|
42
22
|
response = http.request(request)
|
43
23
|
|
44
24
|
if response.code != '202'
|
data/lib/zipkin/span.rb
CHANGED
@@ -4,26 +4,26 @@ module Zipkin
|
|
4
4
|
class Span
|
5
5
|
attr_accessor :operation_name
|
6
6
|
|
7
|
-
attr_reader :context, :start_time, :tags, :logs, :references
|
7
|
+
attr_reader :context, :start_time, :end_time, :tags, :logs, :references
|
8
8
|
|
9
9
|
# Creates a new {Span}
|
10
10
|
#
|
11
11
|
# @param context [SpanContext] the context of the span
|
12
12
|
# @param operation_name [String] the operation name
|
13
|
-
# @param
|
13
|
+
# @param reporter [#report] the span reporter
|
14
14
|
#
|
15
15
|
# @return [Span] a new Span
|
16
16
|
def initialize(
|
17
17
|
context,
|
18
18
|
operation_name,
|
19
|
-
|
19
|
+
reporter,
|
20
20
|
start_time: Time.now,
|
21
21
|
tags: {},
|
22
22
|
references: nil
|
23
23
|
)
|
24
24
|
@context = context
|
25
25
|
@operation_name = operation_name
|
26
|
-
@
|
26
|
+
@reporter = reporter
|
27
27
|
@start_time = start_time
|
28
28
|
@tags = {}
|
29
29
|
@logs = []
|
@@ -39,7 +39,7 @@ module Zipkin
|
|
39
39
|
# a String, Numeric, or Boolean it will be encoded with to_s
|
40
40
|
def set_tag(key, value)
|
41
41
|
sanitized_value = valid_tag_value?(value) ? value : value.to_s
|
42
|
-
@tags = @tags.merge(key.
|
42
|
+
@tags = @tags.merge(key.to_s => sanitized_value)
|
43
43
|
end
|
44
44
|
|
45
45
|
# Set a baggage item on the span
|
@@ -80,7 +80,8 @@ module Zipkin
|
|
80
80
|
#
|
81
81
|
# @param end_time [Time] custom end time, if not now
|
82
82
|
def finish(end_time: Time.now)
|
83
|
-
@
|
83
|
+
@end_time = end_time
|
84
|
+
@reporter.report(self)
|
84
85
|
end
|
85
86
|
|
86
87
|
private
|
data/lib/zipkin/tracer.rb
CHANGED
@@ -7,12 +7,13 @@ require_relative 'span'
|
|
7
7
|
require_relative 'span_context'
|
8
8
|
require_relative 'carrier'
|
9
9
|
require_relative 'trace_id'
|
10
|
-
require_relative '
|
10
|
+
require_relative 'http_client'
|
11
11
|
require_relative 'endpoint'
|
12
|
-
require_relative '
|
12
|
+
require_relative 'async_reporter'
|
13
13
|
require_relative 'scope_manager'
|
14
14
|
require_relative 'scope'
|
15
15
|
require_relative 'samplers'
|
16
|
+
require_relative 'encoders'
|
16
17
|
|
17
18
|
module Zipkin
|
18
19
|
class Tracer
|
@@ -22,30 +23,22 @@ module Zipkin
|
|
22
23
|
service_name:,
|
23
24
|
flush_interval: DEFAULT_FLUSH_INTERVAL,
|
24
25
|
logger: Logger.new(STDOUT),
|
25
|
-
sampler: Samplers::Const.new(true)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
logger: logger
|
32
|
-
)
|
33
|
-
sender.start
|
34
|
-
new(collector, sender, logger: logger, sampler: sampler)
|
26
|
+
sampler: Samplers::Const.new(true),
|
27
|
+
encoder: Encoders::JsonEncoder)
|
28
|
+
encoder = encoder.new(Endpoint.local_endpoint(service_name))
|
29
|
+
sender = HTTPClient.new(url: url, encoder: encoder, logger: logger)
|
30
|
+
reporter = AsyncReporter.create(sender: sender, flush_interval: flush_interval)
|
31
|
+
new(reporter, sender, logger: logger, sampler: sampler)
|
35
32
|
end
|
36
33
|
|
37
|
-
def initialize(
|
38
|
-
@
|
34
|
+
def initialize(reporter, sender, logger: Logger.new(STDOUT), sampler:)
|
35
|
+
@reporter = reporter
|
39
36
|
@sender = sender
|
40
37
|
@logger = logger
|
41
38
|
@scope_manager = ScopeManager.new
|
42
39
|
@sampler = sampler
|
43
40
|
end
|
44
41
|
|
45
|
-
def stop
|
46
|
-
@sender.stop
|
47
|
-
end
|
48
|
-
|
49
42
|
# @return [ScopeManager] the current ScopeManager, which may be a no-op but
|
50
43
|
# may not be nil.
|
51
44
|
attr_reader :scope_manager
|
@@ -93,7 +86,7 @@ module Zipkin
|
|
93
86
|
Span.new(
|
94
87
|
context,
|
95
88
|
operation_name,
|
96
|
-
@
|
89
|
+
@reporter,
|
97
90
|
start_time: start_time,
|
98
91
|
references: references,
|
99
92
|
tags: tags || {}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'bundler'
|
4
5
|
Bundler.setup
|
@@ -7,8 +8,8 @@ require 'zipkin/tracer'
|
|
7
8
|
|
8
9
|
url = ENV['ZIPKIN_URL'] || 'http://localhost:9411'
|
9
10
|
|
10
|
-
tracer1 = Zipkin::Tracer.build(url: url, service_name: 'test-service')
|
11
|
-
tracer2 = Zipkin::Tracer.build(url: url, service_name: 'downstream-service')
|
11
|
+
tracer1 = Zipkin::Tracer.build(url: url, service_name: 'test-service', flush_interval: 1)
|
12
|
+
tracer2 = Zipkin::Tracer.build(url: url, service_name: 'downstream-service', flush_interval: 1)
|
12
13
|
|
13
14
|
rpc_span = tracer1.start_span(
|
14
15
|
'receive request',
|
@@ -45,7 +46,4 @@ async_span = tracer2.start_span(
|
|
45
46
|
sleep 0.3 # emulate network delay
|
46
47
|
async_span.finish
|
47
48
|
|
48
|
-
tracer1.stop
|
49
|
-
tracer2.stop
|
50
|
-
|
51
49
|
puts 'Finished'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
require 'zipkin/tracer'
|
8
|
+
|
9
|
+
url = ENV['ZIPKIN_URL'] || 'http://localhost:9411'
|
10
|
+
|
11
|
+
tracer1 = Zipkin::Tracer.build(url: url, service_name: 'user-service', flush_interval: 1)
|
12
|
+
tracer2 = Zipkin::Tracer.build(url: url, service_name: 'name-service', flush_interval: 1)
|
13
|
+
|
14
|
+
root_span = tracer1.start_span(
|
15
|
+
'GET /users/:id',
|
16
|
+
tags: {
|
17
|
+
'span.kind' => 'server',
|
18
|
+
'http.method' => 'get',
|
19
|
+
'http.url' => 'http://example.com/users/5'
|
20
|
+
}
|
21
|
+
)
|
22
|
+
sleep 1
|
23
|
+
|
24
|
+
fetch_name_span = tracer1.start_span(
|
25
|
+
'get',
|
26
|
+
child_of: root_span,
|
27
|
+
tags: {
|
28
|
+
'span.kind' => 'client',
|
29
|
+
'http.method' => 'get',
|
30
|
+
'http.url' => 'GET /users/5/name'
|
31
|
+
}
|
32
|
+
)
|
33
|
+
sleep 0.3 # emulate network delay
|
34
|
+
|
35
|
+
name_service_span = tracer2.start_span(
|
36
|
+
'GET /users/:id/name',
|
37
|
+
child_of: fetch_name_span,
|
38
|
+
tags: {
|
39
|
+
'span.kind' => 'server',
|
40
|
+
'http.method' => 'get',
|
41
|
+
'http.url' => 'http://example.com/users/5/name'
|
42
|
+
}
|
43
|
+
)
|
44
|
+
sleep 0.5
|
45
|
+
name_service_span.finish
|
46
|
+
|
47
|
+
sleep 0.2 # emulate network delay
|
48
|
+
fetch_name_span.finish
|
49
|
+
|
50
|
+
sleep 0.1 # doing something with fetched info
|
51
|
+
root_span.finish
|
52
|
+
|
53
|
+
puts 'Finishing...'
|
54
|
+
sleep 3
|
55
|
+
|
56
|
+
puts 'Finished'
|
data/script/create_trace
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'bundler'
|
4
5
|
Bundler.setup
|
@@ -7,10 +8,10 @@ require 'zipkin/tracer'
|
|
7
8
|
|
8
9
|
url = ENV['ZIPKIN_URL'] || 'http://localhost:9411'
|
9
10
|
|
10
|
-
tracer1 = Zipkin::Tracer.build(url: url, service_name: 'test-service')
|
11
|
-
tracer2 = Zipkin::Tracer.build(url: url, service_name: 'downstream-service')
|
11
|
+
tracer1 = Zipkin::Tracer.build(url: url, service_name: 'test-service', flush_interval: 1)
|
12
|
+
tracer2 = Zipkin::Tracer.build(url: url, service_name: 'downstream-service-1', flush_interval: 1)
|
12
13
|
|
13
|
-
|
14
|
+
root_span = tracer1.start_span(
|
14
15
|
'receive request',
|
15
16
|
tags: {
|
16
17
|
'span.kind' => 'server'
|
@@ -18,39 +19,52 @@ outer_span = tracer1.start_span(
|
|
18
19
|
)
|
19
20
|
sleep 1
|
20
21
|
|
21
|
-
|
22
|
-
'fetch info from
|
23
|
-
child_of:
|
22
|
+
fetch_info_from_service1_span = tracer1.start_span(
|
23
|
+
'fetch info from service 1',
|
24
|
+
child_of: root_span,
|
24
25
|
tags: {
|
25
26
|
'span.kind' => 'client',
|
26
|
-
'peer.
|
27
|
-
'peer.ipv4' => '6.6.6.6',
|
27
|
+
'peer.ipv4' => '2.2.2.2',
|
28
28
|
'peer.port' => 443
|
29
29
|
}
|
30
30
|
)
|
31
31
|
sleep 0.3 # emulate network delay
|
32
32
|
|
33
|
-
|
34
|
-
'
|
35
|
-
child_of:
|
36
|
-
tags: {
|
33
|
+
service1_span = tracer2.start_span(
|
34
|
+
'service 1 operation',
|
35
|
+
child_of: fetch_info_from_service1_span,
|
36
|
+
tags: {
|
37
|
+
'span.kind' => 'server',
|
38
|
+
'peer.ipv4' => '1.1.1.1',
|
39
|
+
'peer.port' => 443
|
40
|
+
}
|
37
41
|
)
|
38
|
-
|
39
|
-
|
42
|
+
service1_span.log_kv(event: 'custom-event')
|
43
|
+
service1_span.log_kv(foo: 'bar', baz: 'buz')
|
40
44
|
sleep 0.5
|
41
|
-
|
45
|
+
service1_span.finish
|
42
46
|
|
43
47
|
sleep 0.2 # emulate network delay
|
44
48
|
|
45
|
-
|
49
|
+
fetch_info_from_service1_span.finish
|
50
|
+
|
51
|
+
fetch_info_from_service2_span = tracer1.start_span(
|
52
|
+
'fetch info from service 2 which does not have tracing',
|
53
|
+
child_of: root_span,
|
54
|
+
tags: {
|
55
|
+
'span.kind' => 'client',
|
56
|
+
'peer.service' => 'downstream-service-2',
|
57
|
+
'peer.ipv4' => '3.3.3.3',
|
58
|
+
'peer.port' => 443
|
59
|
+
}
|
60
|
+
)
|
61
|
+
sleep 0.3 # emulate network delay
|
62
|
+
fetch_info_from_service2_span.finish
|
46
63
|
|
47
64
|
sleep 0.1 # doing something with fetched info
|
48
|
-
|
65
|
+
root_span.finish
|
49
66
|
|
50
67
|
puts 'Finishing...'
|
51
68
|
sleep 3
|
52
69
|
|
53
|
-
tracer1.stop
|
54
|
-
tracer2.stop
|
55
|
-
|
56
70
|
puts 'Finished'
|
data/zipkin.gemspec
CHANGED
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.6.
|
4
|
+
version: 1.6.1
|
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-
|
11
|
+
date: 2018-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -126,12 +126,15 @@ files:
|
|
126
126
|
- bin/console
|
127
127
|
- bin/setup
|
128
128
|
- lib/zipkin.rb
|
129
|
+
- lib/zipkin/async_reporter.rb
|
130
|
+
- lib/zipkin/async_reporter/buffer.rb
|
129
131
|
- lib/zipkin/carrier.rb
|
130
|
-
- lib/zipkin/
|
131
|
-
- lib/zipkin/
|
132
|
-
- lib/zipkin/
|
132
|
+
- lib/zipkin/encoders.rb
|
133
|
+
- lib/zipkin/encoders/json_encoder.rb
|
134
|
+
- lib/zipkin/encoders/json_encoder/log_annotations.rb
|
135
|
+
- lib/zipkin/encoders/json_encoder/timestamp.rb
|
133
136
|
- lib/zipkin/endpoint.rb
|
134
|
-
- lib/zipkin/
|
137
|
+
- lib/zipkin/http_client.rb
|
135
138
|
- lib/zipkin/samplers.rb
|
136
139
|
- lib/zipkin/samplers/const.rb
|
137
140
|
- lib/zipkin/samplers/probabilistic.rb
|
@@ -144,6 +147,7 @@ files:
|
|
144
147
|
- lib/zipkin/trace_id.rb
|
145
148
|
- lib/zipkin/tracer.rb
|
146
149
|
- script/create_follows_from_trace
|
150
|
+
- script/create_http_trace
|
147
151
|
- script/create_trace
|
148
152
|
- zipkin.gemspec
|
149
153
|
homepage: ''
|
@@ -166,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
170
|
version: '0'
|
167
171
|
requirements: []
|
168
172
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.6
|
173
|
+
rubygems_version: 2.7.6
|
170
174
|
signing_key:
|
171
175
|
specification_version: 4
|
172
176
|
summary: OpenTracing Tracer implementation for Zipkin in Ruby
|
data/lib/zipkin/collector.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'thread'
|
4
|
-
|
5
|
-
require_relative './collector/timestamp'
|
6
|
-
require_relative './collector/log_annotations'
|
7
|
-
|
8
|
-
module Zipkin
|
9
|
-
class Collector
|
10
|
-
OT_KIND_TO_ZIPKIN_KIND = {
|
11
|
-
'server' => 'SERVER',
|
12
|
-
'client' => 'CLIENT',
|
13
|
-
'producer' => 'PRODUCER',
|
14
|
-
'consumer' => 'CONSUMER'
|
15
|
-
}.freeze
|
16
|
-
|
17
|
-
def initialize(local_endpoint)
|
18
|
-
@buffer = Buffer.new
|
19
|
-
@local_endpoint = local_endpoint
|
20
|
-
end
|
21
|
-
|
22
|
-
def retrieve
|
23
|
-
@buffer.retrieve
|
24
|
-
end
|
25
|
-
|
26
|
-
def send_span(span, end_time)
|
27
|
-
finish_ts = Timestamp.create(end_time)
|
28
|
-
start_ts = Timestamp.create(span.start_time)
|
29
|
-
duration = finish_ts - start_ts
|
30
|
-
return unless span.context.sampled?
|
31
|
-
|
32
|
-
@buffer << {
|
33
|
-
traceId: span.context.trace_id,
|
34
|
-
id: span.context.span_id,
|
35
|
-
parentId: span.context.parent_id,
|
36
|
-
name: span.operation_name,
|
37
|
-
kind: OT_KIND_TO_ZIPKIN_KIND[span.tags[:'span.kind'] || 'server'],
|
38
|
-
timestamp: start_ts,
|
39
|
-
duration: duration,
|
40
|
-
debug: false,
|
41
|
-
shared: false,
|
42
|
-
localEndpoint: @local_endpoint,
|
43
|
-
remoteEndpoint: Endpoint.remote_endpoint(span),
|
44
|
-
annotations: LogAnnotations.build(span),
|
45
|
-
tags: span.tags
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
class Buffer
|
50
|
-
def initialize
|
51
|
-
@buffer = []
|
52
|
-
@mutex = Mutex.new
|
53
|
-
end
|
54
|
-
|
55
|
-
def <<(element)
|
56
|
-
@mutex.synchronize do
|
57
|
-
@buffer << element
|
58
|
-
true
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def retrieve
|
63
|
-
@mutex.synchronize do
|
64
|
-
elements = @buffer.dup
|
65
|
-
@buffer.clear
|
66
|
-
elements
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Zipkin
|
4
|
-
class Collector
|
5
|
-
module LogAnnotations
|
6
|
-
def self.build(span)
|
7
|
-
span.logs.map do |log|
|
8
|
-
{
|
9
|
-
timestamp: Timestamp.create(log.fetch(:timestamp)),
|
10
|
-
value: format_log_value(log)
|
11
|
-
}
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.format_log_value(log)
|
16
|
-
if log.keys == %i[event timestamp]
|
17
|
-
log.fetch(:event)
|
18
|
-
else
|
19
|
-
log
|
20
|
-
.reject { |key, _value| key == :timestamp }
|
21
|
-
.map { |key, value| "#{key}=#{value}" }
|
22
|
-
.join(' ')
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|