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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20ecab8e18af62e4795b431f0860148f5929277c
4
- data.tar.gz: b87e0c608b4ee99a1e85279bf9d42afc5b4e8b53
3
+ metadata.gz: 697069b0aff03bae879decd081323fe5c90441b1
4
+ data.tar.gz: 25ae5e9c896c920864800e9dea6e7421cafe3aee
5
5
  SHA512:
6
- metadata.gz: 9e645f3c4257d14f8d17e1402ec5ef73ceee737b380ffa531391a010ad28e11fba30baa806af34d1d21f518583fd6bc44651fc65e5bc36a7f698f50c4edc1158
7
- data.tar.gz: 8aa77e404a4caa1680def056db848c6c124c1e1ee935278770b9a35c8e278100a23c5b347b80c2bdadc5c62c3e2b8a494b8f2f5850af531abc46299b824811ea
6
+ metadata.gz: a0496f4be0ffffa3bcf025abc4a92dd8fc42c621a667bf8c69841120a8472cf0c37f37663b2fc0226b59b7e01990219eb8eec528fcb851974f0848eb4f6af445
7
+ data.tar.gz: 407419063fd8c30148d644156ddbaba8342250f9310dc6323d5affa259ec15dcf2ba9694893d209530f978ff7fb5cee5c21551b8d00652c71584fbcc47b8a3b8
data/Gemfile CHANGED
@@ -15,6 +15,7 @@ gem 'yard'
15
15
 
16
16
  # Testing
17
17
  gem "rspec", "~> 3.3"
18
+ gem "factory_girl"
18
19
 
19
20
  # CI
20
21
  gem "travis-lint"
@@ -1,6 +1,16 @@
1
1
  module DispatchRider
2
2
  class Configuration
3
- attr_accessor :handler_path, :error_handler, :queue_info, :queue_kind, :subscriber, :logger, :log_formatter, :debug
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
 
@@ -4,7 +4,7 @@ module DispatchRider
4
4
  end
5
5
  end
6
6
 
7
+ require_relative 'logging/translator'
7
8
  require_relative 'logging/lifecycle_logger'
8
- require_relative 'logging/base_formatter'
9
9
  require_relative 'logging/text_formatter'
10
10
  require_relative 'logging/json_formatter'
@@ -3,79 +3,12 @@ require 'json'
3
3
  # JSON Log Formatter
4
4
  module DispatchRider
5
5
  module Logging
6
- class JsonFormatter < BaseFormatter
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 format_duration(duration)
55
- duration
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
- logger.error formatter.format_error_handler_fail(message, exception)
6
+ new(:error_handler_fail, message, exception: exception).log
7
7
  end
8
8
 
9
9
  def log_got_stop(reason, message)
10
- logger.info formatter.format_got_stop(message, reason)
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
- logger.info formatter.format_handling :complete, message, duration: duration
28
+ new(:complete, message, duration: duration).log
29
29
  end
30
30
 
31
31
  def log_fail(message, exception)
32
- logger.error formatter.format_handling :fail, message, exception: exception
32
+ new(:fail, message, exception: exception).log
33
33
  end
34
34
 
35
35
  def log_success(message)
36
- logger.info formatter.format_handling :success, message
36
+ new(:success, message).log
37
37
  end
38
38
 
39
39
  def log_start(message)
40
- logger.info formatter.format_handling :start, message
40
+ new(:start, message).log
41
41
  end
42
+ end
42
43
 
43
- def formatter
44
- DispatchRider.config.log_formatter
45
- end
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
- def logger
48
- DispatchRider.config.logger
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 < BaseFormatter
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
- # @param [Symbol] kind of log action. one of: :start, :success, :fail, :complete
20
- # @param [DispatchRider::QueueServices::ReceivedMessage] message
21
- # @param [Exception] exception
22
- # @param [Float] Job execution duration
23
- # @return [String] log item
24
- def format_handling(kind, message, exception: nil, duration: nil)
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(message)}"
13
+ "Starting execution of: #{message_info_fragment(data)}"
28
14
  when :success
29
- "Succeeded execution of: #{message_info_fragment(message)}"
30
- when :fail
31
- "Failed execution of: #{exception_info_fragment(message, exception)}"
32
- when :complete
33
- "Completed execution of: #{message_info_fragment(message)} in #{format_duration(duration)} seconds"
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(message)
40
- "(#{message.guid}): #{message.subject} : #{message_info_arguments(message).inspect}"
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(message, exception)
44
- "(#{message.guid}): #{message.subject} with #{exception.class}: #{exception.message}"
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,10 @@
1
+ module DispatchRider
2
+ module Logging
3
+ class Translator
4
+
5
+ class ErrorHandlerFailTranslator < FailTranslator
6
+ end
7
+
8
+ end
9
+ end
10
+ 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,13 @@
1
+ module DispatchRider
2
+ module Logging
3
+ class Translator
4
+
5
+ class StartTranslator < BaseTranslator
6
+ def translate
7
+ message_info_fragment(@message)
8
+ end
9
+ end
10
+
11
+ end
12
+ end
13
+ 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
+ module DispatchRider
2
+ module Logging
3
+ class Translator
4
+
5
+ class SuccessTranslator < StartTranslator
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -1,4 +1,4 @@
1
1
  # This file specifies the current version of the gem.
2
2
  module DispatchRider
3
- VERSION = "1.6.1"
3
+ VERSION = "1.6.2"
4
4
  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
@@ -97,7 +97,7 @@ describe "Logging" do
97
97
  'guid' => 'test-mode-not-random-guid',
98
98
  'subject' => 'crashing_handler',
99
99
  'body' => {},
100
- 'expection' => {
100
+ 'exception' => {
101
101
  'class' => 'RuntimeError',
102
102
  'message' => 'I crashed!',
103
103
  },
@@ -1,72 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DispatchRider::Logging::JsonFormatter do
4
- let(:fs_message) { DispatchRider::Message.new(subject: 'test', body: { 'key' => 'value', 'guid' => 123 }) }
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(:result_object) do
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
- example { expect(formatted_message).to eq(formatted_message) }
70
- end
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(:message) { DispatchRider::Message.new(subject: 'test', body: 'test_handler') }
7
- let(:string_to_log) { "string to log" }
8
- let(:exception) { StandardError.new }
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) { DispatchRider.config.logger }
14
+ let(:logger) { double :logger }
13
15
 
14
16
  before do
15
- allow(formatter).to receive(:format_got_stop).and_return(string_to_log)
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
- context "log_error_handler_fail" do
21
- after { subject.log_error_handler_fail message, exception }
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 "log_got_stop" do
29
- after { subject.log_got_stop reason, message }
24
+ context 'when log formatter is json' do
25
+ before { DispatchRider.config.log_formatter = DispatchRider::Logging::JsonFormatter.new }
30
26
 
31
- it "calls logger with info" do
32
- expect(logger).to receive(:info).with(string_to_log)
33
- end
34
- end
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
- context "wrap_handling" do
37
- context "block runs successfully" do
38
- let(:block) { Proc.new { true } }
39
- after { subject.wrap_handling(message, &block) }
36
+ before do
37
+ DispatchRider.config.additional_info_injector = additional_info_injector
38
+ end
40
39
 
41
- it "logs start" do
42
- expect(subject).to receive(:log_start).with(message)
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
- it "logs success" do
46
- expect(subject).to receive(:log_success).with(message)
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
- it "logs complete" do
50
- expect(subject).to receive(:log_complete).with(message, an_instance_of(Float))
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 "block fails" do
55
- let(:block) { Proc.new { raise exception } }
56
- after do
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
- it "logs start" do
61
- expect(subject).to receive(:log_start).with(message)
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
- it "logs fail" do
65
- expect(subject).to receive(:log_fail).with(message, exception)
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
- it "logs complete" do
69
- expect(subject).to receive(:log_complete).with(message, an_instance_of(Float))
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
- let(:fs_message) { DispatchRider::Message.new(subject: 'test', body: { 'key' => 'value', 'guid' => 123 }) }
5
- let(:item) { double :item }
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
- context "format_error_handler_fail" do
19
- let(:formatted_message) { "Failed error handling of: string to log" }
20
- example do
21
- expect(subject.format_error_handler_fail(message, exception)).to eq(formatted_message)
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
- context "format_got_stop" do
26
- let(:formatted_message) { "Got stop (Stop reason) while executing: string to log" }
27
- example do
28
- expect(subject.format_got_stop(message, reason)).to eq(formatted_message)
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
- context "format_handling" do
33
- context "start" do
34
- let(:formatted_message) { "Starting execution of: string to log" }
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(subject.format_handling(:start, message)).to eq(formatted_message)
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 "success" do
41
- let(:formatted_message) { "Succeeded execution of: string to log" }
36
+ context 'when phase is :start' do
37
+ let(:phase) { :start }
38
+
42
39
  example do
43
- expect(subject.format_handling(:success, message)).to eq(formatted_message)
40
+ expect(format_result).to eq("Starting execution of: (123): sample_handler : {:foo=>:bar}")
44
41
  end
45
42
  end
46
43
 
47
- context "complete" do
48
- let(:formatted_message) { "Completed execution of: string to log in 2.12 seconds" }
44
+ context 'when phase is :success' do
45
+ let(:phase) { :success }
46
+
49
47
  example do
50
- expect(subject.format_handling(:complete, message, duration: 2.12)).to eq(formatted_message)
48
+ expect(format_result).to eq("Succeeded execution of: (123): sample_handler : {:foo=>:bar}")
51
49
  end
52
50
  end
53
51
 
54
- context "fail" do
55
- let(:formatted_message) { "Failed execution of: string to log" }
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(subject.format_handling(:fail, message, exception: exception)).to eq(formatted_message)
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.1
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-24 00:00:00.000000000 Z
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