freddy-jruby 1.0.0 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/Gemfile +1 -0
- data/README.md +35 -0
- data/freddy.gemspec +2 -1
- data/lib/freddy.rb +11 -3
- data/lib/freddy/consumers.rb +0 -13
- data/lib/freddy/consumers/respond_to_consumer.rb +17 -4
- data/lib/freddy/consumers/response_consumer.rb +1 -8
- data/lib/freddy/consumers/tap_into_consumer.rb +17 -3
- data/lib/freddy/delivery.rb +21 -0
- data/lib/freddy/payload.rb +5 -2
- data/lib/freddy/producers.rb +0 -8
- data/lib/freddy/producers/reply_producer.rb +3 -2
- data/lib/freddy/producers/send_and_forget_producer.rb +20 -2
- data/lib/freddy/producers/send_and_wait_response_producer.rb +18 -5
- data/lib/freddy/trace_carrier.rb +26 -0
- data/spec/freddy/consumers/respond_to_consumer_spec.rb +0 -1
- data/spec/freddy/trace_carrier_spec.rb +56 -0
- data/spec/integration/logging_spec.rb +89 -32
- data/spec/integration/tracing_spec.rb +133 -0
- data/spec/spec_helper.rb +16 -0
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ef47a37bd23d9834cd4d639e0ea0455f5a2c5ad
|
4
|
+
data.tar.gz: 7a778b7dfa7e473a6ea27d848e67df2c662cf249
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fe89c5b20d04b4315937406452315f44516ae6ca1b250b7b11362e1ec5edfcb83ed7ffc0e654dab23735caf37490b311ecd87430f8fc4c9e2bbbb9b85c9a72d
|
7
|
+
data.tar.gz: 9e79d8a97a65c7f7077b90e9577a39ec0238edcff0afb0d97e82c3c99fac304faf154fc822fee1d3042d4600c1a825c69bca9dab998ec295383dee7bddabce89
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -135,6 +135,41 @@ The following operations are supported:
|
|
135
135
|
responder_handler.shutdown
|
136
136
|
```
|
137
137
|
|
138
|
+
## Request Tracing
|
139
|
+
|
140
|
+
Freddy supports [OpenTracing API|https://github.com/opentracing/opentracing-ruby]. You must set a global tracer which then freddy will use:
|
141
|
+
```ruby
|
142
|
+
OpenTracing.global_tracing = MyTracerImplementation.new(...)
|
143
|
+
```
|
144
|
+
|
145
|
+
For example you can use [Logasm::Tracer](https://github.com/salemove/logasm-tracer) which will log all incoming and outgoing requests with trace ID, parent ID and span ID.
|
146
|
+
|
147
|
+
Current trace can be accessed through a thread-local variable `Freddy.trace`. Calling `deliver` or `deliver_with_response` will pass trace context to down-stream services.
|
148
|
+
|
149
|
+
Accessing trace information when using Logasm::Tracer implementation:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
freddy1 = Freddy.build
|
153
|
+
freddy1.respond_do('service1') do |payload, msg_handler|
|
154
|
+
puts "Trace id: #{Freddy.trace.context.trace_id}"
|
155
|
+
puts "Span id: #{Freddy.trace.context.span_id}"
|
156
|
+
|
157
|
+
freddy1.deliver('service2', {})
|
158
|
+
end
|
159
|
+
|
160
|
+
freddy2 = Freddy.build
|
161
|
+
freddy2.tap_into('service2') do |payload|
|
162
|
+
puts "Has same trace_id as the request in service1: #{Freddy.trace.context.trace_id}"
|
163
|
+
puts "Has service1 request span id as parent id: #{Freddy.trace.context.parent_id}"
|
164
|
+
puts "Has its own generated span id: #{Freddy.trace.context.span_id}"
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
In case you already have an ongoing OpenTracing span (e.g. provided by REST API) then you can pass the trace information to Freddy by doing:
|
169
|
+
```ruby
|
170
|
+
Freddy.trace = trace_span
|
171
|
+
```
|
172
|
+
The `trace_span` must implement OpenTracing::Span interface.
|
138
173
|
|
139
174
|
## Notes about concurrency
|
140
175
|
|
data/freddy.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
else
|
9
9
|
spec.name = "freddy"
|
10
10
|
end
|
11
|
-
spec.version = '1.
|
11
|
+
spec.version = '1.3.2'
|
12
12
|
spec.authors = ["Salemove TechMovers"]
|
13
13
|
spec.email = ["techmovers@salemove.com"]
|
14
14
|
spec.description = %q{Messaging API}
|
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
|
|
32
32
|
end
|
33
33
|
|
34
34
|
spec.add_dependency "thread", "~> 0.1"
|
35
|
+
spec.add_dependency "opentracing", "~> 0.3"
|
35
36
|
end
|
data/lib/freddy.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'thread/pool'
|
3
3
|
require 'securerandom'
|
4
|
+
require 'opentracing'
|
4
5
|
|
5
6
|
Dir[File.dirname(__FILE__) + '/freddy/*.rb'].each(&method(:require))
|
6
7
|
|
@@ -25,11 +26,20 @@ class Freddy
|
|
25
26
|
# @example
|
26
27
|
# Freddy.build(Logger.new(STDOUT), user: 'thumper', pass: 'howdy')
|
27
28
|
def self.build(logger = Logger.new(STDOUT), max_concurrency: DEFAULT_MAX_CONCURRENCY, **config)
|
28
|
-
|
29
|
+
OpenTracing.global_tracer ||= OpenTracing::Tracer.new
|
29
30
|
|
31
|
+
connection = Adapters.determine.connect(config)
|
30
32
|
new(connection, logger, max_concurrency)
|
31
33
|
end
|
32
34
|
|
35
|
+
def self.trace
|
36
|
+
Thread.current[:freddy_trace]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.trace=(trace)
|
40
|
+
Thread.current[:freddy_trace] = trace
|
41
|
+
end
|
42
|
+
|
33
43
|
def initialize(connection, logger, max_concurrency)
|
34
44
|
@connection = connection
|
35
45
|
@logger = logger
|
@@ -76,7 +86,6 @@ class Freddy
|
|
76
86
|
handler_adapter_factory = MessageHandlerAdapters::Factory.new(producer)
|
77
87
|
|
78
88
|
Consumers::RespondToConsumer.consume(
|
79
|
-
logger: @logger,
|
80
89
|
thread_pool: Thread.pool(@prefetch_buffer_size),
|
81
90
|
destination: destination,
|
82
91
|
channel: channel,
|
@@ -111,7 +120,6 @@ class Freddy
|
|
111
120
|
@logger.debug "Tapping into messages that match #{pattern}"
|
112
121
|
|
113
122
|
Consumers::TapIntoConsumer.consume(
|
114
|
-
logger: @logger,
|
115
123
|
thread_pool: Thread.pool(@prefetch_buffer_size),
|
116
124
|
pattern: pattern,
|
117
125
|
channel: @connection.create_channel(prefetch: @prefetch_buffer_size),
|
data/lib/freddy/consumers.rb
CHANGED
@@ -1,14 +1 @@
|
|
1
|
-
class Freddy
|
2
|
-
module Consumers
|
3
|
-
def self.log_receive_event(logger, queue_name, delivery)
|
4
|
-
logger.debug(
|
5
|
-
message: 'Received message',
|
6
|
-
queue: queue_name,
|
7
|
-
payload: delivery.payload,
|
8
|
-
correlation_id: delivery.correlation_id
|
9
|
-
)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
1
|
Dir[File.dirname(__FILE__) + '/consumers/*.rb'].each(&method(:require))
|
@@ -5,8 +5,7 @@ class Freddy
|
|
5
5
|
new(*attrs).consume(&block)
|
6
6
|
end
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
@logger = logger
|
8
|
+
def initialize(thread_pool:, destination:, channel:, handler_adapter_factory:)
|
10
9
|
@consume_thread_pool = thread_pool
|
11
10
|
@destination = destination
|
12
11
|
@channel = channel
|
@@ -15,8 +14,6 @@ class Freddy
|
|
15
14
|
|
16
15
|
def consume(&block)
|
17
16
|
consumer = consume_from_destination do |delivery|
|
18
|
-
Consumers.log_receive_event(@logger, @destination, delivery)
|
19
|
-
|
20
17
|
adapter = @handler_adapter_factory.for(delivery)
|
21
18
|
|
22
19
|
msg_handler = MessageHandler.new(adapter, delivery)
|
@@ -37,9 +34,25 @@ class Freddy
|
|
37
34
|
def process_message(delivery, &block)
|
38
35
|
@consume_thread_pool.process do
|
39
36
|
begin
|
37
|
+
Freddy.trace = delivery.build_trace("freddy:respond:#{@destination}",
|
38
|
+
tags: {
|
39
|
+
'peer.address': "#{@destination}:#{delivery.payload[:type]}",
|
40
|
+
'component': 'freddy',
|
41
|
+
'span.kind': 'server' # RPC
|
42
|
+
}
|
43
|
+
)
|
44
|
+
Freddy.trace.log(
|
45
|
+
event: 'Received message through respond_to',
|
46
|
+
queue: @destination,
|
47
|
+
payload: delivery.payload,
|
48
|
+
correlation_id: delivery.correlation_id
|
49
|
+
)
|
50
|
+
|
40
51
|
block.call(delivery)
|
41
52
|
ensure
|
42
53
|
@channel.acknowledge(delivery.tag, false)
|
54
|
+
Freddy.trace.finish
|
55
|
+
Freddy.trace = nil
|
43
56
|
end
|
44
57
|
end
|
45
58
|
end
|
@@ -8,16 +8,9 @@ class Freddy
|
|
8
8
|
def consume(channel, queue, &block)
|
9
9
|
@logger.debug "Consuming messages on #{queue.name}"
|
10
10
|
queue.subscribe do |delivery|
|
11
|
-
|
11
|
+
block.call(delivery)
|
12
12
|
end
|
13
13
|
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def process_message(channel, queue, delivery, &block)
|
18
|
-
Consumers.log_receive_event(@logger, queue.name, delivery)
|
19
|
-
block.call(delivery)
|
20
|
-
end
|
21
14
|
end
|
22
15
|
end
|
23
16
|
end
|
@@ -5,8 +5,7 @@ class Freddy
|
|
5
5
|
new(*attrs).consume(&block)
|
6
6
|
end
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
@logger = logger
|
8
|
+
def initialize(thread_pool:, pattern:, channel:, options:)
|
10
9
|
@consume_thread_pool = thread_pool
|
11
10
|
@pattern = pattern
|
12
11
|
@channel = channel
|
@@ -43,10 +42,25 @@ class Freddy
|
|
43
42
|
def process_message(queue, delivery, &block)
|
44
43
|
@consume_thread_pool.process do
|
45
44
|
begin
|
46
|
-
|
45
|
+
Freddy.trace = delivery.build_trace("freddy:observe:#{@pattern}",
|
46
|
+
tags: {
|
47
|
+
'message_bus.destination': @pattern,
|
48
|
+
'component': 'freddy',
|
49
|
+
'span.kind': 'consumer' # Message Bus
|
50
|
+
},
|
51
|
+
force_follows_from: true
|
52
|
+
)
|
53
|
+
Freddy.trace.log(
|
54
|
+
event: 'Received message through tap_into',
|
55
|
+
payload: delivery.payload,
|
56
|
+
correlation_id: delivery.correlation_id
|
57
|
+
)
|
58
|
+
|
47
59
|
block.call delivery.payload, delivery.routing_key
|
48
60
|
ensure
|
49
61
|
@channel.acknowledge(delivery.tag, false)
|
62
|
+
Freddy.trace.finish
|
63
|
+
Freddy.trace = nil
|
50
64
|
end
|
51
65
|
end
|
52
66
|
end
|
data/lib/freddy/delivery.rb
CHANGED
@@ -20,5 +20,26 @@ class Freddy
|
|
20
20
|
def reply_to
|
21
21
|
@metadata.reply_to
|
22
22
|
end
|
23
|
+
|
24
|
+
def build_trace(operation_name, tags: {}, force_follows_from: false)
|
25
|
+
carrier = TraceCarrier.new(@metadata)
|
26
|
+
parent =
|
27
|
+
if expecting_response? && !force_follows_from
|
28
|
+
OpenTracing.global_tracer.extract(OpenTracing::FORMAT_TEXT_MAP, carrier)
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Creating a child span when the message sender is expecting a response.
|
34
|
+
# Otherwise creating a new trace because the OpenTracing client does not
|
35
|
+
# support FollowsFrom yet.
|
36
|
+
OpenTracing.start_span(operation_name, child_of: parent, tags: tags)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def expecting_response?
|
42
|
+
type == 'request'
|
43
|
+
end
|
23
44
|
end
|
24
45
|
end
|
data/lib/freddy/payload.rb
CHANGED
@@ -22,12 +22,15 @@ class Freddy
|
|
22
22
|
end
|
23
23
|
|
24
24
|
class OjAdapter
|
25
|
+
PARSE_OPTIONS = { symbol_keys: true }
|
26
|
+
DUMP_OPTIONS = { mode: :compat, time_format: :xmlschema, second_precision: 6 }
|
27
|
+
|
25
28
|
def self.parse(payload)
|
26
|
-
Oj.strict_load(payload,
|
29
|
+
Oj.strict_load(payload, PARSE_OPTIONS)
|
27
30
|
end
|
28
31
|
|
29
32
|
def self.dump(payload)
|
30
|
-
Oj.dump(payload,
|
33
|
+
Oj.dump(payload, DUMP_OPTIONS)
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
data/lib/freddy/producers.rb
CHANGED
@@ -9,10 +9,11 @@ class Freddy
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def produce(destination, payload, properties)
|
12
|
-
|
12
|
+
Freddy.trace.log event: 'Sending response', queue: destination, payload: payload
|
13
13
|
|
14
14
|
properties = properties.merge(
|
15
|
-
routing_key: destination,
|
15
|
+
routing_key: destination,
|
16
|
+
content_type: CONTENT_TYPE
|
16
17
|
)
|
17
18
|
|
18
19
|
@exchange.publish Payload.dump(payload), properties
|
@@ -10,15 +10,33 @@ class Freddy
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def produce(destination, payload, properties)
|
13
|
-
|
13
|
+
span = OpenTracing.start_span("freddy:notify:#{destination}",
|
14
|
+
child_of: Freddy.trace,
|
15
|
+
tags: {
|
16
|
+
'message_bus.destination': destination,
|
17
|
+
'component': 'freddy',
|
18
|
+
'span.kind': 'producer' # Message Bus
|
19
|
+
}
|
20
|
+
)
|
21
|
+
span.log event: 'Sending message', payload: payload
|
14
22
|
|
15
|
-
properties = properties.merge(
|
23
|
+
properties = properties.merge(
|
24
|
+
routing_key: destination,
|
25
|
+
content_type: CONTENT_TYPE
|
26
|
+
)
|
27
|
+
OpenTracing.global_tracer.inject(span.context, OpenTracing::FORMAT_TEXT_MAP, TraceCarrier.new(properties))
|
16
28
|
json_payload = Payload.dump(payload)
|
17
29
|
|
18
30
|
# Connection adapters handle thread safety for #publish themselves. No
|
19
31
|
# need to lock these.
|
20
32
|
@topic_exchange.publish json_payload, properties.dup
|
21
33
|
@exchange.publish json_payload, properties.dup
|
34
|
+
ensure
|
35
|
+
# We don't know how many listeners there are and we do not know when
|
36
|
+
# this message gets processed. Instead we close the span immediately.
|
37
|
+
# Listeners should use FollowsFrom to add trace information.
|
38
|
+
# https://github.com/opentracing/specification/blob/master/specification.md
|
39
|
+
span.finish
|
22
40
|
end
|
23
41
|
end
|
24
42
|
end
|
@@ -23,14 +23,24 @@ class Freddy
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def produce(destination, payload, timeout_in_seconds:, delete_on_timeout:, **properties)
|
26
|
+
span = OpenTracing.start_span("freddy:request:#{destination}",
|
27
|
+
child_of: Freddy.trace,
|
28
|
+
tags: {
|
29
|
+
'component': 'freddy',
|
30
|
+
'span.kind': 'client', # RPC
|
31
|
+
'payload.type': payload[:type]
|
32
|
+
}
|
33
|
+
)
|
34
|
+
|
26
35
|
correlation_id = SecureRandom.uuid
|
27
36
|
|
28
37
|
container = SyncResponseContainer.new(
|
29
|
-
on_timeout(correlation_id, destination, timeout_in_seconds)
|
38
|
+
on_timeout(correlation_id, destination, timeout_in_seconds, span)
|
30
39
|
)
|
31
40
|
|
32
41
|
@request_manager.store(correlation_id,
|
33
42
|
callback: container,
|
43
|
+
trace: span,
|
34
44
|
destination: destination
|
35
45
|
)
|
36
46
|
|
@@ -43,11 +53,11 @@ class Freddy
|
|
43
53
|
correlation_id: correlation_id, reply_to: @response_queue.name,
|
44
54
|
mandatory: true, type: 'request'
|
45
55
|
)
|
56
|
+
OpenTracing.global_tracer.inject(span.context, OpenTracing::FORMAT_TEXT_MAP, TraceCarrier.new(properties))
|
46
57
|
json_payload = Payload.dump(payload)
|
47
58
|
|
48
|
-
|
49
|
-
|
50
|
-
queue: destination,
|
59
|
+
span.log(
|
60
|
+
event: 'Publishing request',
|
51
61
|
payload: payload,
|
52
62
|
response_queue: @response_queue.name,
|
53
63
|
correlation_id: correlation_id
|
@@ -77,14 +87,17 @@ class Freddy
|
|
77
87
|
@logger.debug "Got response for request to #{request[:destination]} "\
|
78
88
|
"with correlation_id #{delivery.correlation_id}"
|
79
89
|
request[:callback].call(delivery.payload, delivery)
|
90
|
+
ensure
|
91
|
+
request[:trace].finish
|
80
92
|
end
|
81
93
|
|
82
|
-
def on_timeout(correlation_id, destination, timeout_in_seconds)
|
94
|
+
def on_timeout(correlation_id, destination, timeout_in_seconds, trace)
|
83
95
|
Proc.new do
|
84
96
|
@logger.warn "Request timed out waiting response from #{destination}"\
|
85
97
|
", correlation id #{correlation_id}"
|
86
98
|
|
87
99
|
@request_manager.delete(correlation_id)
|
100
|
+
trace.finish
|
88
101
|
end
|
89
102
|
end
|
90
103
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Freddy
|
2
|
+
# Carrier for rabbitmq following OpenTracing API
|
3
|
+
# See https://github.com/opentracing/opentracing-ruby/blob/master/lib/opentracing/carrier.rb
|
4
|
+
class TraceCarrier
|
5
|
+
def initialize(properties)
|
6
|
+
@properties = properties
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
@properties.headers && @properties.headers["x-trace-#{key}"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, value)
|
14
|
+
@properties[:headers] ||= {}
|
15
|
+
@properties[:headers]["x-trace-#{key}"] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
Hash[
|
20
|
+
(@properties.headers || {})
|
21
|
+
.select {|key, _| key =~ /^x-trace/}
|
22
|
+
.map {|key, value| [key.sub(/x-trace-/, ''), value]}
|
23
|
+
].each(&block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Freddy::TraceCarrier do
|
4
|
+
subject(:carrier) { described_class.new(properties) }
|
5
|
+
|
6
|
+
context 'when adding trace information' do
|
7
|
+
let(:properties) { {x: 'y'} }
|
8
|
+
let(:key_name) { 'some-key' }
|
9
|
+
let(:key_value) { 'some-key' }
|
10
|
+
|
11
|
+
it 'adds a header with x-trace- prefix' do
|
12
|
+
carrier[key_name] = key_value
|
13
|
+
expect(properties[:headers]["x-trace-#{key_name}"]).to eq(key_value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when extracting trace information' do
|
18
|
+
let(:key_name) { 'some-key' }
|
19
|
+
let(:serialized_key_name) { "x-trace-#{key_name}" }
|
20
|
+
let(:key_value) { 'some-key' }
|
21
|
+
|
22
|
+
let(:properties) do
|
23
|
+
double(headers: {serialized_key_name => key_value})
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'extracts a header with x-trace- prefix' do
|
27
|
+
expect(carrier[key_name]).to eq(key_value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#each' do
|
32
|
+
context 'when headers are present' do
|
33
|
+
let(:properties) do
|
34
|
+
double(
|
35
|
+
headers: {
|
36
|
+
"x-trace-key1" => "value1",
|
37
|
+
"x-trace-key2" => "value2",
|
38
|
+
"other-key" => "value3"
|
39
|
+
}
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'iterates over keys starting with x-trace- prefix' do
|
44
|
+
expect(carrier.each.count).to eq(2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when no headers' do
|
49
|
+
let(:properties) { double(headers: nil) }
|
50
|
+
|
51
|
+
it 'iterates over an empty list' do
|
52
|
+
expect(carrier.each.count).to eq(0)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,44 +1,101 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'logasm/tracer'
|
2
3
|
|
3
|
-
describe 'Logging' do
|
4
|
-
let(:
|
5
|
-
let(:
|
4
|
+
describe 'Logging with Logasm::Tracer' do
|
5
|
+
let(:logger) { ArrayLogger.new }
|
6
|
+
let(:tracer) { Logasm::Tracer.new(logger) }
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
before { OpenTracing.global_tracer = tracer }
|
9
|
+
after { OpenTracing.global_tracer = nil }
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
context 'when receiving an untraced request' do
|
12
|
+
let(:freddy) { Freddy.build(spy, config) }
|
13
|
+
let(:destination) { random_destination }
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
before do
|
16
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
17
|
+
sleep 0.1 # emulate some processing
|
18
|
+
msg_handler.success({})
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
after { freddy.close }
|
23
|
+
|
24
|
+
it 'generates a trace' do
|
25
|
+
freddy.deliver_with_response(destination, {})
|
26
|
+
|
27
|
+
expect(logger.calls.map(&:first)).to eq([
|
28
|
+
# Initiator
|
29
|
+
"Span [freddy:request:#{destination}] started",
|
30
|
+
"Span [freddy:request:#{destination}] Publishing request",
|
31
|
+
|
32
|
+
# Service
|
33
|
+
"Span [freddy:respond:#{destination}] started",
|
34
|
+
"Span [freddy:respond:#{destination}] Received message through respond_to",
|
35
|
+
"Span [freddy:respond:#{destination}] Sending response",
|
36
|
+
"Span [freddy:respond:#{destination}] finished",
|
23
37
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
queue: destination,
|
29
|
-
payload: payload,
|
30
|
-
correlation_id: anything
|
31
|
-
)
|
38
|
+
# Initiator
|
39
|
+
"Span [freddy:request:#{destination}] finished"
|
40
|
+
])
|
41
|
+
end
|
32
42
|
end
|
33
43
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
context 'when receiving a traced request' do
|
45
|
+
let(:freddy) { Freddy.build(spy, config) }
|
46
|
+
let(:freddy2) { Freddy.build(spy, config) }
|
47
|
+
|
48
|
+
let(:destination) { random_destination }
|
49
|
+
let(:destination2) { random_destination }
|
50
|
+
|
51
|
+
before do
|
52
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
53
|
+
sleep 0.1 # emulate some processing
|
54
|
+
msg_handler.success({
|
55
|
+
trace_initiator: {},
|
56
|
+
current_receiver: freddy.deliver_with_response(destination2, {})
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
freddy2.respond_to(destination2) do |payload, msg_handler|
|
61
|
+
sleep 0.1 # emulate some processing
|
62
|
+
msg_handler.success({})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
after do
|
67
|
+
freddy.close
|
68
|
+
freddy2.close
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'generates a trace' do
|
72
|
+
freddy.deliver_with_response(destination, {})
|
73
|
+
|
74
|
+
expect(logger.calls.map(&:first)).to eq([
|
75
|
+
# Initiator
|
76
|
+
"Span [freddy:request:#{destination}] started",
|
77
|
+
"Span [freddy:request:#{destination}] Publishing request",
|
78
|
+
|
79
|
+
# Service 1
|
80
|
+
"Span [freddy:respond:#{destination}] started",
|
81
|
+
"Span [freddy:respond:#{destination}] Received message through respond_to",
|
82
|
+
"Span [freddy:request:#{destination2}] started",
|
83
|
+
"Span [freddy:request:#{destination2}] Publishing request",
|
84
|
+
|
85
|
+
# Service 2
|
86
|
+
"Span [freddy:respond:#{destination2}] started",
|
87
|
+
"Span [freddy:respond:#{destination2}] Received message through respond_to",
|
88
|
+
"Span [freddy:respond:#{destination2}] Sending response",
|
89
|
+
"Span [freddy:respond:#{destination2}] finished",
|
90
|
+
|
91
|
+
# Service 1
|
92
|
+
"Span [freddy:request:#{destination2}] finished",
|
93
|
+
"Span [freddy:respond:#{destination}] Sending response",
|
94
|
+
"Span [freddy:respond:#{destination}] finished",
|
95
|
+
|
96
|
+
# Initiator
|
97
|
+
"Span [freddy:request:#{destination}] finished"
|
98
|
+
])
|
99
|
+
end
|
43
100
|
end
|
44
101
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'logasm/tracer'
|
3
|
+
|
4
|
+
describe 'Tracing' do
|
5
|
+
let(:tracer) { Logasm::Tracer.new(logger) }
|
6
|
+
let(:logger) { spy }
|
7
|
+
|
8
|
+
before { OpenTracing.global_tracer = tracer }
|
9
|
+
after { OpenTracing.global_tracer = nil }
|
10
|
+
|
11
|
+
context 'when receiving a traced request' do
|
12
|
+
let(:freddy) { Freddy.build(logger, config) }
|
13
|
+
let(:freddy2) { Freddy.build(logger, config) }
|
14
|
+
|
15
|
+
let(:destination) { random_destination }
|
16
|
+
let(:destination2) { random_destination }
|
17
|
+
|
18
|
+
before do
|
19
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
20
|
+
msg_handler.success({
|
21
|
+
trace_initiator: {
|
22
|
+
trace_id: Freddy.trace.context.trace_id,
|
23
|
+
parent_id: Freddy.trace.context.parent_id,
|
24
|
+
span_id: Freddy.trace.context.span_id
|
25
|
+
},
|
26
|
+
current_receiver: freddy.deliver_with_response(destination2, {})
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
freddy2.respond_to(destination2) do |payload, msg_handler|
|
31
|
+
msg_handler.success({
|
32
|
+
trace_id: Freddy.trace.context.trace_id,
|
33
|
+
parent_id: Freddy.trace.context.parent_id,
|
34
|
+
span_id: Freddy.trace.context.span_id
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
after do
|
40
|
+
freddy.close
|
41
|
+
freddy2.close
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'has trace_id from the trace initiator' do
|
45
|
+
response = freddy.deliver_with_response(destination, {})
|
46
|
+
trace_initiator = response.fetch(:trace_initiator)
|
47
|
+
current_receiver = response.fetch(:current_receiver)
|
48
|
+
expect(trace_initiator.fetch(:trace_id)).to eq(current_receiver.fetch(:trace_id))
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'has parent_id' do
|
52
|
+
response = freddy.deliver_with_response(destination, {})
|
53
|
+
current_receiver = response.fetch(:current_receiver)
|
54
|
+
expect(current_receiver.fetch(:parent_id)).to_not be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has generated span_id' do
|
58
|
+
response = freddy.deliver_with_response(destination, {})
|
59
|
+
trace_initiator = response.fetch(:trace_initiator)
|
60
|
+
current_receiver = response.fetch(:current_receiver)
|
61
|
+
expect(current_receiver.fetch(:span_id)).to_not be_nil
|
62
|
+
expect(current_receiver.fetch(:span_id)).to_not eq(trace_initiator.fetch(:span_id))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when receiving a nested traced request' do
|
67
|
+
let(:freddy) { Freddy.build(logger, config) }
|
68
|
+
let(:freddy2) { Freddy.build(logger, config) }
|
69
|
+
let(:freddy3) { Freddy.build(logger, config) }
|
70
|
+
|
71
|
+
let(:destination) { random_destination }
|
72
|
+
let(:destination2) { random_destination }
|
73
|
+
let(:destination3) { random_destination }
|
74
|
+
|
75
|
+
before do
|
76
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
77
|
+
msg_handler.success({
|
78
|
+
trace_initiator: {
|
79
|
+
trace_id: Freddy.trace.context.trace_id,
|
80
|
+
parent_id: Freddy.trace.context.parent_id,
|
81
|
+
span_id: Freddy.trace.context.span_id
|
82
|
+
}
|
83
|
+
}.merge(freddy.deliver_with_response(destination2, {})))
|
84
|
+
end
|
85
|
+
|
86
|
+
freddy2.respond_to(destination2) do |payload, msg_handler|
|
87
|
+
msg_handler.success({
|
88
|
+
previous_receiver: {
|
89
|
+
trace_id: Freddy.trace.context.trace_id,
|
90
|
+
parent_id: Freddy.trace.context.parent_id,
|
91
|
+
span_id: Freddy.trace.context.span_id
|
92
|
+
},
|
93
|
+
current_receiver: freddy2.deliver_with_response(destination3, {})
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
freddy3.respond_to(destination3) do |payload, msg_handler|
|
98
|
+
msg_handler.success({
|
99
|
+
trace_id: Freddy.trace.context.trace_id,
|
100
|
+
parent_id: Freddy.trace.context.parent_id,
|
101
|
+
span_id: Freddy.trace.context.span_id
|
102
|
+
})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
after do
|
107
|
+
freddy.close
|
108
|
+
freddy2.close
|
109
|
+
freddy3.close
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'has trace_id from the trace initiator' do
|
113
|
+
response = freddy.deliver_with_response(destination, {})
|
114
|
+
trace_initiator = response.fetch(:trace_initiator)
|
115
|
+
current_receiver = response.fetch(:current_receiver)
|
116
|
+
expect(trace_initiator.fetch(:trace_id)).to eq(current_receiver.fetch(:trace_id))
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'has parent_id' do
|
120
|
+
response = freddy.deliver_with_response(destination, {})
|
121
|
+
current_receiver = response.fetch(:current_receiver)
|
122
|
+
expect(current_receiver.fetch(:parent_id)).to_not be_nil
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'has generated span_id' do
|
126
|
+
response = freddy.deliver_with_response(destination, {})
|
127
|
+
previous_receiver = response.fetch(:previous_receiver)
|
128
|
+
current_receiver = response.fetch(:current_receiver)
|
129
|
+
expect(current_receiver.fetch(:span_id)).to_not be_nil
|
130
|
+
expect(current_receiver.fetch(:span_id)).to_not eq(previous_receiver.fetch(:span_id))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -22,6 +22,10 @@ RSpec.configure do |config|
|
|
22
22
|
config.run_all_when_everything_filtered = true
|
23
23
|
config.filter_run :focus
|
24
24
|
config.order = 'random'
|
25
|
+
|
26
|
+
config.before do
|
27
|
+
OpenTracing.global_tracer ||= OpenTracing::Tracer.new
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
def random_destination
|
@@ -61,3 +65,15 @@ def spawn_echo_responder(freddy, queue_name)
|
|
61
65
|
msg_handler.success(payload)
|
62
66
|
end
|
63
67
|
end
|
68
|
+
|
69
|
+
class ArrayLogger
|
70
|
+
attr_accessor :calls
|
71
|
+
|
72
|
+
def initialize
|
73
|
+
@calls = []
|
74
|
+
end
|
75
|
+
|
76
|
+
def info(*args)
|
77
|
+
@calls << args
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freddy-jruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salemove TechMovers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.3'
|
89
|
+
name: opentracing
|
90
|
+
prerelease: false
|
91
|
+
type: :runtime
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.3'
|
83
97
|
description: Messaging API
|
84
98
|
email:
|
85
99
|
- techmovers@salemove.com
|
@@ -120,6 +134,7 @@ files:
|
|
120
134
|
- lib/freddy/responder_handler.rb
|
121
135
|
- lib/freddy/sync_response_container.rb
|
122
136
|
- lib/freddy/timeout_error.rb
|
137
|
+
- lib/freddy/trace_carrier.rb
|
123
138
|
- spec/freddy/consumers/respond_to_consumer_spec.rb
|
124
139
|
- spec/freddy/error_response_spec.rb
|
125
140
|
- spec/freddy/freddy_spec.rb
|
@@ -127,10 +142,12 @@ files:
|
|
127
142
|
- spec/freddy/payload_spec.rb
|
128
143
|
- spec/freddy/responder_handler_spec.rb
|
129
144
|
- spec/freddy/sync_response_container_spec.rb
|
145
|
+
- spec/freddy/trace_carrier_spec.rb
|
130
146
|
- spec/integration/concurrency_spec.rb
|
131
147
|
- spec/integration/logging_spec.rb
|
132
148
|
- spec/integration/reply_spec.rb
|
133
149
|
- spec/integration/tap_into_with_group_spec.rb
|
150
|
+
- spec/integration/tracing_spec.rb
|
134
151
|
- spec/spec_helper.rb
|
135
152
|
homepage:
|
136
153
|
licenses:
|
@@ -152,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
169
|
version: '0'
|
153
170
|
requirements: []
|
154
171
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.
|
172
|
+
rubygems_version: 2.4.8
|
156
173
|
signing_key:
|
157
174
|
specification_version: 4
|
158
175
|
summary: API for inter-application messaging supporting acknowledgements and request-response
|
@@ -164,8 +181,10 @@ test_files:
|
|
164
181
|
- spec/freddy/payload_spec.rb
|
165
182
|
- spec/freddy/responder_handler_spec.rb
|
166
183
|
- spec/freddy/sync_response_container_spec.rb
|
184
|
+
- spec/freddy/trace_carrier_spec.rb
|
167
185
|
- spec/integration/concurrency_spec.rb
|
168
186
|
- spec/integration/logging_spec.rb
|
169
187
|
- spec/integration/reply_spec.rb
|
170
188
|
- spec/integration/tap_into_with_group_spec.rb
|
189
|
+
- spec/integration/tracing_spec.rb
|
171
190
|
- spec/spec_helper.rb
|