Skip to content
Closed
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
30 changes: 15 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ jobs:
fail-fast: false
matrix:
include:
- ruby: '2.3'
rails: '5.2'
bundler: '1'
- ruby: '2.4'
rails: '5.2'
bundler: '1'
- ruby: '2.5'
rails: '6.0'
- ruby: '3.3' # v1.x sqlite3 requires Ruby 3.3
rails: '7.0'
bundler: 'default'
- ruby: '2.6'
rails: '6.0'
- ruby: '3.4'
rails: '7.1'
bundler: 'default'
- ruby: '2.7'
rails: '6.1'
- ruby: '3.4'
rails: '7.2'
bundler: 'default'
- ruby: '3.4'
rails: '8.0'
bundler: 'default'
- ruby: '3.4'
rails: '8.1'
bundler: 'default'
env:
RAILS_VERSION: ${{ matrix.rails }}
Expand All @@ -39,14 +39,14 @@ jobs:
bundler: ${{ matrix.bundler }}
bundler-cache: true
- run: bundle exec rubocop
if: matrix.ruby == '2.7'
if: matrix.rails == '7.1'
- run: bundle exec rspec --format doc
- uses: codecov/codecov-action@v3
if: matrix.ruby == '2.7'
if: matrix.rails == '7.1'
with:
files: coverage/coverage.xml
- run: bin/yardoc --fail-on-warning
if: matrix.ruby == '2.7'
if: matrix.rails == '7.1'
- run: bin/check-version

release:
Expand Down
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require:

AllCops:
SuggestExtensions: false
TargetRubyVersion: 2.3
TargetRubyVersion: 3.3

Gemspec/DeprecatedAttributeAssignment: { Enabled: true }
Gemspec/RequireMFA: { Enabled: true }
Expand Down
21 changes: 7 additions & 14 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@ source 'https://rubygems.org'
gemspec

not_jruby = %i[ruby mingw x64_mingw].freeze
ruby_version = Gem::Version.new(RUBY_VERSION)
rails_version = Gem::Version.new(ENV.fetch('RAILS_VERSION', '5.2'))
rails_version = Gem::Version.new(ENV.fetch('RAILS_VERSION', '7.1.0'))

gem 'byebug', platforms: not_jruby
gem 'rails', "~> #{rails_version}"
gem 'redcarpet', '~> 3.5', platforms: not_jruby
gem 'rubocop', '~> 1.46'
gem 'rubocop-rspec', '~> 2.12.0'
gem 'simplecov', '>= 0.17.1'
gem 'simplecov-cobertura', '~> 3.0'
gem 'yard', '~> 0.9.25', platforms: not_jruby

if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
gem 'rubocop', '~> 1.36.0'
gem 'rubocop-rspec', '~> 2.12.0'
gem 'simplecov', '>= 0.17.1'
gem 'simplecov-cobertura', '~> 2.1'
end

if ruby_version >= Gem::Version.new('2.6')
gem 'sqlite3', '~> 1.5'
else
gem 'sqlite3', '~> 1.4', '< 1.5'
end
# Rails 7.0's ActiveRecord adapter requires sqlite3 ~> 1.4; 7.1+ allows 2.x
gem 'sqlite3', rails_version < Gem::Version.new('7.1') ? '~> 1.4' : '>= 1.4'
8 changes: 4 additions & 4 deletions epilog.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ Gem::Specification.new do |spec|
spec.files = Dir['lib/**/*.rb', '*.md', '*.txt', '.yardopts']
spec.require_paths = ['lib']

spec.required_ruby_version = '>= 2.3'
spec.required_ruby_version = '>= 3.3'

spec.add_development_dependency 'combustion', '~> 1.3'
spec.add_development_dependency 'rails', '>= 4.2', '< 7'
spec.add_development_dependency 'rails', '>= 4.2'
spec.add_development_dependency 'rspec', '~> 3.11'
spec.add_development_dependency 'rspec-rails', '~> 5.1'
spec.add_development_dependency 'sqlite3', '~> 1.3'
spec.add_development_dependency 'rspec-rails', '>= 7.0'
spec.add_development_dependency 'sqlite3', '>= 1.4'
end
2 changes: 1 addition & 1 deletion lib/epilog/filter/blacklist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Blacklist < HashKey
attr_reader :blacklist

def initialize(blacklist = DEFAULT_BLACKLIST)
@blacklist = blacklist.map { |b| [b.to_s.downcase, nil] }.to_h
@blacklist = blacklist.to_h { |b| [b.to_s.downcase, nil] }
super()
end

Expand Down
4 changes: 2 additions & 2 deletions lib/epilog/filter/filter_parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ class FilterParameters < Blacklist
def filter_parameters
return @filter_parameters if @filter_parameters

filtered = ::Rails.application.config.filter_parameters.map do |p|
filtered = ::Rails.application.config.filter_parameters.to_h do |p|
[p.to_s.downcase, true]
end.to_h
end

@filter_parameters = filtered if ::Rails.initialized?
filtered
Expand Down
4 changes: 2 additions & 2 deletions lib/epilog/mock_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

module Epilog
class MockLogger < ::Logger
def initialize(**options)
super(nil, **options)
def initialize(**)
super(nil, **)
reset
end

Expand Down
4 changes: 2 additions & 2 deletions lib/epilog/rails/action_controller_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def log_end(event)
info do
{
message: response_string(event),
request: request,
request:,
response: response_hash(event),
metrics: process_metrics(event.payload[:metrics]
.merge(request_runtime: event.duration.round(2)))
Expand Down Expand Up @@ -158,7 +158,7 @@ def normalize_status(event)

def basic_message(event, message)
{
message: message,
message:,
metrics: process_metrics(duration: event.duration)
}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/epilog/rails/action_view_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def render_collection(event)

def hash(event, message)
{
message: message,
message:,
template: fix_path(event.payload[:identifier]),
layout: fix_path(event.payload[:layout]),
metrics: {
Expand Down
2 changes: 1 addition & 1 deletion lib/epilog/rails/active_job_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def perform(event)

def event_hash(message, event)
{
message: message,
message:,
job: job_hash(event.payload[:job]),
adapter: adapter_name(event.payload[:adapter])
}
Expand Down
2 changes: 1 addition & 1 deletion lib/epilog/rails/active_record_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ActiveRecordSubscriber < LogSubscriber
IGNORE_PAYLOAD_NAMES = %w[SCHEMA EXPLAIN].freeze

def sql(event)
ActiveRecord::LogSubscriber.runtime += event.duration
ActiveRecord::RuntimeRegistry.sql_runtime += event.duration

return unless logger.debug?

Expand Down
20 changes: 9 additions & 11 deletions lib/epilog/rails/ext/action_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,27 @@ module ActionControllerExt
def process_action(*)
epilog_instrument('request_received')
epilog_instrument('process_request') do |payload|
begin
super
ensure
payload[:response] = response
payload[:metrics] = epilog_metrics
end
super
ensure
payload[:response] = response
payload[:metrics] = epilog_metrics
end
end

private

def epilog_instrument(name, &block)
def epilog_instrument(name, &)
ActiveSupport::Notifications.instrument(
"#{name}.action_controller",
epilog_payload,
&block
&
)
end

def epilog_payload
{
request: request,
response: response,
request:,
response:,
controller: self.class.name,
action: action_name,
context: epilog_context
Expand All @@ -37,7 +35,7 @@ def epilog_payload
def epilog_metrics
{
db_runtime: try(:db_runtime),
view_runtime: view_runtime
view_runtime:
}
end

Expand Down
27 changes: 16 additions & 11 deletions lib/epilog/rails/ext/active_support_logger.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# frozen_string_literal: true

module ActiveSupport
class Logger
# Rails uses this method to attach additional loggers to the main
# Rails.logger object when using the rails console or server. This results
# in extra unformatted log output in those cases. Prevent that by
# overriding the method with a stub. Examples can be found in
#
# - railties/lib/rails/commands/server.rb
# - active_record/lib/active_record/railtie.rb
def self.broadcast(*_args)
Module.new
# For Rails 7.1+, the broadcast_to patch is applied in the railtie's
# after_initialize block (see railtie.rb) to ensure the BroadcastLogger
# class is fully defined before we patch it.
if ::Rails.gem_version < Gem::Version.new('7.1')
module ActiveSupport
class Logger
# Rails uses this method to attach additional loggers to the main
# Rails.logger object when using the rails console or server. This results
# in extra unformatted log output in those cases. Prevent that by
# overriding the method with a stub. Examples can be found in
#
# - railties/lib/rails/commands/server.rb
# - active_record/lib/active_record/railtie.rb
def self.broadcast(*_args)
Module.new
end
end
end
end
11 changes: 7 additions & 4 deletions lib/epilog/rails/ext/event_delegate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
module Epilog
module EventDelegateExt
# Rails has no public API to determine the delegate for an event
# object. Add this method to allow checking if the delegate matches
# a given object.
def delegates_to?(delegate)
@delegate == delegate
# object. Add these methods to allow checking the delegate.
def delegate
@delegate
end

def delegates_to?(other)
@delegate == other
end
end
end
Expand Down
75 changes: 58 additions & 17 deletions lib/epilog/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ def self.rails_6_1_higher?
]

initializer 'epilog.configure' do |app|
disable_rails_defaults

::Rails.logger ||= Logger.new($stdout)

app.config.epilog.subscriptions.each do |namespace|
Expand All @@ -57,28 +55,71 @@ def self.rails_6_1_higher?
end
end

private
# In Rails 7.1+, ActionView::LogSubscriber::Start are attached late
# in the initialization process, so we need to disable them after
# initialization completes
config.after_initialize do
disable_rails_defaults
prevent_double_logs_from_broadcast
end

class << self
private

def disable_rails_defaults
blacklisted_subscribers.each do |subscriber|
subscriber.patterns.each do |pattern|
unsubscribe_listeners(subscriber, pattern)
def disable_rails_defaults
blacklisted_subscribers.each do |subscriber|
subscriber.patterns.each do |pattern|
unsubscribe_listeners(subscriber, pattern)
end
end

# Rails 7.1 adds ActionView::LogSubscriber::Start which subscribes
# separately and logs "Rendering..." messages at the start of rendering
# see https://github.com/rails/rails/commit/9c58a54702b038b9acebdb3efa85c26156ff1987#diff-fd389a9f74e2259b56015e3f8d15a5ce33c093045dd4cb354e82d6d81fe9b06aR98-R99
unsubscribe_action_view_start_listeners
end
end

def unsubscribe_listeners(subscriber, pattern)
notifier = ActiveSupport::Notifications.notifier
notifier.listeners_for(Array.wrap(pattern).first).each do |listener|
if listener.delegates_to?(subscriber)
ActiveSupport::Notifications.unsubscribe(listener)
def unsubscribe_listeners(subscriber, pattern)
notifier = ActiveSupport::Notifications.notifier
notifier.listeners_for(Array.wrap(pattern).first).each do |listener|
if listener.delegates_to?(subscriber)
ActiveSupport::Notifications.unsubscribe(listener)
end
end
end
end

def blacklisted_subscribers
ActiveSupport::LogSubscriber.log_subscribers.select do |subscriber|
SUBSCRIBER_BLACKLIST.include?(subscriber.class)
def unsubscribe_action_view_start_listeners
return unless defined?(ActionView::LogSubscriber::Start)

notifier = ActiveSupport::Notifications.notifier
%w[render_template.action_view render_layout.action_view].each do |pattern|
notifier.listeners_for(pattern).each do |listener|
if listener.delegate.is_a?(ActionView::LogSubscriber::Start)
ActiveSupport::Notifications.unsubscribe(listener)
end
end
end
end

# In Rails 7.1+, the server and console call Rails.logger.broadcast_to(console)
# which adds a second logger and causes every log line to appear twice
# (e.g. custom format + default Logger format). Override broadcast_to with
# a no-op to prevent adding duplicate destinations.
#
# This must be done in after_initialize (not at require time) because:
# 1. Rails wraps the logger in a BroadcastLogger during bootstrap
# 2. We need to override the instance method on the actual Rails.logger
def prevent_double_logs_from_broadcast
return if ::Rails.gem_version < Gem::Version.new('7.1')
return unless ::Rails.logger

::Rails.logger.define_singleton_method(:broadcast_to) { |*| nil }
end

def blacklisted_subscribers
ActiveSupport::LogSubscriber.log_subscribers.select do |subscriber|
SUBSCRIBER_BLACKLIST.include?(subscriber.class)
end
end
end
end
Expand Down
Loading
Loading