diff --git a/lib/event_logger_rails.rb b/lib/event_logger_rails.rb index 76788eb..ee8ccc0 100644 --- a/lib/event_logger_rails.rb +++ b/lib/event_logger_rails.rb @@ -15,26 +15,58 @@ require 'event_logger_rails/output' require 'event_logger_rails/version' -## -# Namespace for EventLoggerRails gem +# Provides configurable state and public API for EventLoggerRails. +# Also serves as the namespace for the gem. module EventLoggerRails + # @!attribute [r] default_level + # @return [Symbol] The default level of the events logged by EventLoggerRails. mattr_accessor :default_level + + # @!attribute [r] logdev + # @return [IO, #write] The log device used by EventLoggerRails. mattr_accessor :logdev + + # @!attribute [r] registered_events + # @return [Array] The events registry defined in the config/event_logger_rails.yml file. mattr_accessor :registered_events + + # @!attribute [r] sensitive_fields + # @return [Array] The fields which may contain sensitive data that EventLoggerRails should filter. mattr_accessor :sensitive_fields + # Provides a method for configuring EventLoggerRails. + # + # @yield [self] Gives the class itself to the block for configuration. + # @example + # EventLoggerRails.setup do |config| + # config.default_level = :info + # end + # @return [void] def self.setup yield self end + # Returns or initializes the Emitter instance for EventLoggerRails. + # + # @note The emitter is initialized with the configured log device. + # @return [Emitter] The Emitter instance used for logging events. def self.emitter @emitter ||= Emitter.new(logdev:) end + # Forwards the arguments to the Emitter's log method. + # + # @example + # EventLoggerRails.log('foo.bar.baz', level: :info, data: { foo: 'bar' }) + # @param (see Emitter#log) + # @return [void] def self.log(...) emitter.log(...) end + # Resets the Emitter instance. + # + # @return [void] def self.reset @emitter = nil end diff --git a/lib/event_logger_rails/current_request.rb b/lib/event_logger_rails/current_request.rb index 3e39364..99bc687 100644 --- a/lib/event_logger_rails/current_request.rb +++ b/lib/event_logger_rails/current_request.rb @@ -4,6 +4,19 @@ module EventLoggerRails ## # Provides global state with request details class CurrentRequest < ActiveSupport::CurrentAttributes + # @note Defines the attributes for the current request object. + # @!attribute [rw] id + # @return [String] The ID of the request. + # @!attribute [rw] format + # @return [Symbol] The format of the request. + # @!attribute [rw] method + # @return [String] The HTTP method of the request. + # @!attribute [rw] parameters + # @return [Hash] The parameters of the request. + # @!attribute [rw] path + # @return [String] The path of the request. + # @!attribute [rw] remote_ip + # @return [String] The remote IP of the request. attribute :id, :format, :method, :parameters, :path, :remote_ip end end diff --git a/lib/event_logger_rails/emitter.rb b/lib/event_logger_rails/emitter.rb index c0cd91e..0c3c1fa 100644 --- a/lib/event_logger_rails/emitter.rb +++ b/lib/event_logger_rails/emitter.rb @@ -4,10 +4,20 @@ module EventLoggerRails ## # Processes events, sending data to logger. class Emitter + ## Initializes the emitter using the given log device for log output. + # + # @param logdev [IO, #write] The log device for log output. def initialize(logdev:) @logger = JsonLogger.new(logdev) end + # Validates and logs an event with the given level and data. + # If an error is raised, it recursively calls itself with the error's event. + # + # @param event [EventLoggerRails::Event, String] The event to log. Can be a string or an Event object. + # @param level [Symbol] The level of the event. + # @param data [Hash] Additional data to log. + # @return [Integer] The number of bytes written to the log. def log(event, level:, data: {}) Event.new(event).validate! do |validated_event| message = Message.new(event: validated_event, data:) @@ -20,8 +30,16 @@ def log(event, level:, data: {}) private + # @!attribute [r] logger + # @return [JsonLogger] The logger instance used for log output. attr_reader :logger + # Logs a message with the given level. + # + # @param message [String] The message to log. + # @param level [Symbol] The level of the message. + # @return [Integer] The number of bytes written to the log. + # @raise [EventLoggerRails::Exceptions::InvalidLoggerLevel] If the level is invalid. def log_message(message, level) logger.send(level) { message } rescue NoMethodError diff --git a/lib/event_logger_rails/event.rb b/lib/event_logger_rails/event.rb index c70b859..14c4fd2 100644 --- a/lib/event_logger_rails/event.rb +++ b/lib/event_logger_rails/event.rb @@ -4,6 +4,7 @@ module EventLoggerRails ## # Models an event for logging. class Event + # Contains the default event registration. DEFAULT_EVENTS = { 'event_logger_rails.logger_level.invalid' => { description: 'Indicates provided level was invalid.', @@ -20,32 +21,88 @@ class Event }.freeze private_constant :DEFAULT_EVENTS - attr_reader :identifier, :description, :level + # @!attribute [r] identifier + # @return [String] The identifier of the event. + attr_reader :identifier + # @!attribute [r] description + # @return [String] The description of the event. + attr_reader :description + + # @!attribute [r] level + # @return [Symbol] The configured logging level of the event. + attr_reader :level + + # Initializes the event using the provided identifier to determine its properties from + # either the default registration (for default events) or the user-defined registry. + # + # @param provided_identifier [EventLoggerRails::Event, String] The event or its identifier. def initialize(provided_identifier) @provided_identifier = provided_identifier.to_s + # Attempt to find default registration for event if (default_event = DEFAULT_EVENTS[@provided_identifier]) default_registration = [@provided_identifier, *default_event&.values] end + # Fallback to user-defined registration if default not found. + # Deconstruct registration to set identifier, description, and level attributes. @identifier, @description, @level = default_registration || config_registration end + # Converts the event into a hash and merges the given hash into it. + # + # @param kwargs [Hash] The hash to merge into the event. + # @return [Hash] The merged hash. + # @example + # event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # event.merge(foo: 'bar') + # # { + # # event_identifier: 'event_logger_rails.event.testing', + # # event_description: 'Event reserved for testing', + # # foo: 'bar' + # # } def merge(...) to_hash.merge(...) end + # Determines if the event is valid. + # + # @return [Boolean] true if the event is valid, false otherwise. + # @example + # valid_event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # valid_event.valid? # => true + # invalid_event = EventLoggerRails::Event.new('foo.bar.baz') + # invalid_event.valid? # => false def valid? identifier.present? end + # Validates the event and yields it to the given block. + # + # @yield [self] Yields the event to the given block. + # @raise [EventLoggerRails::Exceptions::UnregisteredEvent] If the event is not registered. + # @example + # event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # event.validate! do |validated_event| + # puts "Event: #{validated_event}" + # end def validate! raise Exceptions::UnregisteredEvent.new(unregistered_event: self) unless valid? yield(self) end + # Returns a hash representation of the event. + # + # @return [Hash] The event as a hash. + # @example + # event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # event.to_hash + # # { + # # event_identifier: 'event_logger_rails.event.testing', + # # event_description: 'Event reserved for testing' + # # } def to_hash { event_identifier: identifier, @@ -53,18 +110,38 @@ def to_hash } end + # Returns a string representation of the event. + # The provided identifier is returned if the event is not registered. + # + # @return [String] The event as a string. + # @example + # event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # event.to_s # => 'event_logger_rails.event.testing' def to_s identifier&.to_s || provided_identifier.to_s end + # Determines if the event is equivalent to the given object through string comparison. + # + # @param other [EventLoggerRails::Event] The event to compare. + # @return [Boolean] true if the event is equal to the given object, false otherwise. + # @example + # event = EventLoggerRails::Event.new('event_logger_rails.event.testing') + # event == 'event_logger_rails.event.testing' # => true def ==(other) to_s == other.to_s end private + # @!attribute [r] provided_identifier + # @return [String] The identifier provided when the event was initialized. attr_reader :provided_identifier + # Parses the event identifier and looks up the details from the user-defined registry. + # + # @return [Array] The identifier, description, and level of the event. + # If the event is not registered, each array element will be nil. def config_registration parsed_event = provided_identifier.split('.').map(&:to_sym) config = EventLoggerRails.registered_events.dig(*parsed_event)