Skip to content

Conversation

@Nowaker
Copy link

@Nowaker Nowaker commented Sep 14, 2023

This is #303 rebased against master.

Not that my feedback from #303 (comment) still applies - it's not an ideal implementation... but it works. It's been in production of a huge site for one year now.

For reference, RequestStore.store[:lograge_event_payload] is what this original PR adds to Lograge core, and then formatters or other custom loggers. Like my logger that is set as Rails.logger and therefore each non-Lograge line includes what Lograge logs for that request.

# config/application.rb
    config.log_level = :debug
    require_relative '../lib/exceptions'
    config.logger = ::Exceptions::Logger.new(STDOUT)
# lib/exceptions.rb
class Exceptions
  def self.to_s_truncated e, source
    unless e.is_a?(Exception)
      return '(not an exception)'
    end

    truncated_backtrace = []
    truncated_backtrace << "#{e.class.name}: #{e}"

    full_stack_size = e.backtrace.size
    truncated_backtrace += e.backtrace.first(5)
    if full_stack_size > 5
      truncated_backtrace << "(truncated; total frames: #{full_stack_size})"
    end

    truncated_backtrace.join("\n")
  end

  def self.to_s_one_line e, source
    unless e.is_a?(Exception)
      return '(not an exception)'
    end

    s = "#{e.class.name}: #{e}"

    if first_frame = e.backtrace.first
      s << " - #{first_frame}"
    end

    if source
      s << " via #{source}"
    end

    s
  end

  def self.to_lograge e, hash, event
    hash[:error] = Exceptions.to_s_one_line(e, 'lograge')
    hash[:appsignal] = "#{e.class.name} #{event.payload[:controller]}##{event.payload[:action]}"
  end

  class Logger < ::Logger
    %w(unknown fatal error warn info debug).each do |level|
      level_const = Logger.const_get level.upcase

      define_method level do |msg, controller = nil, &block|
        if msg.is_a? Exception
          msg = Exceptions.to_s_one_line(msg, 'logger')
        end

        if msg && controller
          event = RequestStore.store[:lograge_event_payload] || {}
          event.define_singleton_method :payload do
            event
          end

          if controller
            event.merge! Rails.configuration.lograge.custom_payload_method.call(controller)
            event.merge! Rails.configuration.lograge.custom_options.call(event, controller)
          end

          unless controller.is_a?(Rack::Attack::Request)
            event.merge! type: 'logger'
          end

          lograge_line = Rails.configuration.lograge.formatter.call(event)

          msg = "#{lograge_line} --- #{msg}"
        end

        add(level_const, msg, progname, &block)
      end
    end
  end
end

Allows for the added payload fields in lograge to surface in logs
outside of just controller logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants