Skip to content

Commit c418386

Browse files
committed
action mailer
1 parent 1d49b51 commit c418386

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

lib/rails_semantic_logger.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ module RailsSemanticLogger
66
module ActionController
77
autoload :LogSubscriber, "rails_semantic_logger/action_controller/log_subscriber"
88
end
9+
module ActionMailer
10+
autoload :LogSubscriber, "rails_semantic_logger/action_mailer/log_subscriber"
11+
end
912
module ActionView
1013
autoload :LogSubscriber, "rails_semantic_logger/action_view/log_subscriber"
1114
end
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
require "active_support/log_subscriber"
2+
require "action_mailer"
3+
4+
module RailsSemanticLogger
5+
module ActionMailer
6+
class LogSubscriber < ::ActiveSupport::LogSubscriber
7+
def deliver(event)
8+
message_id = event.payload[:message_id]
9+
duration = event.duration.round(1)
10+
message = begin
11+
if event.payload[:perform_deliveries]
12+
"Delivered mail #{message_id} (#{duration}ms)"
13+
else
14+
"Skipped delivery of mail #{message_id} as `perform_deliveries` is false"
15+
end
16+
end
17+
log_with_formatter event: event do |fmt|
18+
{ message: message }
19+
end
20+
end
21+
22+
# An email was generated.
23+
def process(event)
24+
mailer = event.payload[:mailer]
25+
action = event.payload[:action]
26+
duration = event.duration.round(1)
27+
log_with_formatter event: event do |fmt|
28+
{ message: "#{mailer}##{action}: processed outbound mail in #{duration}ms" }
29+
end
30+
end
31+
32+
private
33+
34+
class EventFormatter
35+
def initialize(event:, log_duration: false)
36+
@event = event
37+
@log_duration = log_duration
38+
end
39+
40+
def mailer
41+
event.payload[:mailer]
42+
end
43+
44+
def payload
45+
{}.tap do |h|
46+
h[:event_name] = event.name
47+
h[:mailer] = mailer
48+
h[:action] = action
49+
h[:message_id] = event.payload[:message_id]
50+
h[:perform_deliveries] = event.payload[:perform_deliveries]
51+
h[:subject] = event.payload[:subject]
52+
h[:to] = event.payload[:to]
53+
h[:from] = event.payload[:from]
54+
h[:bcc] = event.payload[:bcc]
55+
h[:cc] = event.payload[:cc]
56+
h[:date] = date
57+
h[:duration] = event.duration.round(2) if log_duration?
58+
end
59+
end
60+
61+
def date
62+
if date = event.payload[:date]
63+
Time.parse(date).utc
64+
else
65+
nil
66+
end
67+
end
68+
69+
private
70+
71+
attr_reader :event
72+
73+
def mailer
74+
event.payload[:mailer]
75+
end
76+
77+
def action
78+
event.payload[:action]
79+
end
80+
81+
def log_duration?
82+
@log_duration
83+
end
84+
end
85+
86+
def log_with_formatter(level: :info, **kw_args)
87+
fmt = EventFormatter.new(**kw_args)
88+
msg = yield fmt
89+
logger.public_send(level, **msg, payload: fmt.payload)
90+
end
91+
92+
def logger
93+
::ActionMailer::Base.logger
94+
end
95+
end
96+
end
97+
end

lib/rails_semantic_logger/engine.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "rails"
22
require "action_controller/log_subscriber"
33
require "action_view/log_subscriber"
4+
require "action_mailer/log_subscriber"
45
require "rails_semantic_logger/options"
56

67
module RailsSemanticLogger
@@ -198,6 +199,13 @@ class Engine < ::Rails::Engine
198199
RailsSemanticLogger::ActionController::LogSubscriber,
199200
:action_controller
200201
)
202+
203+
# Action Mailer
204+
RailsSemanticLogger.swap_subscriber(
205+
::ActionMailer::LogSubscriber,
206+
RailsSemanticLogger::ActionMailer::LogSubscriber,
207+
:action_mailer
208+
)
201209
end
202210

203211
#

test/action_mailer_test.rb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
require_relative "test_helper"
2+
3+
class ActionMailerTest < Minitest::Test
4+
class MyMailer < ActionMailer::Base
5+
def some_email(to:, from:, subject:)
6+
mail(to: to, from: from, subject: subject, body: "Hello")
7+
end
8+
end
9+
10+
describe "ActionMailer" do
11+
before do
12+
::ActionMailer::Base.delivery_method = :test
13+
@mock_logger = MockLogger.new
14+
@appender = SemanticLogger.add_appender(logger: @mock_logger, formatter: :raw)
15+
end
16+
17+
after do
18+
SemanticLogger.remove_appender(@appender)
19+
end
20+
21+
describe "#deliver" do
22+
it "sets the ActionMailer logger" do
23+
assert_kind_of SemanticLogger::Logger, MyMailer.logger
24+
end
25+
26+
it "sends the email" do
27+
MyMailer.some_email(to: '[email protected]', from: '[email protected]', subject: 'test').deliver_now
28+
end
29+
end
30+
31+
describe "Logging::LogSubscriber" do
32+
before do
33+
skip "Older rails does not support ActiveSupport::Notification" unless defined?(ActiveSupport::Notifications)
34+
end
35+
36+
let(:subscriber) { RailsSemanticLogger::ActionMailer::LogSubscriber.new }
37+
38+
let(:event) do
39+
ActiveSupport::Notifications::Event.new event_name,
40+
5.seconds.ago,
41+
Time.zone.now,
42+
SecureRandom.uuid,
43+
payload
44+
end
45+
46+
let(:payload) do
47+
{
48+
mailer: 'MyMailer',
49+
action: :some_email,
50+
}
51+
end
52+
53+
let(:event_name) { "deliver.action_mailer" }
54+
55+
let(:mailer) do
56+
MyMailer.some_email(to: '[email protected]', from: '[email protected]', subject: 'test')
57+
end
58+
59+
%i[deliver process].each do |method|
60+
describe "##{method}" do
61+
specify do
62+
assert ActionMailer::Base.logger.info
63+
subscriber.public_send(method, event)
64+
end
65+
end
66+
end
67+
68+
describe "ActiveJob::Logging::LogSubscriber::EventFormatter" do
69+
let(:formatter) do
70+
RailsSemanticLogger::ActionMailer::LogSubscriber::EventFormatter.new(event: event, log_duration: true)
71+
end
72+
73+
let(:event_name) { "deliver.action_mailer" }
74+
75+
describe "#payload" do
76+
specify do
77+
assert_equal(formatter.payload[:event_name], "deliver.action_mailer")
78+
assert_equal(formatter.payload[:mailer], "MyMailer")
79+
assert_equal(formatter.payload[:action], :some_email)
80+
assert_kind_of(Float, formatter.payload[:duration])
81+
end
82+
end
83+
end
84+
end
85+
end
86+
end

0 commit comments

Comments
 (0)