Module: Cogger

Extended by:
Registry
Defined in:
lib/cogger.rb,
lib/cogger/hub.rb,
lib/cogger/tag.rb,
lib/cogger/entry.rb,
lib/cogger/level.rb,
lib/cogger/program.rb,
lib/cogger/registry.rb,
lib/cogger/time/span.rb,
lib/cogger/time/unit.rb,
lib/cogger/time/clock.rb,
lib/cogger/time/range.rb,
lib/cogger/rack/logger.rb,
lib/cogger/configuration.rb,
lib/cogger/refines/logger.rb,
lib/cogger/formatters/json.rb,
lib/cogger/formatters/color.rb,
lib/cogger/formatters/crash.rb,
lib/cogger/formatters/emoji.rb,
lib/cogger/formatters/simple.rb,
lib/cogger/refines/log_device.rb,
lib/cogger/formatters/abstract.rb,
lib/cogger/formatters/property.rb,
lib/cogger/formatters/parsers/key.rb,
lib/cogger/formatters/parsers/emoji.rb,
lib/cogger/formatters/parsers/element.rb,
lib/cogger/formatters/parsers/abstract.rb,
lib/cogger/formatters/parsers/combined.rb,
lib/cogger/formatters/parsers/position.rb,
lib/cogger/formatters/transformers/key.rb,
lib/cogger/formatters/sanitizers/escape.rb,
lib/cogger/formatters/sanitizers/filter.rb,
lib/cogger/formatters/transformers/color.rb,
lib/cogger/formatters/transformers/emoji.rb,
lib/cogger/formatters/sanitizers/format_time.rb

Overview

Computes default program name based on current file name.

Defined Under Namespace

Modules: Formatters, Rack, Refines, Registry, Time Classes: Hub

Constant Summary collapse

DATETIME_FORMAT =
"%Y-%m-%dT%H:%M:%S.%L%:z"
LEVELS =
%w[debug info warn error fatal unknown].freeze
Tag =

Models a tag which may consist of an array and/or hash.

Data.define :singles, :pairs do
  using Refinements::Hash

  def self.for(*bag)
    bag.each.with_object new do |item, tag|
      value = item.is_a?(Proc) ? item.call : item
      value.is_a?(Hash) ? tag.pairs.merge!(value) : tag.singles.append(value)
    end
  end

  def initialize singles: [], pairs: {}
    super
  end

  def empty? = singles.empty? && pairs.empty?

  def to_h = empty? ? Core::EMPTY_HASH : {tags: singles.to_a, **pairs}.tap(&:compress!)

  def to_s = empty? ? Core::EMPTY_STRING : "#{format_singles} #{format_pairs}".tap(&:strip!)

  private

  def format_singles
    singles.map { |value| "[#{value}]" }
           .join " "
  end

  def format_pairs
    pairs.map { |key, value| "[#{key}=#{value}]" }
         .join(" ")
  end
end
Entry =

Defines a log entry which can be formatted for output.

Data.define :id, :level, :at, :message, :tags, :datetime_format, :payload do
  def self.for(message = nil, **payload)
    new id: payload.delete(:id) || Program.call,
        level: (payload.delete(:level) || "INFO").upcase,
        at: payload.delete(:at) || ::Time.now,
        message: (block_given? ? yield : message),
        tags: Array(payload.delete(:tags)),
        datetime_format: payload.delete(:datetime_format) || DATETIME_FORMAT,
        payload:
  end

  def self.for_crash message, error, id:
    new id:,
        level: "FATAL",
        message:,
        payload: {
          error_message: error.message,
          error_class: error.class,
          backtrace: error.backtrace
        }
  end

  def initialize id: Program.call,
                 level: "INFO",
                 at: ::Time.now,
                 message: nil,
                 tags: Core::EMPTY_ARRAY,
                 datetime_format: DATETIME_FORMAT,
                 payload: Core::EMPTY_HASH
    super
  end

  def attributes = {id:, level:, at:, message:, **payload}

  def tagged_attributes tagger: Tag
    computed_tags = tagger.for(*tags)

    return attributes if computed_tags.empty?

    {id:, level:, at:, message:, **computed_tags.to_h, **payload}
  end

  def tagged tagger: Tag
    attributes.tap do |pairs|
      computed_tags = tagger.for(*tags)
      pairs[:message] = "#{computed_tags} #{pairs[:message]}" unless computed_tags.empty?
    end
  end
end
Level =
lambda do |logger = Logger, environment: ENV, allowed: LEVELS|
  value = String environment.fetch("LOG_LEVEL", "INFO")

  return logger.const_get value.upcase if allowed.include? value.downcase

  fail ArgumentError, %(Invalid log level: #{value.inspect}. Use: #{allowed.to_usage "or"}.)
end
Program =
lambda do |name = $PROGRAM_NAME|
  Pathname(name).then { |path| path.basename(path.extname).to_s }
end
Configuration =

Defines the default configuration for all pipes.

Data.define(
  :id,
  :io,
  :level,
  :formatter,
  :datetime_format,
  :tags,
  :mode,
  :age,
  :size,
  :suffix,
  :entry,
  :logger
) do
  using Refinements::Array

  def initialize id: Program.call,
                 io: $stdout,
                 level: Level.call,
                 formatter: Formatters::Emoji.new,
                 datetime_format: DATETIME_FORMAT,
                 tags: Core::EMPTY_ARRAY,
                 mode: false,
                 age: 0,
                 size: 1_048_576,
                 suffix: "%Y-%m-%d",
                 entry: Entry,
                 logger: Logger

    super.tap { tags.freeze }
  end

  def entag(other = nil) = other ? tags.including(other) : tags

  def to_logger
    logger.new io,
               age,
               size,
               progname: id,
               level:,
               formatter:,
               datetime_format:,
               binmode: mode,
               shift_period_suffix: suffix
  end

  def inspect
    "#<#{self.class} @id=#{id}, @io=#{io.class}, @level=#{level}, " \
    "@formatter=#{formatter.class}, @datetime_format=#{datetime_format.inspect}, " \
    "@tags=#{tags.inspect}, @mode=#{mode}, @age=#{age}, @size=#{size}, " \
    "@suffix=#{suffix.inspect}, @entry=#{entry}, @logger=#{logger}>"
  end
end

Class Method Summary collapse

Methods included from Registry

add_alias, add_emoji, add_filter, add_formatter, aliases, color, defaults, emojis, extended, filters, formatters, get_emoji, get_formatter, templates

Class Method Details

.loader(registry = Zeitwerk::Registry) ⇒ Object



19
20
21
# File 'lib/cogger.rb', line 19

def self.loader registry = Zeitwerk::Registry
  @loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
end

.newObject



23
# File 'lib/cogger.rb', line 23

def self.new(...) = Hub.new(...)