dispatch-rider 1.6.1 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/dispatch-rider/configuration.rb +12 -1
- data/lib/dispatch-rider/logging.rb +1 -1
- data/lib/dispatch-rider/logging/json_formatter.rb +3 -70
- data/lib/dispatch-rider/logging/lifecycle_logger.rb +53 -11
- data/lib/dispatch-rider/logging/text_formatter.rb +31 -31
- data/lib/dispatch-rider/logging/translator.rb +26 -0
- data/lib/dispatch-rider/logging/translator/base_translator.rb +44 -0
- data/lib/dispatch-rider/logging/translator/complete_translator.rb +18 -0
- data/lib/dispatch-rider/logging/translator/error_handler_fail_translator.rb +10 -0
- data/lib/dispatch-rider/logging/translator/fail_translator.rb +18 -0
- data/lib/dispatch-rider/logging/translator/start_translator.rb +13 -0
- data/lib/dispatch-rider/logging/translator/stop_translator.rb +18 -0
- data/lib/dispatch-rider/logging/translator/success_translator.rb +10 -0
- data/lib/dispatch-rider/version.rb +1 -1
- data/spec/factories/messages.rb +10 -0
- data/spec/integration/logging_spec.rb +1 -1
- data/spec/lib/dispatch-rider/logging/json_formatter_spec.rb +4 -65
- data/spec/lib/dispatch-rider/logging/lifecycle_logger_spec.rb +136 -40
- data/spec/lib/dispatch-rider/logging/text_formatter_spec.rb +49 -36
- data/spec/lib/dispatch-rider/logging/translator_spec.rb +160 -0
- data/spec/spec_helper.rb +5 -0
- metadata +14 -3
- data/lib/dispatch-rider/logging/base_formatter.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 697069b0aff03bae879decd081323fe5c90441b1
|
4
|
+
data.tar.gz: 25ae5e9c896c920864800e9dea6e7421cafe3aee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0496f4be0ffffa3bcf025abc4a92dd8fc42c621a667bf8c69841120a8472cf0c37f37663b2fc0226b59b7e01990219eb8eec528fcb851974f0848eb4f6af445
|
7
|
+
data.tar.gz: 407419063fd8c30148d644156ddbaba8342250f9310dc6323d5affa259ec15dcf2ba9694893d209530f978ff7fb5cee5c21551b8d00652c71584fbcc47b8a3b8
|
data/Gemfile
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
module DispatchRider
|
2
2
|
class Configuration
|
3
|
-
attr_accessor
|
3
|
+
attr_accessor(
|
4
|
+
:handler_path,
|
5
|
+
:error_handler,
|
6
|
+
:queue_info,
|
7
|
+
:queue_kind,
|
8
|
+
:subscriber,
|
9
|
+
:logger,
|
10
|
+
:log_formatter,
|
11
|
+
:debug,
|
12
|
+
:additional_info_injector
|
13
|
+
)
|
4
14
|
attr_reader :callbacks
|
5
15
|
|
6
16
|
def initialize
|
@@ -11,6 +21,7 @@ module DispatchRider
|
|
11
21
|
@callbacks = Callbacks::Storage.new
|
12
22
|
@subscriber = DispatchRider::Subscriber
|
13
23
|
@log_formatter = DispatchRider::Logging::TextFormatter.new
|
24
|
+
@additional_info_injector = -> (data) { data }
|
14
25
|
@logger = Logger.new(STDERR)
|
15
26
|
@debug = false
|
16
27
|
|
@@ -3,79 +3,12 @@ require 'json'
|
|
3
3
|
# JSON Log Formatter
|
4
4
|
module DispatchRider
|
5
5
|
module Logging
|
6
|
-
class JsonFormatter
|
7
|
-
# @param [DispatchRider::QueueServices::ReceivedMessage] message
|
8
|
-
# @param [Exception] exception
|
9
|
-
# @return [String] JSON representation of the log item
|
10
|
-
def format_error_handler_fail(message, exception)
|
11
|
-
as_json do
|
12
|
-
{
|
13
|
-
phase: :failed,
|
14
|
-
}.merge exception_info_fragment(message, exception)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# @param [DispatchRider::QueueServices::ReceivedMessage] message
|
19
|
-
# @param [String] reason
|
20
|
-
# @return [String] JSON representation of the log item
|
21
|
-
def format_got_stop(message, reason)
|
22
|
-
as_json do
|
23
|
-
{
|
24
|
-
phase: :stop,
|
25
|
-
reason: reason,
|
26
|
-
}.merge message_info_fragment(message)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# @param [Symbol] kind of log action. one of: :start, :success, :fail, :complete
|
31
|
-
# @param [DispatchRider::QueueServices::ReceivedMessage] message
|
32
|
-
# @param [Exception] exception
|
33
|
-
# @param [Float] Job execution duration
|
34
|
-
# @return [String] JSON representation of the log item
|
35
|
-
def format_handling(kind, message, exception: nil, duration: nil)
|
36
|
-
as_json do
|
37
|
-
fragment = case kind
|
38
|
-
when :start
|
39
|
-
message_info_fragment(message)
|
40
|
-
when :success
|
41
|
-
message_info_fragment(message)
|
42
|
-
when :fail
|
43
|
-
exception_info_fragment(message, exception)
|
44
|
-
when :complete
|
45
|
-
duration_fragment = { duration: format_duration(duration) }
|
46
|
-
message_info_fragment(message).merge duration_fragment
|
47
|
-
end
|
48
|
-
{ phase: kind }.merge fragment
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
6
|
+
class JsonFormatter
|
53
7
|
|
54
|
-
def
|
55
|
-
|
8
|
+
def format(data)
|
9
|
+
data.to_json
|
56
10
|
end
|
57
11
|
|
58
|
-
def as_json
|
59
|
-
JSON.generate yield
|
60
|
-
end
|
61
|
-
|
62
|
-
def message_info_fragment(message)
|
63
|
-
{
|
64
|
-
guid: message.guid.to_s,
|
65
|
-
subject: message.subject,
|
66
|
-
body: message_info_arguments(message),
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
|
-
def exception_info_fragment(message, exception)
|
71
|
-
exception_details = {
|
72
|
-
expection: {
|
73
|
-
class: exception.class.to_s,
|
74
|
-
message: exception.message,
|
75
|
-
}
|
76
|
-
}
|
77
|
-
message_info_fragment(message).merge exception_details
|
78
|
-
end
|
79
12
|
end
|
80
13
|
end
|
81
14
|
end
|
@@ -3,11 +3,11 @@ module DispatchRider
|
|
3
3
|
class LifecycleLogger
|
4
4
|
class << self
|
5
5
|
def log_error_handler_fail(message, exception)
|
6
|
-
|
6
|
+
new(:error_handler_fail, message, exception: exception).log
|
7
7
|
end
|
8
8
|
|
9
9
|
def log_got_stop(reason, message)
|
10
|
-
|
10
|
+
new(:stop, message, reason: reason).log
|
11
11
|
end
|
12
12
|
|
13
13
|
def wrap_handling(message)
|
@@ -25,29 +25,71 @@ module DispatchRider
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def log_complete(message, duration)
|
28
|
-
|
28
|
+
new(:complete, message, duration: duration).log
|
29
29
|
end
|
30
30
|
|
31
31
|
def log_fail(message, exception)
|
32
|
-
|
32
|
+
new(:fail, message, exception: exception).log
|
33
33
|
end
|
34
34
|
|
35
35
|
def log_success(message)
|
36
|
-
|
36
|
+
new(:success, message).log
|
37
37
|
end
|
38
38
|
|
39
39
|
def log_start(message)
|
40
|
-
|
40
|
+
new(:start, message).log
|
41
41
|
end
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
def initialize(kind, message, options = {})
|
45
|
+
@kind = kind
|
46
|
+
@message = message
|
47
|
+
@options = options
|
48
|
+
end
|
49
|
+
|
50
|
+
def log
|
51
|
+
logger.send(log_action, formatted_data)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
attr_reader :kind, :message, :options
|
57
|
+
|
58
|
+
def formatter
|
59
|
+
DispatchRider.config.log_formatter
|
60
|
+
end
|
61
|
+
|
62
|
+
def logger
|
63
|
+
DispatchRider.config.logger
|
64
|
+
end
|
46
65
|
|
47
|
-
|
48
|
-
|
66
|
+
def additional_info_injector
|
67
|
+
DispatchRider.config.additional_info_injector
|
68
|
+
end
|
69
|
+
|
70
|
+
def translator
|
71
|
+
Translator
|
72
|
+
end
|
73
|
+
|
74
|
+
def translated_message
|
75
|
+
translator.translate(message, kind, options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def interjected_message
|
79
|
+
additional_info_injector.call(translated_message)
|
80
|
+
end
|
81
|
+
|
82
|
+
def formatted_data
|
83
|
+
formatter.format(interjected_message)
|
84
|
+
end
|
85
|
+
|
86
|
+
def log_action
|
87
|
+
case kind
|
88
|
+
when :fail, :error_handler_fail then :error
|
89
|
+
when :start, :stop, :complete, :success then :info
|
49
90
|
end
|
50
91
|
end
|
92
|
+
|
51
93
|
end
|
52
94
|
end
|
53
95
|
end
|
@@ -1,48 +1,48 @@
|
|
1
1
|
# Text Log Formatter
|
2
2
|
module DispatchRider
|
3
3
|
module Logging
|
4
|
-
class TextFormatter
|
5
|
-
# @param [DispatchRider::QueueServices::ReceivedMessage] message
|
6
|
-
# @param [Exception] exception
|
7
|
-
# @return [String] log item
|
8
|
-
def format_error_handler_fail(message, exception)
|
9
|
-
"Failed error handling of: #{exception_info_fragment(message, exception)}"
|
10
|
-
end
|
11
|
-
|
12
|
-
# @param [DispatchRider::QueueServices::ReceivedMessage] message
|
13
|
-
# @param [String] reason
|
14
|
-
# @return [String] log item
|
15
|
-
def format_got_stop(message, reason)
|
16
|
-
"Got stop #{reason ? '(' + reason + ') ' : ' ' }while executing: #{message_info_fragment(message)}"
|
17
|
-
end
|
4
|
+
class TextFormatter
|
18
5
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
case kind
|
6
|
+
def format(data)
|
7
|
+
case data[:phase]
|
8
|
+
when :complete
|
9
|
+
"Completed execution of: #{message_info_fragment(data)} in #{format_duration(data[:duration])} seconds"
|
10
|
+
when :fail
|
11
|
+
"Failed execution of: #{exception_info_fragment(data)}"
|
26
12
|
when :start
|
27
|
-
"Starting execution of: #{message_info_fragment(
|
13
|
+
"Starting execution of: #{message_info_fragment(data)}"
|
28
14
|
when :success
|
29
|
-
"Succeeded execution of: #{message_info_fragment(
|
30
|
-
when :
|
31
|
-
"
|
32
|
-
when :
|
33
|
-
"
|
15
|
+
"Succeeded execution of: #{message_info_fragment(data)}"
|
16
|
+
when :stop
|
17
|
+
"Got stop #{data[:reason] ? '(' + data[:reason] + ')' : '' } while executing: #{message_info_fragment(data)}"
|
18
|
+
when :error_handler_fail
|
19
|
+
"Failed error handling of: #{exception_info_fragment(data)}"
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Invalid phase : #{data[:phase].inspect}"
|
34
22
|
end
|
35
23
|
end
|
36
24
|
|
37
25
|
private
|
38
26
|
|
39
|
-
def message_info_fragment(
|
40
|
-
"(#{
|
27
|
+
def message_info_fragment(data)
|
28
|
+
"(#{data[:guid]}): #{data[:subject]} : #{message_info_arguments(data[:body]).inspect}"
|
41
29
|
end
|
42
30
|
|
43
|
-
def exception_info_fragment(
|
44
|
-
"(#{
|
31
|
+
def exception_info_fragment(data)
|
32
|
+
"(#{data[:guid]}): #{data[:subject]} with #{data[:exception][:class]}: #{data[:exception][:message]}"
|
45
33
|
end
|
34
|
+
|
35
|
+
def message_info_arguments(body)
|
36
|
+
body.dup.tap do |m|
|
37
|
+
m.delete('guid')
|
38
|
+
m.delete('object_id')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_duration(duration)
|
43
|
+
'%.2f' % [duration]
|
44
|
+
end
|
45
|
+
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DispatchRider
|
2
|
+
module Logging
|
3
|
+
|
4
|
+
# Translates a message into a loggable hash based on its result.
|
5
|
+
class Translator
|
6
|
+
def self.translate(message, kind, **args)
|
7
|
+
klass = translator_class(kind)
|
8
|
+
fragment = klass.new(message, **args).translate
|
9
|
+
{ phase: kind }.merge fragment
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.translator_class(kind)
|
13
|
+
const_get("#{kind}_translator".classify)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require_relative 'translator/base_translator'
|
21
|
+
require_relative 'translator/complete_translator'
|
22
|
+
require_relative 'translator/fail_translator'
|
23
|
+
require_relative 'translator/error_handler_fail_translator'
|
24
|
+
require_relative 'translator/start_translator'
|
25
|
+
require_relative 'translator/stop_translator'
|
26
|
+
require_relative 'translator/success_translator'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module DispatchRider
|
2
|
+
module Logging
|
3
|
+
class Translator
|
4
|
+
|
5
|
+
class BaseTranslator
|
6
|
+
def initialize(message, **)
|
7
|
+
@message = message
|
8
|
+
end
|
9
|
+
|
10
|
+
def translate
|
11
|
+
raise NotImplementedError, 'Translators must implement #translate'
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def message_info_fragment(message)
|
17
|
+
{
|
18
|
+
guid: message.guid.to_s,
|
19
|
+
subject: message.subject,
|
20
|
+
body: message_info_arguments(message),
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_info_arguments(message)
|
25
|
+
message.body.dup.tap do |m|
|
26
|
+
m.delete('guid')
|
27
|
+
m.delete('object_id')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def exception_info_fragment(message, exception)
|
32
|
+
exception_details = {
|
33
|
+
exception: {
|
34
|
+
class: exception.class.to_s,
|
35
|
+
message: exception.message,
|
36
|
+
}
|
37
|
+
}
|
38
|
+
message_info_fragment(message).merge exception_details
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DispatchRider
|
2
|
+
module Logging
|
3
|
+
class Translator
|
4
|
+
|
5
|
+
class CompleteTranslator < BaseTranslator
|
6
|
+
def initialize(message, duration:)
|
7
|
+
super(message)
|
8
|
+
@duration = duration
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate
|
12
|
+
message_info_fragment(@message).merge duration: @duration
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DispatchRider
|
2
|
+
module Logging
|
3
|
+
class Translator
|
4
|
+
|
5
|
+
class FailTranslator < BaseTranslator
|
6
|
+
def initialize(message, exception:)
|
7
|
+
super(message)
|
8
|
+
@exception = exception
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate
|
12
|
+
exception_info_fragment(@message, @exception)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DispatchRider
|
2
|
+
module Logging
|
3
|
+
class Translator
|
4
|
+
|
5
|
+
class StopTranslator < BaseTranslator
|
6
|
+
def initialize(message, reason:)
|
7
|
+
super(message)
|
8
|
+
@reason = reason
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate
|
12
|
+
message_info_fragment(@message).merge reason: @reason
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :message, class: 'DispatchRider::Message' do
|
3
|
+
subject 'sample_handler'
|
4
|
+
body(
|
5
|
+
'key' => 'value',
|
6
|
+
'guid' => DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
7
|
+
)
|
8
|
+
initialize_with { DispatchRider::Message.new(attributes) }
|
9
|
+
end
|
10
|
+
end
|
@@ -1,72 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe DispatchRider::Logging::JsonFormatter do
|
4
|
-
let(:
|
5
|
-
let(:item) { double :item }
|
6
|
-
let(:queue) { double :queue }
|
7
|
-
let(:message) { DispatchRider::QueueServices::FileSystem::FsReceivedMessage.new(fs_message, item, queue) }
|
8
|
-
let(:exception) { StandardError.new }
|
9
|
-
let(:reason) { "Stop reason" }
|
4
|
+
let(:data) { { some: :data } }
|
10
5
|
|
11
|
-
let(:
|
12
|
-
{
|
13
|
-
"subject" => "test",
|
14
|
-
"guid" => "123",
|
15
|
-
"body" => {
|
16
|
-
"key" => "value"
|
17
|
-
},
|
18
|
-
}
|
19
|
-
end
|
20
|
-
let(:result_exception) do
|
21
|
-
{
|
22
|
-
"expection" => {
|
23
|
-
"class" => "StandardError",
|
24
|
-
"message" => "StandardError"
|
25
|
-
}
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
context "format_error_handler_fail" do
|
30
|
-
let(:formatted_message) { result_object.merge("phase" => "failed").merge(result_exception) }
|
31
|
-
let(:result_message) { JSON.parse subject.format_error_handler_fail(message, exception) }
|
32
|
-
|
33
|
-
example { expect(result_message).to eq(formatted_message) }
|
34
|
-
end
|
35
|
-
|
36
|
-
context "format_got_stop" do
|
37
|
-
let(:formatted_message) { result_object.merge("phase" => "stop", "reason" => reason) }
|
38
|
-
let(:result_message) { JSON.parse subject.format_got_stop(message, reason) }
|
39
|
-
|
40
|
-
example { expect(result_message).to eq(formatted_message) }
|
41
|
-
end
|
42
|
-
|
43
|
-
context "format_handling" do
|
44
|
-
context "start" do
|
45
|
-
let(:formatted_message) { result_object.merge("phase" => "start") }
|
46
|
-
let(:result_message) { JSON.parse subject.format_handling(:start, message) }
|
47
|
-
|
48
|
-
example { expect(result_message).to eq(formatted_message) }
|
49
|
-
end
|
50
|
-
|
51
|
-
context "success" do
|
52
|
-
let(:formatted_message) { result_object.merge("phase" => "success") }
|
53
|
-
let(:result_message) { JSON.parse subject.format_handling(:success, message) }
|
54
|
-
|
55
|
-
example { expect(result_message).to eq(formatted_message) }
|
56
|
-
end
|
57
|
-
|
58
|
-
context "complete" do
|
59
|
-
let(:formatted_message) { result_object.merge("phase" => "complete", "duration" => 2.0) }
|
60
|
-
let(:result_message) { JSON.parse subject.format_handling(:complete, message, duration: 2.0) }
|
61
|
-
|
62
|
-
example { expect(result_message).to eq(formatted_message) }
|
63
|
-
end
|
64
|
-
|
65
|
-
context "fail" do
|
66
|
-
let(:formatted_message) { result_object.merge("phase" => "fail").merge(result_exception) }
|
67
|
-
let(:result_message) { JSON.parse subject.format_handling(:fail, message, exception: exception) }
|
6
|
+
let(:formatted_data) { %{{"some":"data"}} }
|
68
7
|
|
69
|
-
|
70
|
-
|
8
|
+
example do
|
9
|
+
expect(described_class.new.format(data)).to eq(formatted_data)
|
71
10
|
end
|
72
11
|
end
|
@@ -1,72 +1,168 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe DispatchRider::Logging::LifecycleLogger do
|
3
|
+
describe DispatchRider::Logging::LifecycleLogger, aggregrate_failures: true do
|
4
4
|
subject { DispatchRider::Logging::LifecycleLogger }
|
5
5
|
|
6
|
-
let(:
|
7
|
-
let(:
|
8
|
-
let(:
|
6
|
+
let(:queue) { double :queue }
|
7
|
+
let(:item) { double :item }
|
8
|
+
let(:fs_message) { DispatchRider::QueueServices::FileSystem::FsReceivedMessage.new(message, item, queue) }
|
9
|
+
let(:message) { DispatchRider::Message.new(subject: 'test', body: { 'guid' => '123', 'some' => 'key' }) }
|
10
|
+
let(:exception) { StandardError.new('something failed') }
|
9
11
|
let(:reason) { "Stop reason" }
|
10
12
|
|
11
13
|
let(:formatter) { DispatchRider.config.log_formatter }
|
12
|
-
let(:logger) {
|
14
|
+
let(:logger) { double :logger }
|
13
15
|
|
14
16
|
before do
|
15
|
-
|
16
|
-
allow(formatter).to receive(:format_error_handler_fail).and_return(string_to_log)
|
17
|
-
allow(formatter).to receive(:format_handling).and_return(string_to_log)
|
17
|
+
DispatchRider.config.logger = logger
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
it "calls logger with error" do
|
24
|
-
expect(logger).to receive(:error).with(string_to_log)
|
25
|
-
end
|
20
|
+
after do
|
21
|
+
DispatchRider.clear_configuration!
|
26
22
|
end
|
27
23
|
|
28
|
-
context
|
29
|
-
|
24
|
+
context 'when log formatter is json' do
|
25
|
+
before { DispatchRider.config.log_formatter = DispatchRider::Logging::JsonFormatter.new }
|
30
26
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
context 'when additional_info_injector is customized' do
|
28
|
+
let(:additional_info_injector) do
|
29
|
+
-> (message) do
|
30
|
+
message[:employee_id] = 47
|
31
|
+
message[:account_id] = 42
|
32
|
+
message
|
33
|
+
end
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
after { subject.wrap_handling(message, &block) }
|
36
|
+
before do
|
37
|
+
DispatchRider.config.additional_info_injector = additional_info_injector
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
describe 'log_error_handler_fail' do
|
41
|
+
let(:expected_info) do
|
42
|
+
{
|
43
|
+
phase: 'error_handler_fail',
|
44
|
+
guid: '123',
|
45
|
+
subject: 'test',
|
46
|
+
body: { some: 'key' },
|
47
|
+
exception: { class: 'StandardError', message: 'something failed' },
|
48
|
+
employee_id: 47,
|
49
|
+
account_id: 42,
|
50
|
+
}.deep_stringify_keys.to_json
|
51
|
+
end
|
52
|
+
|
53
|
+
it "calls logger with error" do
|
54
|
+
expect(logger).to receive(:error).with(expected_info)
|
55
|
+
subject.log_error_handler_fail fs_message, exception
|
56
|
+
end
|
43
57
|
end
|
44
58
|
|
45
|
-
|
46
|
-
|
59
|
+
describe "log_got_stop" do
|
60
|
+
let(:expected_info) do
|
61
|
+
{
|
62
|
+
phase: 'stop',
|
63
|
+
guid: '123',
|
64
|
+
subject: 'test',
|
65
|
+
body: { some: 'key' },
|
66
|
+
reason: reason,
|
67
|
+
employee_id: 47,
|
68
|
+
account_id: 42,
|
69
|
+
}.deep_stringify_keys.to_json
|
70
|
+
end
|
71
|
+
|
72
|
+
it "calls logger with info" do
|
73
|
+
expect(logger).to receive(:info).with(expected_info)
|
74
|
+
subject.log_got_stop reason, fs_message
|
75
|
+
end
|
47
76
|
end
|
48
77
|
|
49
|
-
|
50
|
-
|
78
|
+
describe "wrap_handling" do
|
79
|
+
let(:expected_start_info) do
|
80
|
+
{
|
81
|
+
phase: 'start',
|
82
|
+
guid: '123',
|
83
|
+
subject: 'test',
|
84
|
+
body: { some: 'key' },
|
85
|
+
employee_id: 47,
|
86
|
+
account_id: 42,
|
87
|
+
}.deep_stringify_keys.to_json
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:expected_succeed_info) do
|
91
|
+
{
|
92
|
+
phase: 'success',
|
93
|
+
guid: '123',
|
94
|
+
subject: 'test',
|
95
|
+
body: { some: 'key' },
|
96
|
+
employee_id: 47,
|
97
|
+
account_id: 42,
|
98
|
+
}.deep_stringify_keys.to_json
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:expected_complete_info) do
|
102
|
+
/{"phase":"complete","guid":"123","subject":"test","body":{"some":"key"},"duration":\d+(?:.\d+)?,"employee_id":47,"account_id":42}/
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'succeeding the handler' do
|
106
|
+
example do
|
107
|
+
expect(logger).to receive(:info).with(expected_start_info)
|
108
|
+
expect(logger).to receive(:info).with(expected_succeed_info)
|
109
|
+
expect(logger).to receive(:info).with(expected_complete_info)
|
110
|
+
expect {
|
111
|
+
subject.wrap_handling(fs_message) { true }
|
112
|
+
}.not_to raise_exception
|
113
|
+
end
|
114
|
+
end
|
51
115
|
end
|
52
116
|
end
|
53
117
|
|
54
|
-
context
|
55
|
-
|
56
|
-
|
57
|
-
expect { subject.wrap_handling(message, &block) }.to raise_error(exception)
|
118
|
+
context 'when log formatter is text based' do
|
119
|
+
before do
|
120
|
+
DispatchRider.config.log_formatter = DispatchRider::Logging::TextFormatter.new
|
58
121
|
end
|
59
122
|
|
60
|
-
|
61
|
-
|
123
|
+
describe "log_error_handler_fail" do
|
124
|
+
it "calls logger with error" do
|
125
|
+
expect(logger).to receive(:error).with(
|
126
|
+
"Failed error handling of: (123): test with StandardError: something failed"
|
127
|
+
)
|
128
|
+
subject.log_error_handler_fail fs_message, exception
|
129
|
+
end
|
62
130
|
end
|
63
131
|
|
64
|
-
|
65
|
-
|
132
|
+
describe "log_got_stop" do
|
133
|
+
it "calls logger with info" do
|
134
|
+
expect(logger).to receive(:info).with(
|
135
|
+
%{Got stop (Stop reason) while executing: (123): test : {"some"=>"key"}})
|
136
|
+
subject.log_got_stop reason, fs_message
|
137
|
+
end
|
66
138
|
end
|
67
139
|
|
68
|
-
|
69
|
-
|
140
|
+
describe "wrap_handling" do
|
141
|
+
context 'succeeding the handler' do
|
142
|
+
example do
|
143
|
+
expect(logger).to receive(:info).with(%{Starting execution of: (123): test : {"some"=>"key"}})
|
144
|
+
expect(logger).to receive(:info).with(%{Succeeded execution of: (123): test : {"some"=>"key"}})
|
145
|
+
expect(logger).to receive(:info).with(
|
146
|
+
/Completed execution of: \(123\): test : {"some"=>"key"} in \d+(?:.\d+)? seconds/
|
147
|
+
)
|
148
|
+
expect {
|
149
|
+
subject.wrap_handling(fs_message) { true }
|
150
|
+
}.not_to raise_exception
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'failing the handler' do
|
155
|
+
example do
|
156
|
+
expect(logger).to receive(:info).with(%{Starting execution of: (123): test : {"some"=>"key"}})
|
157
|
+
expect(logger).to receive(:error).with(%{Failed execution of: (123): test with RuntimeError: failed!})
|
158
|
+
expect(logger).to receive(:info).with(
|
159
|
+
/Completed execution of: \(123\): test : {"some"=>"key"} in \d+(?:.\d+)? seconds/
|
160
|
+
)
|
161
|
+
expect {
|
162
|
+
subject.wrap_handling(fs_message) { raise "failed!" }
|
163
|
+
}.to raise_exception "failed!"
|
164
|
+
end
|
165
|
+
end
|
70
166
|
end
|
71
167
|
end
|
72
168
|
end
|
@@ -1,60 +1,73 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe DispatchRider::Logging::TextFormatter do
|
4
|
-
|
5
|
-
|
6
|
-
let(:queue) { double :queue }
|
7
|
-
let(:message) { DispatchRider::QueueServices::FileSystem::FsReceivedMessage.new(fs_message, item, queue) }
|
8
|
-
|
9
|
-
let(:string_to_log) { "string to log" }
|
10
|
-
let(:exception) { StandardError.new }
|
11
|
-
let(:reason) { "Stop reason" }
|
12
|
-
|
13
|
-
before do
|
14
|
-
allow(subject).to receive(:message_info_fragment).and_return(string_to_log)
|
15
|
-
allow(subject).to receive(:exception_info_fragment).and_return(string_to_log)
|
16
|
-
end
|
4
|
+
describe "#format" do
|
5
|
+
subject(:format_result) { described_class.new.format(data) }
|
17
6
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
let(:data) do
|
8
|
+
{
|
9
|
+
phase: phase,
|
10
|
+
guid: '123',
|
11
|
+
body: { foo: :bar },
|
12
|
+
subject: 'sample_handler',
|
13
|
+
}
|
22
14
|
end
|
23
|
-
end
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
16
|
+
context 'when phase is :complete' do
|
17
|
+
let(:phase) { :complete }
|
18
|
+
|
19
|
+
before { data[:duration] = 10 }
|
20
|
+
|
21
|
+
example do
|
22
|
+
expect(format_result).to eq("Completed execution of: (123): sample_handler : {:foo=>:bar} in 10.00 seconds")
|
23
|
+
end
|
29
24
|
end
|
30
|
-
end
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
context 'when phase is :fail' do
|
27
|
+
let(:phase) { :fail }
|
28
|
+
|
29
|
+
before { data[:exception] = { class: StandardError, message: 'Foo is not bar' } }
|
30
|
+
|
35
31
|
example do
|
36
|
-
expect(
|
32
|
+
expect(format_result).to eq("Failed execution of: (123): sample_handler with StandardError: Foo is not bar")
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
|
-
context
|
41
|
-
let(:
|
36
|
+
context 'when phase is :start' do
|
37
|
+
let(:phase) { :start }
|
38
|
+
|
42
39
|
example do
|
43
|
-
expect(
|
40
|
+
expect(format_result).to eq("Starting execution of: (123): sample_handler : {:foo=>:bar}")
|
44
41
|
end
|
45
42
|
end
|
46
43
|
|
47
|
-
context
|
48
|
-
let(:
|
44
|
+
context 'when phase is :success' do
|
45
|
+
let(:phase) { :success }
|
46
|
+
|
49
47
|
example do
|
50
|
-
expect(
|
48
|
+
expect(format_result).to eq("Succeeded execution of: (123): sample_handler : {:foo=>:bar}")
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
|
-
context
|
55
|
-
let(:
|
52
|
+
context 'when phase is :stop' do
|
53
|
+
let(:phase) { :stop }
|
54
|
+
|
55
|
+
before { data[:reason] = 'Ninja Attack' }
|
56
|
+
|
57
|
+
example do
|
58
|
+
expect(format_result).to eq("Got stop (Ninja Attack) while executing: (123): sample_handler : {:foo=>:bar}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when phase is :error_handler_fail' do
|
63
|
+
let(:phase) { :error_handler_fail }
|
64
|
+
|
65
|
+
before { data[:exception] = { class: StandardError, message: 'Foo is not bar' } }
|
66
|
+
|
56
67
|
example do
|
57
|
-
expect(
|
68
|
+
expect(format_result).to eq(
|
69
|
+
"Failed error handling of: (123): sample_handler with StandardError: Foo is not bar"
|
70
|
+
)
|
58
71
|
end
|
59
72
|
end
|
60
73
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DispatchRider::Logging::Translator do
|
4
|
+
let(:queue) { double :queue }
|
5
|
+
let(:message) { build(:message) }
|
6
|
+
let(:item) { double :item }
|
7
|
+
let(:fs_message) { DispatchRider::QueueServices::FileSystem::FsReceivedMessage.new(message, item, queue) }
|
8
|
+
|
9
|
+
let(:exception) { nil }
|
10
|
+
let(:duration) { nil }
|
11
|
+
let(:reason) { nil }
|
12
|
+
|
13
|
+
describe '.translate' do
|
14
|
+
context 'when the job is starting' do
|
15
|
+
subject(:result) do
|
16
|
+
described_class.translate(fs_message, kind)
|
17
|
+
end
|
18
|
+
let(:kind) { :start }
|
19
|
+
let(:expected_hash) do
|
20
|
+
{
|
21
|
+
phase: :start,
|
22
|
+
subject: 'sample_handler',
|
23
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
24
|
+
body: {
|
25
|
+
'key' => 'value',
|
26
|
+
},
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
example do
|
31
|
+
expect(result).to eq(expected_hash)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when the job has succeeded' do
|
36
|
+
subject(:result) do
|
37
|
+
described_class.translate(fs_message, kind)
|
38
|
+
end
|
39
|
+
let(:kind) { :success }
|
40
|
+
let(:expected_hash) do
|
41
|
+
{
|
42
|
+
phase: :success,
|
43
|
+
subject: 'sample_handler',
|
44
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
45
|
+
body: {
|
46
|
+
'key' => 'value',
|
47
|
+
},
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
example do
|
52
|
+
expect(result).to eq(expected_hash)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the job has failed' do
|
57
|
+
subject(:result) do
|
58
|
+
described_class.translate(fs_message, kind, exception: exception)
|
59
|
+
end
|
60
|
+
let(:kind) { :fail }
|
61
|
+
let(:exception) do
|
62
|
+
ArgumentError.new("Foo is not bar")
|
63
|
+
end
|
64
|
+
|
65
|
+
let(:expected_hash) do
|
66
|
+
{
|
67
|
+
phase: :fail,
|
68
|
+
subject: 'sample_handler',
|
69
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
70
|
+
body: {
|
71
|
+
'key' => 'value',
|
72
|
+
},
|
73
|
+
exception: {
|
74
|
+
class: 'ArgumentError',
|
75
|
+
message: 'Foo is not bar',
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
example do
|
81
|
+
expect(result).to eq(expected_hash)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when the job has completed' do
|
86
|
+
subject(:result) do
|
87
|
+
described_class.translate(fs_message, kind, duration: duration)
|
88
|
+
end
|
89
|
+
let(:kind) { :complete }
|
90
|
+
let(:duration) { 5 }
|
91
|
+
let(:expected_hash) do
|
92
|
+
{
|
93
|
+
phase: :complete,
|
94
|
+
subject: 'sample_handler',
|
95
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
96
|
+
body: {
|
97
|
+
'key' => 'value',
|
98
|
+
},
|
99
|
+
duration: 5,
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
example do
|
104
|
+
expect(result).to eq(expected_hash)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when the error handler fails' do
|
109
|
+
subject(:result) do
|
110
|
+
described_class.translate(fs_message, kind, exception: exception)
|
111
|
+
end
|
112
|
+
let(:kind) { :error_handler_fail }
|
113
|
+
let(:exception) do
|
114
|
+
ArgumentError.new("Foo is not bar")
|
115
|
+
end
|
116
|
+
|
117
|
+
let(:expected_hash) do
|
118
|
+
{
|
119
|
+
phase: :error_handler_fail,
|
120
|
+
subject: 'sample_handler',
|
121
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
122
|
+
body: {
|
123
|
+
'key' => 'value',
|
124
|
+
},
|
125
|
+
exception: {
|
126
|
+
class: 'ArgumentError',
|
127
|
+
message: 'Foo is not bar',
|
128
|
+
}
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
example do
|
133
|
+
expect(result).to eq(expected_hash)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'when the job has completed' do
|
138
|
+
subject(:result) do
|
139
|
+
described_class.translate(fs_message, kind, reason: reason)
|
140
|
+
end
|
141
|
+
let(:kind) { :stop }
|
142
|
+
let(:reason) { "Got TERM" }
|
143
|
+
let(:expected_hash) do
|
144
|
+
{
|
145
|
+
phase: :stop,
|
146
|
+
subject: 'sample_handler',
|
147
|
+
guid: DispatchRider::Debug::PUBLISHER_MESSAGE_GUID,
|
148
|
+
body: {
|
149
|
+
'key' => 'value',
|
150
|
+
},
|
151
|
+
reason: 'Got TERM',
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
example do
|
156
|
+
expect(result).to eq(expected_hash)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -10,6 +10,9 @@ require 'tempfile'
|
|
10
10
|
require 'dispatch-rider'
|
11
11
|
Dir['./spec/support/**/*.rb'].each { |fn| require(fn) }
|
12
12
|
|
13
|
+
FactoryGirl.definition_file_paths = %w{spec/factories/}
|
14
|
+
FactoryGirl.find_definitions
|
15
|
+
|
13
16
|
RSpec.configure do |config|
|
14
17
|
config.raise_errors_for_deprecations!
|
15
18
|
config.mock_with :rspec
|
@@ -25,6 +28,8 @@ RSpec.configure do |config|
|
|
25
28
|
config.before do
|
26
29
|
DispatchRider.config.logger = NullLogger.new
|
27
30
|
end
|
31
|
+
|
32
|
+
config.include FactoryGirl::Syntax::Methods
|
28
33
|
end
|
29
34
|
|
30
35
|
# Airbrake dummy module
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dispatch-rider
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Suman Mukherjee
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-06-
|
14
|
+
date: 2015-06-25 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -115,10 +115,17 @@ files:
|
|
115
115
|
- lib/dispatch-rider/handlers/named_process.rb
|
116
116
|
- lib/dispatch-rider/integrations/appsignal.rb
|
117
117
|
- lib/dispatch-rider/logging.rb
|
118
|
-
- lib/dispatch-rider/logging/base_formatter.rb
|
119
118
|
- lib/dispatch-rider/logging/json_formatter.rb
|
120
119
|
- lib/dispatch-rider/logging/lifecycle_logger.rb
|
121
120
|
- lib/dispatch-rider/logging/text_formatter.rb
|
121
|
+
- lib/dispatch-rider/logging/translator.rb
|
122
|
+
- lib/dispatch-rider/logging/translator/base_translator.rb
|
123
|
+
- lib/dispatch-rider/logging/translator/complete_translator.rb
|
124
|
+
- lib/dispatch-rider/logging/translator/error_handler_fail_translator.rb
|
125
|
+
- lib/dispatch-rider/logging/translator/fail_translator.rb
|
126
|
+
- lib/dispatch-rider/logging/translator/start_translator.rb
|
127
|
+
- lib/dispatch-rider/logging/translator/stop_translator.rb
|
128
|
+
- lib/dispatch-rider/logging/translator/success_translator.rb
|
122
129
|
- lib/dispatch-rider/message.rb
|
123
130
|
- lib/dispatch-rider/notification_services.rb
|
124
131
|
- lib/dispatch-rider/notification_services/aws_sns.rb
|
@@ -163,6 +170,7 @@ files:
|
|
163
170
|
- lib/generators/dispatch_rider/job/templates/handler/handler_spec.rb.erb
|
164
171
|
- lib/generators/dispatch_rider/job/templates/publisher/publisher.rb.erb
|
165
172
|
- lib/generators/dispatch_rider/job/templates/publisher/publisher_spec.rb.erb
|
173
|
+
- spec/factories/messages.rb
|
166
174
|
- spec/fixtures/handlers/another_test_handler.rb
|
167
175
|
- spec/fixtures/handlers/test_handler.rb
|
168
176
|
- spec/integration/logging_spec.rb
|
@@ -178,6 +186,7 @@ files:
|
|
178
186
|
- spec/lib/dispatch-rider/logging/json_formatter_spec.rb
|
179
187
|
- spec/lib/dispatch-rider/logging/lifecycle_logger_spec.rb
|
180
188
|
- spec/lib/dispatch-rider/logging/text_formatter_spec.rb
|
189
|
+
- spec/lib/dispatch-rider/logging/translator_spec.rb
|
181
190
|
- spec/lib/dispatch-rider/message_spec.rb
|
182
191
|
- spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb
|
183
192
|
- spec/lib/dispatch-rider/notification_services/base_spec.rb
|
@@ -240,6 +249,7 @@ specification_version: 4
|
|
240
249
|
summary: Messaging system that is customizable based on which queueing system we are
|
241
250
|
using.
|
242
251
|
test_files:
|
252
|
+
- spec/factories/messages.rb
|
243
253
|
- spec/fixtures/handlers/another_test_handler.rb
|
244
254
|
- spec/fixtures/handlers/test_handler.rb
|
245
255
|
- spec/integration/logging_spec.rb
|
@@ -255,6 +265,7 @@ test_files:
|
|
255
265
|
- spec/lib/dispatch-rider/logging/json_formatter_spec.rb
|
256
266
|
- spec/lib/dispatch-rider/logging/lifecycle_logger_spec.rb
|
257
267
|
- spec/lib/dispatch-rider/logging/text_formatter_spec.rb
|
268
|
+
- spec/lib/dispatch-rider/logging/translator_spec.rb
|
258
269
|
- spec/lib/dispatch-rider/message_spec.rb
|
259
270
|
- spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb
|
260
271
|
- spec/lib/dispatch-rider/notification_services/base_spec.rb
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module DispatchRider
|
2
|
-
module Logging
|
3
|
-
class BaseFormatter
|
4
|
-
def format_error_handler_fail(*)
|
5
|
-
raise NotImplementedError
|
6
|
-
end
|
7
|
-
|
8
|
-
def format_got_stop(*)
|
9
|
-
raise NotImplementedError
|
10
|
-
end
|
11
|
-
|
12
|
-
def format_handling(*)
|
13
|
-
raise NotImplementedError
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def message_info_arguments(message)
|
19
|
-
message.body.dup.tap do |m|
|
20
|
-
m.delete('guid')
|
21
|
-
m.delete('object_id')
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def format_duration(duration)
|
26
|
-
format '%.2f', duration
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|