dispatch-rider 1.6.1 → 1.6.2
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/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
|