Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
bump: minor
type: add
---

Report events from Rails 8.1's Structured Event Reporting (`ActiveSupport::EventReporter`) as logs.
4 changes: 4 additions & 0 deletions lib/appsignal/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def dsl_config_file?
:enable_gvl_global_timer => true,
:enable_gvl_waiting_threads => true,
:enable_rails_error_reporter => true,
:enable_active_support_event_log_reporter => true,
:enable_rake_performance_instrumentation => false,
:endpoint => "https://push.appsignal.com",
:files_world_accessible => true,
Expand Down Expand Up @@ -184,6 +185,7 @@ def dsl_config_file?
:enable_gvl_global_timer => "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER",
:enable_gvl_waiting_threads => "APPSIGNAL_ENABLE_GVL_WAITING_THREADS",
:enable_rails_error_reporter => "APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER",
:enable_active_support_event_log_reporter => "APPSIGNAL_ENABLE_ACTIVE_SUPPORT_EVENT_LOG_REPORTER",
:enable_rake_performance_instrumentation =>
"APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION",
:files_world_accessible => "APPSIGNAL_FILES_WORLD_ACCESSIBLE",
Expand Down Expand Up @@ -802,6 +804,8 @@ def activate_if_environment(*envs)
# @return [Boolean] Configure whether GVL waiting threads instrumentation is enabled
# @!attribute [rw] enable_rails_error_reporter
# @return [Boolean] Configure whether Rails error reporter integration is enabled
# @!attribute [rw] enable_active_support_event_log_reporter
# @return [Boolean] Configure whether ActiveSupport::EventReporter integration is enabled
# @!attribute [rw] enable_rake_performance_instrumentation
# @return [Boolean] Configure whether Rake performance instrumentation is enabled
# @!attribute [rw] files_world_accessible
Expand Down
1 change: 1 addition & 0 deletions lib/appsignal/hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def truncate(text)
require "appsignal/hooks/action_mailer"
require "appsignal/hooks/active_job"
require "appsignal/hooks/active_support_notifications"
require "appsignal/hooks/active_support_event_reporter"
require "appsignal/hooks/celluloid"
require "appsignal/hooks/code_ownership"
require "appsignal/hooks/delayed_job"
Expand Down
21 changes: 21 additions & 0 deletions lib/appsignal/hooks/active_support_event_reporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Appsignal
class Hooks
# @!visibility private
class ActiveSupportEventReporterHook < Appsignal::Hooks::Hook
register :active_support_event_reporter

def dependencies_present?
defined?(::ActiveSupport::EventReporter) &&
Appsignal.config &&
Appsignal.config[:enable_active_support_event_log_reporter]
end

def install
require "appsignal/integrations/active_support_event_reporter"
Rails.event.subscribe(Appsignal::Integrations::ActiveSupportEventReporter::Subscriber.new())
end
end
end
end
18 changes: 18 additions & 0 deletions lib/appsignal/integrations/active_support_event_reporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module Appsignal
module Integrations
# @!visibility private
module ActiveSupportEventReporter
class Subscriber
def initialize
@logger = Appsignal::Logger.new("rails_events")
end

def emit(event)
@logger.info(event[:name], event[:payload])
end
end
end
end
end
3 changes: 3 additions & 0 deletions spec/lib/appsignal/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ def on_load
:enable_minutely_probes => false,
:enable_nginx_metrics => false,
:enable_rails_error_reporter => false,
:enable_active_support_event_log_reporter => false,
:enable_rake_performance_instrumentation => false,
:enable_statsd => false,
:endpoint => "https://test.appsignal.com",
Expand Down Expand Up @@ -792,6 +793,7 @@ def on_load
"APPSIGNAL_ENABLE_MINUTELY_PROBES" => "false",
"APPSIGNAL_ENABLE_NGINX_METRICS" => "false",
"APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER" => "false",
"APPSIGNAL_ENABLE_ACTIVE_SUPPORT_EVENT_LOG_REPORTER" => "false",
"APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION" => "false",
"APPSIGNAL_ENABLE_STATSD" => "false",
"APPSIGNAL_FILES_WORLD_ACCESSIBLE" => "false",
Expand Down Expand Up @@ -926,6 +928,7 @@ def on_load
:enable_statsd => true,
:enable_nginx_metrics => false,
:enable_rails_error_reporter => true,
:enable_active_support_event_log_reporter => true,
:enable_rake_performance_instrumentation => false,
:endpoint => "https://push.appsignal.com",
:files_world_accessible => true,
Expand Down
67 changes: 67 additions & 0 deletions spec/lib/appsignal/hooks/active_support_event_reporter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
describe Appsignal::Hooks::ActiveSupportEventReporterHook do
begin
require "active_support/event_reporter"
rescue LoadError # rubocop:disable Lint/SuppressedException
end

describe "#dependencies_present?" do
if DependencyHelper.rails8_1_present?
context "when ActiveSupport::EventReporter is present" do
context "with enable_active_support_event_log_reporter enabled" do
before { start_agent }

it "returns true" do
expect(described_class.new.dependencies_present?).to be_truthy
end
end

context "with enable_active_support_event_log_reporter disabled" do
before do
ENV["APPSIGNAL_ENABLE_ACTIVE_SUPPORT_EVENT_LOG_REPORTER"] = "false"
start_agent
end

it "returns false" do
expect(described_class.new.dependencies_present?).to be_falsy
end
end
end
else
context "when ActiveSupport::EventReporter is not present" do
subject { described_class.new.dependencies_present? }

it { is_expected.to be_falsy }
end
end
end

if defined?(::ActiveSupport::EventReporter)
describe "#install" do
before do
# Mock Rails.event
subscribers = []
mock_event_reporter = instance_double(
"ActiveSupport::EventReporter",
:subscribe => nil,
:subscribers => subscribers
)

allow(mock_event_reporter).to receive(:subscribe) do |subscriber|
subscribers << subscriber
end

allow(Rails).to receive(:event).and_return(mock_event_reporter)
end

it "subscribes the ActiveSupportEventReporter::Subscriber to Rails.event" do
event_reporter = Rails.event
expect(event_reporter.subscribers).to be_empty

described_class.new.install

expect(event_reporter.subscribers.length).to eq(1)
expect(event_reporter.subscribers.first).to be_a(Appsignal::Integrations::ActiveSupportEventReporter::Subscriber)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require "appsignal/integrations/active_support_event_reporter"

describe Appsignal::Integrations::ActiveSupportEventReporter::Subscriber do
let(:subscriber) { described_class.new }
let(:logger) { instance_double(Appsignal::Logger) }

before do
start_agent
allow(Appsignal::Logger).to receive(:new).with("rails_events").and_return(logger)
end

describe "#emit" do
it "logs the event name and payload" do
event = {
:name => "user.created",
:payload => { :id => 123, :email => "user@example.com" },
}

expect(logger).to receive(:info).with("user.created", { :id => 123, :email => "user@example.com" })

subscriber.emit(event)
end
end
end
4 changes: 4 additions & 0 deletions spec/support/helpers/dependency_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def rails7_1_present?
rails_present? && rails_version >= Gem::Version.new("7.1.0")
end

def rails8_1_present?
rails_present? && rails_version >= Gem::Version.new("8.1.0")
end

def active_job_wraps_args?
rails7_present? || (ruby_3_1_or_newer? && rails6_1_present? && !rails6_1_5_present?)
end
Expand Down
Loading