freddy 1.0.1 → 1.1.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 +4 -4
- data/README.md +29 -0
- data/freddy.gemspec +1 -1
- data/lib/freddy/consumers/respond_to_consumer.rb +2 -0
- data/lib/freddy/consumers/tap_into_consumer.rb +2 -0
- data/lib/freddy/consumers.rb +2 -1
- data/lib/freddy/delivery.rb +15 -1
- data/lib/freddy/producers/reply_producer.rb +6 -1
- data/lib/freddy/producers/send_and_forget_producer.rb +8 -1
- data/lib/freddy/producers/send_and_wait_response_producer.rb +7 -2
- data/lib/freddy/producers.rb +1 -1
- data/lib/freddy/traces.rb +40 -0
- data/lib/freddy.rb +8 -0
- data/spec/freddy/traces/trace_id_spec.rb +9 -0
- data/spec/integration/logging_spec.rb +4 -2
- data/spec/integration/tracing_spec.rb +160 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55a9bea9337f7d20d2e713bd012ed8f216fef328
|
4
|
+
data.tar.gz: 2c49767c9226fdf1b882cf221cec8ff7726203f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d3c30c1d5d54c72539821bc465f0887371ee30fdcbed3fa4711ee3b9f65137922025a4aa6956ca862b08b851d5bc8bff2d4aac7279a80250475c45a90e475ab
|
7
|
+
data.tar.gz: 13f606726903475c3619ee4f7dd1d18ebe257cbb48844cb0831cf81809b468eeb7143c4d4519b8cd1e6fa00e9d4703dcf9ce1282ebf70d4867419c85a89f42ae
|
data/README.md
CHANGED
@@ -135,6 +135,35 @@ The following operations are supported:
|
|
135
135
|
responder_handler.shutdown
|
136
136
|
```
|
137
137
|
|
138
|
+
## Request Tracing
|
139
|
+
|
140
|
+
Freddy helps application developers to implement distributed tracing. Freddy provides trace ID, parent ID and span ID when receiving a request. These can be accessed through a thread-local variable `Freddy.trace`. Calling `deliver` or `deliver_with_response` will pass these IDs to the next service.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
freddy1 = Freddy.build
|
144
|
+
freddy1.respond_do('service1') do |payload, msg_handler|
|
145
|
+
puts "Trace id: #{Freddy.trace.id}"
|
146
|
+
puts "Span id: #{Freddy.trace.span_id}"
|
147
|
+
|
148
|
+
freddy1.deliver('service2', {})
|
149
|
+
end
|
150
|
+
|
151
|
+
freddy2 = Freddy.build
|
152
|
+
freddy2.tap_into('service2') do |payload|
|
153
|
+
puts "Has same trace_id as the request in service1: #{Freddy.trace.id}"
|
154
|
+
puts "Has service1 request span id as parent id: #{Freddy.trace.parent_id}"
|
155
|
+
puts "Has its own generated span id: #{Freddy.trace.span_id}"
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
In case you already have trace IDs (e.g. provided by REST API) then you can set them yourself:
|
160
|
+
```ruby
|
161
|
+
Freddy.trace = Freddy::Traces::Trace.new({
|
162
|
+
id: 'YourTraceId',
|
163
|
+
parent_id: 'YourParentId', # Use nil in case this is the root of the trace
|
164
|
+
span_id: 'YourSpanId'
|
165
|
+
})
|
166
|
+
```
|
138
167
|
|
139
168
|
## Notes about concurrency
|
140
169
|
|
data/freddy.gemspec
CHANGED
@@ -37,9 +37,11 @@ class Freddy
|
|
37
37
|
def process_message(delivery, &block)
|
38
38
|
@consume_thread_pool.process do
|
39
39
|
begin
|
40
|
+
Freddy.trace = delivery.trace
|
40
41
|
block.call(delivery)
|
41
42
|
ensure
|
42
43
|
@channel.acknowledge(delivery.tag, false)
|
44
|
+
Freddy.trace = nil
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
@@ -44,9 +44,11 @@ class Freddy
|
|
44
44
|
@consume_thread_pool.process do
|
45
45
|
begin
|
46
46
|
Consumers.log_receive_event(@logger, queue.name, delivery)
|
47
|
+
Freddy.trace = delivery.trace
|
47
48
|
block.call delivery.payload, delivery.routing_key
|
48
49
|
ensure
|
49
50
|
@channel.acknowledge(delivery.tag, false)
|
51
|
+
Freddy.trace = nil
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
data/lib/freddy/consumers.rb
CHANGED
data/lib/freddy/delivery.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
class Freddy
|
2
2
|
class Delivery
|
3
|
-
attr_reader :routing_key, :payload, :tag
|
3
|
+
attr_reader :routing_key, :payload, :tag, :trace
|
4
4
|
|
5
5
|
def initialize(payload, metadata, routing_key, tag)
|
6
6
|
@payload = payload
|
7
7
|
@metadata = metadata
|
8
8
|
@routing_key = routing_key
|
9
9
|
@tag = tag
|
10
|
+
@trace = build_trace(metadata.headers || {})
|
10
11
|
end
|
11
12
|
|
12
13
|
def correlation_id
|
@@ -20,5 +21,18 @@ class Freddy
|
|
20
21
|
def reply_to
|
21
22
|
@metadata.reply_to
|
22
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_trace(headers)
|
28
|
+
if headers['x-trace-id'] && headers['x-span-id']
|
29
|
+
Traces::Trace.build_from_existing_trace(
|
30
|
+
id: headers['x-trace-id'],
|
31
|
+
parent_id: headers['x-span-id']
|
32
|
+
)
|
33
|
+
else
|
34
|
+
Traces::Trace.build
|
35
|
+
end
|
36
|
+
end
|
23
37
|
end
|
24
38
|
end
|
@@ -12,7 +12,12 @@ class Freddy
|
|
12
12
|
Producers.log_send_event(@logger, payload, destination)
|
13
13
|
|
14
14
|
properties = properties.merge(
|
15
|
-
routing_key: destination,
|
15
|
+
routing_key: destination,
|
16
|
+
content_type: CONTENT_TYPE,
|
17
|
+
headers: {
|
18
|
+
'x-trace-id' => Freddy.trace.id,
|
19
|
+
'x-span-id' => Freddy.trace.span_id
|
20
|
+
}
|
16
21
|
)
|
17
22
|
|
18
23
|
@exchange.publish Payload.dump(payload), properties
|
@@ -12,7 +12,14 @@ class Freddy
|
|
12
12
|
def produce(destination, payload, properties)
|
13
13
|
Producers.log_send_event(@logger, payload, destination)
|
14
14
|
|
15
|
-
properties = properties.merge(
|
15
|
+
properties = properties.merge(
|
16
|
+
routing_key: destination,
|
17
|
+
content_type: CONTENT_TYPE,
|
18
|
+
headers: {
|
19
|
+
'x-trace-id' => Freddy.trace.id,
|
20
|
+
'x-span-id' => Freddy.trace.span_id
|
21
|
+
}
|
22
|
+
)
|
16
23
|
json_payload = Payload.dump(payload)
|
17
24
|
|
18
25
|
# Connection adapters handle thread safety for #publish themselves. No
|
@@ -41,7 +41,11 @@ class Freddy
|
|
41
41
|
properties = properties.merge(
|
42
42
|
routing_key: destination, content_type: CONTENT_TYPE,
|
43
43
|
correlation_id: correlation_id, reply_to: @response_queue.name,
|
44
|
-
mandatory: true, type: 'request'
|
44
|
+
mandatory: true, type: 'request',
|
45
|
+
headers: {
|
46
|
+
'x-trace-id' => Freddy.trace.id,
|
47
|
+
'x-span-id' => Freddy.trace.span_id
|
48
|
+
}
|
45
49
|
)
|
46
50
|
json_payload = Payload.dump(payload)
|
47
51
|
|
@@ -50,7 +54,8 @@ class Freddy
|
|
50
54
|
queue: destination,
|
51
55
|
payload: payload,
|
52
56
|
response_queue: @response_queue.name,
|
53
|
-
correlation_id: correlation_id
|
57
|
+
correlation_id: correlation_id,
|
58
|
+
trace: Freddy.trace.to_h
|
54
59
|
)
|
55
60
|
|
56
61
|
# Connection adapters handle thread safety for #publish themselves. No
|
data/lib/freddy/producers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Freddy
|
2
2
|
module Producers
|
3
3
|
def self.log_send_event(logger, payload, destination)
|
4
|
-
logger.debug message: 'Sending message', queue: destination, payload: payload
|
4
|
+
logger.debug message: 'Sending message', queue: destination, payload: payload, trace: Freddy.trace.to_h
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Freddy
|
2
|
+
module Traces
|
3
|
+
class Trace
|
4
|
+
def self.build
|
5
|
+
id = TraceId.generate
|
6
|
+
span_id = TraceId.generate
|
7
|
+
new(id: id, parent_id: nil, span_id: span_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.build_from_existing_trace(id:, parent_id:)
|
11
|
+
span_id = TraceId.generate
|
12
|
+
new(id: id, parent_id: parent_id, span_id: span_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :id, :parent_id, :span_id
|
16
|
+
|
17
|
+
def initialize(id:, parent_id:, span_id:)
|
18
|
+
@id = id
|
19
|
+
@parent_id = parent_id
|
20
|
+
@span_id = span_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h
|
24
|
+
{id: @id, parent_id: @parent_id, span_id: @span_id}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module TraceId
|
29
|
+
TRACE_ID_UPPER_BOUND = 2 ** 64
|
30
|
+
|
31
|
+
# Generates 64-bit lower-hex encoded ID. This was chosen to be compatible
|
32
|
+
# with tracing frameworks like zipkin.
|
33
|
+
def self.generate
|
34
|
+
rand(TRACE_ID_UPPER_BOUND).to_s(16)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
NO_TRACE = Trace.new(id: nil, parent_id: nil, span_id: nil)
|
39
|
+
end
|
40
|
+
end
|
data/lib/freddy.rb
CHANGED
@@ -30,6 +30,14 @@ class Freddy
|
|
30
30
|
new(connection, logger, max_concurrency)
|
31
31
|
end
|
32
32
|
|
33
|
+
def self.trace
|
34
|
+
Thread.current[:freddy_trace] || Traces::NO_TRACE
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.trace=(trace)
|
38
|
+
Thread.current[:freddy_trace] = trace
|
39
|
+
end
|
40
|
+
|
33
41
|
def initialize(connection, logger, max_concurrency)
|
34
42
|
@connection = connection
|
35
43
|
@logger = logger
|
@@ -27,7 +27,8 @@ describe 'Logging' do
|
|
27
27
|
message: 'Received message',
|
28
28
|
queue: destination,
|
29
29
|
payload: payload,
|
30
|
-
correlation_id: anything
|
30
|
+
correlation_id: anything,
|
31
|
+
trace: anything
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
@@ -38,7 +39,8 @@ describe 'Logging' do
|
|
38
39
|
queue: destination,
|
39
40
|
payload: payload,
|
40
41
|
response_queue: anything,
|
41
|
-
correlation_id: anything
|
42
|
+
correlation_id: anything,
|
43
|
+
trace: anything
|
42
44
|
)
|
43
45
|
end
|
44
46
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Tracing' do
|
4
|
+
context 'when receiving an untraced request' do
|
5
|
+
let(:freddy) { Freddy.build(logger, config) }
|
6
|
+
let(:destination) { random_destination }
|
7
|
+
|
8
|
+
before do
|
9
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
10
|
+
msg_handler.success({
|
11
|
+
trace_id: Freddy.trace.id,
|
12
|
+
parent_id: Freddy.trace.parent_id,
|
13
|
+
span_id: Freddy.trace.span_id
|
14
|
+
})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
after { freddy.close }
|
19
|
+
|
20
|
+
it 'has generated trace_id' do
|
21
|
+
response = freddy.deliver_with_response(destination, {})
|
22
|
+
expect(response.fetch(:trace_id)).to_not be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has no parent_id' do
|
26
|
+
response = freddy.deliver_with_response(destination, {})
|
27
|
+
expect(response.fetch(:parent_id)).to be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'has generated span_id' do
|
31
|
+
response = freddy.deliver_with_response(destination, {})
|
32
|
+
expect(response.fetch(:span_id)).to_not be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when receiving a traced request' do
|
37
|
+
let(:freddy) { Freddy.build(logger, config) }
|
38
|
+
let(:freddy2) { Freddy.build(logger, config) }
|
39
|
+
|
40
|
+
let(:destination) { random_destination }
|
41
|
+
let(:destination2) { random_destination }
|
42
|
+
|
43
|
+
before do
|
44
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
45
|
+
msg_handler.success({
|
46
|
+
trace_initiator: {
|
47
|
+
trace_id: Freddy.trace.id,
|
48
|
+
parent_id: Freddy.trace.parent_id,
|
49
|
+
span_id: Freddy.trace.span_id
|
50
|
+
},
|
51
|
+
current_receiver: freddy.deliver_with_response(destination2, {})
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
freddy2.respond_to(destination2) do |payload, msg_handler|
|
56
|
+
msg_handler.success({
|
57
|
+
trace_id: Freddy.trace.id,
|
58
|
+
parent_id: Freddy.trace.parent_id,
|
59
|
+
span_id: Freddy.trace.span_id
|
60
|
+
})
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
after do
|
65
|
+
freddy.close
|
66
|
+
freddy2.close
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'has trace_id from the trace initiator' do
|
70
|
+
response = freddy.deliver_with_response(destination, {})
|
71
|
+
trace_initiator = response.fetch(:trace_initiator)
|
72
|
+
current_receiver = response.fetch(:current_receiver)
|
73
|
+
expect(trace_initiator.fetch(:trace_id)).to eq(current_receiver.fetch(:trace_id))
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'has request initiator span_id as parent_id' do
|
77
|
+
response = freddy.deliver_with_response(destination, {})
|
78
|
+
trace_initiator = response.fetch(:trace_initiator)
|
79
|
+
current_receiver = response.fetch(:current_receiver)
|
80
|
+
expect(trace_initiator.fetch(:span_id)).to eq(current_receiver.fetch(:parent_id))
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'has generated span_id' do
|
84
|
+
response = freddy.deliver_with_response(destination, {})
|
85
|
+
trace_initiator = response.fetch(:trace_initiator)
|
86
|
+
current_receiver = response.fetch(:current_receiver)
|
87
|
+
expect(current_receiver.fetch(:span_id)).to_not be_nil
|
88
|
+
expect(current_receiver.fetch(:span_id)).to_not eq(trace_initiator.fetch(:span_id))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when receiving a nested traced request' do
|
93
|
+
let(:freddy) { Freddy.build(logger, config) }
|
94
|
+
let(:freddy2) { Freddy.build(logger, config) }
|
95
|
+
let(:freddy3) { Freddy.build(logger, config) }
|
96
|
+
|
97
|
+
let(:destination) { random_destination }
|
98
|
+
let(:destination2) { random_destination }
|
99
|
+
let(:destination3) { random_destination }
|
100
|
+
|
101
|
+
before do
|
102
|
+
freddy.respond_to(destination) do |payload, msg_handler|
|
103
|
+
msg_handler.success({
|
104
|
+
trace_initiator: {
|
105
|
+
trace_id: Freddy.trace.id,
|
106
|
+
parent_id: Freddy.trace.parent_id,
|
107
|
+
span_id: Freddy.trace.span_id
|
108
|
+
}
|
109
|
+
}.merge(freddy.deliver_with_response(destination2, {})))
|
110
|
+
end
|
111
|
+
|
112
|
+
freddy2.respond_to(destination2) do |payload, msg_handler|
|
113
|
+
msg_handler.success({
|
114
|
+
previous_receiver: {
|
115
|
+
trace_id: Freddy.trace.id,
|
116
|
+
parent_id: Freddy.trace.parent_id,
|
117
|
+
span_id: Freddy.trace.span_id
|
118
|
+
},
|
119
|
+
current_receiver: freddy2.deliver_with_response(destination3, {})
|
120
|
+
})
|
121
|
+
end
|
122
|
+
|
123
|
+
freddy3.respond_to(destination3) do |payload, msg_handler|
|
124
|
+
msg_handler.success({
|
125
|
+
trace_id: Freddy.trace.id,
|
126
|
+
parent_id: Freddy.trace.parent_id,
|
127
|
+
span_id: Freddy.trace.span_id
|
128
|
+
})
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
after do
|
133
|
+
freddy.close
|
134
|
+
freddy2.close
|
135
|
+
freddy3.close
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'has trace_id from the trace initiator' do
|
139
|
+
response = freddy.deliver_with_response(destination, {})
|
140
|
+
trace_initiator = response.fetch(:trace_initiator)
|
141
|
+
current_receiver = response.fetch(:current_receiver)
|
142
|
+
expect(trace_initiator.fetch(:trace_id)).to eq(current_receiver.fetch(:trace_id))
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'has request initiator span_id as parent_id' do
|
146
|
+
response = freddy.deliver_with_response(destination, {})
|
147
|
+
previous_receiver = response.fetch(:previous_receiver)
|
148
|
+
current_receiver = response.fetch(:current_receiver)
|
149
|
+
expect(previous_receiver.fetch(:span_id)).to eq(current_receiver.fetch(:parent_id))
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'has generated span_id' do
|
153
|
+
response = freddy.deliver_with_response(destination, {})
|
154
|
+
previous_receiver = response.fetch(:previous_receiver)
|
155
|
+
current_receiver = response.fetch(:current_receiver)
|
156
|
+
expect(current_receiver.fetch(:span_id)).to_not be_nil
|
157
|
+
expect(current_receiver.fetch(:span_id)).to_not eq(previous_receiver.fetch(:span_id))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freddy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.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-
|
11
|
+
date: 2017-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- lib/freddy/responder_handler.rb
|
121
121
|
- lib/freddy/sync_response_container.rb
|
122
122
|
- lib/freddy/timeout_error.rb
|
123
|
+
- lib/freddy/traces.rb
|
123
124
|
- spec/freddy/consumers/respond_to_consumer_spec.rb
|
124
125
|
- spec/freddy/error_response_spec.rb
|
125
126
|
- spec/freddy/freddy_spec.rb
|
@@ -127,10 +128,12 @@ files:
|
|
127
128
|
- spec/freddy/payload_spec.rb
|
128
129
|
- spec/freddy/responder_handler_spec.rb
|
129
130
|
- spec/freddy/sync_response_container_spec.rb
|
131
|
+
- spec/freddy/traces/trace_id_spec.rb
|
130
132
|
- spec/integration/concurrency_spec.rb
|
131
133
|
- spec/integration/logging_spec.rb
|
132
134
|
- spec/integration/reply_spec.rb
|
133
135
|
- spec/integration/tap_into_with_group_spec.rb
|
136
|
+
- spec/integration/tracing_spec.rb
|
134
137
|
- spec/spec_helper.rb
|
135
138
|
homepage:
|
136
139
|
licenses:
|
@@ -164,8 +167,10 @@ test_files:
|
|
164
167
|
- spec/freddy/payload_spec.rb
|
165
168
|
- spec/freddy/responder_handler_spec.rb
|
166
169
|
- spec/freddy/sync_response_container_spec.rb
|
170
|
+
- spec/freddy/traces/trace_id_spec.rb
|
167
171
|
- spec/integration/concurrency_spec.rb
|
168
172
|
- spec/integration/logging_spec.rb
|
169
173
|
- spec/integration/reply_spec.rb
|
170
174
|
- spec/integration/tap_into_with_group_spec.rb
|
175
|
+
- spec/integration/tracing_spec.rb
|
171
176
|
- spec/spec_helper.rb
|