- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "zeitwerk"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
Zeitwerk::Loader.new.then do |loader|
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  loader.inflector.inflect "json" => "JSON", "range" => "RANGE"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  loader.tag = File.basename __FILE__, ".rb"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  loader.push_dir __dir__
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  loader.setup
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
# Main namespace.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  extend Registry
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%L%:z"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  LEVELS = %w[debug info warn error fatal unknown].freeze
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  def self.loader registry = Zeitwerk::Registry
           
        
      
        
          
- 
            
              4
            
            
              
            
            
    @loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  def self.new(...) = Hub.new(...)
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "logger"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/array"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
            
              
            
            
  # Defines the default configuration for all pipes.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  Configuration = Data.define(
           
        
      
        
          
- 
            
            
              
            
            
    :id,
           
        
      
        
          
- 
            
            
              
            
            
    :io,
           
        
      
        
          
- 
            
            
              
            
            
    :level,
           
        
      
        
          
- 
            
            
              
            
            
    :formatter,
           
        
      
        
          
- 
            
            
              
            
            
    :datetime_format,
           
        
      
        
          
- 
            
            
              
            
            
    :tags,
           
        
      
        
          
- 
            
            
              
            
            
    :header,
           
        
      
        
          
- 
            
            
              
            
            
    :mode,
           
        
      
        
          
- 
            
            
              
            
            
    :age,
           
        
      
        
          
- 
            
            
              
            
            
    :size,
           
        
      
        
          
- 
            
            
              
            
            
    :suffix,
           
        
      
        
          
- 
            
            
              
            
            
    :entry,
           
        
      
        
          
- 
            
            
              
            
            
    :logger,
           
        
      
        
          
- 
            
            
              
            
            
    :mutex
           
        
      
        
          
- 
            
            
              
            
            
  ) do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    using Refinements::Array
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def initialize id: Program.call,
           
        
      
        
          
- 
            
            
              
            
            
                   io: $stdout,
           
        
      
        
          
- 
            
            
              
            
            
                   level: Level.call,
           
        
      
        
          
- 
            
            
              
            
            
                   formatter: Formatters::Emoji.new,
           
        
      
        
          
- 
            
            
              
            
            
                   datetime_format: DATETIME_FORMAT,
           
        
      
        
          
- 
            
            
              
            
            
                   tags: Core::EMPTY_ARRAY,
           
        
      
        
          
- 
            
            
              
            
            
                   header: true,
           
        
      
        
          
- 
            
            
              
            
            
                   mode: false,
           
        
      
        
          
- 
            
            
              
            
            
                   age: nil,
           
        
      
        
          
- 
            
            
              
            
            
                   size: 1_048_576,
           
        
      
        
          
- 
            
            
              
            
            
                   suffix: "%Y-%m-%d",
           
        
      
        
          
- 
            
            
              
            
            
                   entry: Entry,
           
        
      
        
          
- 
            
            
              
            
            
                   logger: Logger,
           
        
      
        
          
- 
            
            
              
            
            
                   mutex: Mutex.new
           
        
      
        
          
- 
            
              158
            
            
              
            
            
      super.tap { tags.freeze }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              52
            
            
              
                
                  then: 7
                
              
                
                  else: 44
                
              
            
            
    def entag(other = nil) = other ? tags.including(other) : tags
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def to_logger
           
        
      
        
          
- 
            
              71
            
            
              
            
            
      logger.new io,
           
        
      
        
          
- 
            
            
              
            
            
                 age,
           
        
      
        
          
- 
            
            
              
            
            
                 size,
           
        
      
        
          
- 
            
            
              
            
            
                 progname: id,
           
        
      
        
          
- 
            
            
              
            
            
                 level:,
           
        
      
        
          
- 
            
            
              
            
            
                 formatter:,
           
        
      
        
          
- 
            
            
              
            
            
                 datetime_format:,
           
        
      
        
          
- 
            
            
              
            
            
                 skip_header: skip_header?,
           
        
      
        
          
- 
            
            
              
            
            
                 binmode: mode,
           
        
      
        
          
- 
            
            
              
            
            
                 shift_period_suffix: suffix
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def inspect
           
        
      
        
          
- 
            
              8
            
            
              
            
            
      "#<#{self.class} @id=#{id}, @io=#{io.class}, @level=#{level}, " \
           
        
      
        
          
- 
            
            
              
            
            
      "@formatter=#{formatter.class}, @datetime_format=#{datetime_format.inspect}, " \
           
        
      
        
          
- 
            
            
              
            
            
      "@tags=#{tags.inspect}, @header=#{header}, @mode=#{mode}, @age=#{age}, @size=#{size}, " \
           
        
      
        
          
- 
            
            
              
            
            
      "@suffix=#{suffix.inspect}, @entry=#{entry}, @logger=#{logger}>"
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def skip_header? = formatter == :json || formatter.is_a?(Formatters::JSON) || !header
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
            
              
            
            
  # Defines a log entry which can be formatted for output.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  Entry = Data.define :id, :level, :at, :message, :tags, :datetime_format, :payload do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.for(message = nil, **payload, &)
           
        
      
        
          
- 
            
              91
            
            
              
                
                  then: 21
                
              
                
                  else: 70
                
              
            
            
      content = block_given? ? yield : message
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              91
            
            
              
            
            
      new id: payload.delete(:id) || Program.call,
           
        
      
        
          
- 
            
              91
            
            
              
            
            
          level: (payload.delete(:level) || "INFO").upcase,
           
        
      
        
          
- 
            
            
              
            
            
          at: payload.delete(:at) || ::Time.now,
           
        
      
        
          
- 
            
            
              
            
            
          message: sanitize!(content, payload),
           
        
      
        
          
- 
            
            
              
            
            
          tags: Array(payload.delete(:tags)),
           
        
      
        
          
- 
            
            
              
            
            
          datetime_format: payload.delete(:datetime_format) || DATETIME_FORMAT,
           
        
      
        
          
- 
            
            
              
            
            
          payload:
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.for_crash message, error, id:
           
        
      
        
          
- 
            
              10
            
            
              
            
            
      new id:,
           
        
      
        
          
- 
            
            
              
            
            
          level: "FATAL",
           
        
      
        
          
- 
            
            
              
            
            
          message:,
           
        
      
        
          
- 
            
            
              
            
            
          payload: {
           
        
      
        
          
- 
            
            
              
            
            
            error_message: error.message,
           
        
      
        
          
- 
            
            
              
            
            
            error_class: error.class,
           
        
      
        
          
- 
            
            
              
            
            
            backtrace: error.backtrace
           
        
      
        
          
- 
            
            
              
            
            
          }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.sanitize! content, payload
           
        
      
        
          
- 
            
              91
            
            
              
                
                  then: 3
                
              
            
            
      body = if content.is_a? Hash
           
        
      
        
          
- 
            
              6
            
            
              
            
            
               content.delete(:message).tap { payload.merge! content }
           
        
      
        
          
- 
            
            
              
                
                  else: 88
                
              
            
            
             else
           
        
      
        
          
- 
            
              88
            
            
              
            
            
               content
           
        
      
        
          
- 
            
            
              
            
            
             end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              91
            
            
              
                
                  then: 52
                
              
            
            
      if body.is_a? String
           
        
      
        
          
- 
            
              52
            
            
              
            
            
        body.encode "UTF-8", invalid: :replace, undef: :replace, replace: "?"
           
        
      
        
          
- 
            
            
              
                
                  else: 39
                
              
            
            
      else
           
        
      
        
          
- 
            
              39
            
            
              
            
            
        body
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private_class_method :sanitize!
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def initialize id: Program.call,
           
        
      
        
          
- 
            
            
              
            
            
                   level: "INFO",
           
        
      
        
          
- 
            
            
              
            
            
                   at: ::Time.now,
           
        
      
        
          
- 
            
            
              
            
            
                   message: nil,
           
        
      
        
          
- 
            
            
              
            
            
                   tags: Core::EMPTY_ARRAY,
           
        
      
        
          
- 
            
            
              
            
            
                   datetime_format: DATETIME_FORMAT,
           
        
      
        
          
- 
            
            
              
            
            
                   payload: Core::EMPTY_HASH
           
        
      
        
          
- 
            
              108
            
            
              
            
            
      super
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def attributes = {id:, level:, at:, message:, **payload}
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def tagged_attributes tagger: Tag
           
        
      
        
          
- 
            
              22
            
            
              
            
            
      computed_tags = tagger.for(*tags)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              22
            
            
              
                
                  then: 15
                
              
                
                  else: 7
                
              
            
            
      return attributes if computed_tags.empty?
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              7
            
            
              
            
            
      {id:, level:, at:, message:, **computed_tags.to_h, **payload}
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def tagged tagger: Tag
           
        
      
        
          
- 
            
              66
            
            
              
            
            
      attributes.tap do |pairs|
           
        
      
        
          
- 
            
              66
            
            
              
            
            
        computed_tags = tagger.for(*tags)
           
        
      
        
          
- 
            
              66
            
            
              
                
                  else: 65
                
              
                
                  then: 1
                
              
            
            
        pairs[:message] = "#{computed_tags} #{pairs[:message]}" unless computed_tags.empty?
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # An abstract class with common/shared functionality.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      NEW_LINE = "\n"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
      SANITIZERS = {
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        escape: Sanitizers::Escape.new,
           
        
      
        
          
- 
            
            
              
            
            
        filter: Sanitizers::Filter,
           
        
      
        
          
- 
            
            
              
            
            
        format_time: Sanitizers::FormatTime
           
        
      
        
          
- 
            
            
              
            
            
      }.freeze
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize sanitizers: SANITIZERS
           
        
      
        
          
- 
            
              109
            
            
              
            
            
        @sanitizers = sanitizers
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*)
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        fail NoMethodError,
           
        
      
        
          
- 
            
            
              
            
            
             "`#{self.class}##{__method__} #{method(__method__).parameters}` must be implemented."
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      protected
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def sanitize entry, method
           
        
      
        
          
- 
            
              84
            
            
              
            
            
        entry.public_send(method).tap do |attributes|
           
        
      
        
          
- 
            
              84
            
            
              
            
            
          filter attributes
           
        
      
        
          
- 
            
              506
            
            
              
            
            
          attributes.transform_values! { |value| format_time value, format: entry.datetime_format }
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              45
            
            
              
            
            
      def escape(...) = (@escape ||= sanitizers.fetch(__method__)).call(...)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              85
            
            
              
            
            
      def filter(...) = (@filter ||= sanitizers.fetch(__method__)).call(...)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              423
            
            
              
            
            
      def format_time(...) = (@format_time ||= sanitizers.fetch(__method__)).call(...)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :sanitizers
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats by color.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Color < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = "<dynamic>[%<id>s]</dynamic> %<message:dynamic>s"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize template = TEMPLATE, parser: Parsers::Combined.new
           
        
      
        
          
- 
            
              63
            
            
              
            
            
        super()
           
        
      
        
          
- 
            
              63
            
            
              
            
            
        @template = template
           
        
      
        
          
- 
            
              63
            
            
              
            
            
        @parser = parser
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*input)
           
        
      
        
          
- 
            
              45
            
            
              
            
            
        *, entry = input
           
        
      
        
          
- 
            
              45
            
            
              
            
            
        attributes = sanitize entry, :tagged
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              45
            
            
              
            
            
        format(parse(attributes[:level]), attributes).tap(&:strip!) << NEW_LINE
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :template, :parser
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def parse(level) = parser.call template, level
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats fatal crashes.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Crash < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = <<~CONTENT
           
        
      
        
          
- 
            
            
              
            
            
        <dynamic>[%<id>s] [%<level>s] [%<at>s] Crash!
           
        
      
        
          
- 
            
            
              
            
            
          %<message>s
           
        
      
        
          
- 
            
            
              
            
            
          %<error_message>s (%<error_class>s)
           
        
      
        
          
- 
            
            
              
            
            
        %<backtrace>s</dynamic>
           
        
      
        
          
- 
            
            
              
            
            
      CONTENT
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize template = TEMPLATE, parser: Parsers::Combined.new
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        super()
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        @template = template
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        @parser = parser
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*input)
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        *, entry = input
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        attributes = sanitize entry, :tagged
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        attributes[:backtrace] = %(  #{attributes[:backtrace].join "\n  "})
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        format(parse(attributes[:level]), attributes) << NEW_LINE
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :template, :parser
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def parse(level) = parser.call template, level
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats by emoji and color.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Emoji < Color
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = "%<emoji:dynamic>s <dynamic>[%<id>s]</dynamic> %<message:dynamic>s"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize(template = TEMPLATE, ...)
           
        
      
        
          
- 
            
              54
            
            
              
            
            
        super
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "json"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats as JSON output.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class JSON < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = nil
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize template = TEMPLATE, parser: Parsers::Position.new
           
        
      
        
          
- 
            
              16
            
            
              
            
            
        super()
           
        
      
        
          
- 
            
              16
            
            
              
            
            
        @template = template
           
        
      
        
          
- 
            
              16
            
            
              
            
            
        @parser = parser
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*input)
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        *, entry = input
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        attributes = sanitize(entry, :tagged_attributes).tap(&:compact!)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        parser.call(template, attributes).to_json << NEW_LINE
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :template, :parser
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # An abstract class with common functionality.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        TRANSFORMERS = {color: Transformers::Color.new, emoji: Transformers::Emoji.new}.freeze
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize registry: Cogger, transformers: TRANSFORMERS, expressor: Regexp
           
        
      
        
          
- 
            
              41
            
            
              
            
            
          @registry = registry
           
        
      
        
          
- 
            
              41
            
            
              
            
            
          @transformers = transformers
           
        
      
        
          
- 
            
              41
            
            
              
            
            
          @expressor = expressor
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call(_template, **)
           
        
      
        
          
- 
            
              1
            
            
              
            
            
          fail NoMethodError,
           
        
      
        
          
- 
            
            
              
            
            
               "`#{self.class}##{__method__} #{method(__method__).parameters}` must be implemented."
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        protected
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :registry, :transformers, :expressor
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              141
            
            
              
            
            
        def transform_color(...) = (@tranform_color ||= transformers.fetch(:color)).call(...)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              45
            
            
              
            
            
        def transform_emoji(...) = (@transform_emoji ||= transformers.fetch(:emoji)).call(...)
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # Parses template literals, emojis, and keys for specific and dynamic colors.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Combined
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        STEPS = [Element.new, Emoji.new, Key.new].freeze # Order matters.
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize steps: STEPS
           
        
      
        
          
- 
            
              74
            
            
              
            
            
          @steps = steps
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call template, level
           
        
      
        
          
- 
            
              224
            
            
              
            
            
          steps.reduce(template.dup) { |modification, step| step.call modification, level }
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :steps
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # Parses template elements for specific and dynamic colors.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Element < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        PATTERN = %r(
           
        
      
        
          
- 
            
            
              
            
            
          <                  # Tag open start.
           
        
      
        
          
- 
            
            
              
            
            
          (?<directive>\w+)  # Tag open name.
           
        
      
        
          
- 
            
            
              
            
            
          >                  # Tag open end.
           
        
      
        
          
- 
            
            
              
            
            
          (?<content>.+?)    # Content.
           
        
      
        
          
- 
            
            
              
            
            
          </                 # Tag close start.
           
        
      
        
          
- 
            
            
              
            
            
          \w+                # Tag close.
           
        
      
        
          
- 
            
            
              
            
            
          >                  # Tag close end.
           
        
      
        
          
- 
            
            
              
            
            
        )mx
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize pattern: PATTERN
           
        
      
        
          
- 
            
              8
            
            
              
            
            
          super()
           
        
      
        
          
- 
            
              8
            
            
              
            
            
          @pattern = pattern
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call template, level
           
        
      
        
          
- 
            
              63
            
            
              
            
            
          mutate template, level
           
        
      
        
          
- 
            
              63
            
            
              
            
            
          template
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def mutate template, level
           
        
      
        
          
- 
            
              63
            
            
              
            
            
          template.gsub! pattern do
           
        
      
        
          
- 
            
              58
            
            
              
            
            
            captures = expressor.last_match.named_captures
           
        
      
        
          
- 
            
              58
            
            
              
            
            
            transform_color captures["content"], captures["directive"], level
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # Parses template emojis for specific and dynamic colors.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Emoji < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        PATTERN = /
           
        
      
        
          
- 
            
            
              
            
            
          %<                 # Start.
           
        
      
        
          
- 
            
            
              
            
            
          (?<key>emoji)      # Key.
           
        
      
        
          
- 
            
            
              
            
            
          :                  # Delimiter.
           
        
      
        
          
- 
            
            
              
            
            
          (?<directive>\w+)  # Directive.
           
        
      
        
          
- 
            
            
              
            
            
          >s                 # End.
           
        
      
        
          
- 
            
            
              
            
            
        /x
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize pattern: PATTERN
           
        
      
        
          
- 
            
              5
            
            
              
            
            
          super()
           
        
      
        
          
- 
            
              5
            
            
              
            
            
          @pattern = pattern
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call template, level
           
        
      
        
          
- 
            
              60
            
            
              
            
            
          mutate template, level
           
        
      
        
          
- 
            
              60
            
            
              
            
            
          template
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def mutate template, level
           
        
      
        
          
- 
            
              60
            
            
              
            
            
          template.gsub! pattern do
           
        
      
        
          
- 
            
              44
            
            
              
            
            
            captures = expressor.last_match.named_captures
           
        
      
        
          
- 
            
              44
            
            
              
            
            
            transform_emoji captures["key"], captures["directive"], level
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # Parses template for specific and dynamic keys (i.e. string format specifiers).
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Key < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        PATTERN = /
           
        
      
        
          
- 
            
            
              
            
            
          %                                   # Start.
           
        
      
        
          
- 
            
            
              
            
            
          (?<flag>[\s#+-0*])?                 # Optional flag.
           
        
      
        
          
- 
            
            
              
            
            
          \.?                                 # Optional precision.
           
        
      
        
          
- 
            
            
              
            
            
          (?<width>\d+)?                      # Optional width.
           
        
      
        
          
- 
            
            
              
            
            
          <                                   # Reference start.
           
        
      
        
          
- 
            
            
              
            
            
          (?<key>\w+)                         # Key.
           
        
      
        
          
- 
            
            
              
            
            
          :                                   # Delimiter.
           
        
      
        
          
- 
            
            
              
            
            
          (?<directive>\w+)                   # Directive.
           
        
      
        
          
- 
            
            
              
            
            
          >                                   # Reference end.
           
        
      
        
          
- 
            
            
              
            
            
          (?<specifier>[ABEGXabcdefgiopsux])  # Specifier.
           
        
      
        
          
- 
            
            
              
            
            
        /x
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize pattern: PATTERN
           
        
      
        
          
- 
            
              27
            
            
              
            
            
          super()
           
        
      
        
          
- 
            
              27
            
            
              
            
            
          @pattern = pattern
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call template, level
           
        
      
        
          
- 
            
              82
            
            
              
            
            
          mutate template, level
           
        
      
        
          
- 
            
              82
            
            
              
            
            
          template
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def mutate template, level
           
        
      
        
          
- 
            
              82
            
            
              
            
            
          template.gsub! pattern do |match|
           
        
      
        
          
- 
            
              82
            
            
              
            
            
            captures = expressor.last_match.named_captures
           
        
      
        
          
- 
            
              82
            
            
              
            
            
            directive = captures["directive"]
           
        
      
        
          
- 
            
              82
            
            
              
            
            
            match.sub! ":#{directive}", Core::EMPTY_STRING
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              82
            
            
              
            
            
            transform_color match, directive, level
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Parsers
           
        
      
        
          
- 
            
            
              
            
            
      # Parses template and reorders attributes based on template key positions.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Position
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        PATTERN = /
           
        
      
        
          
- 
            
            
              
            
            
          %             # Start.
           
        
      
        
          
- 
            
            
              
            
            
          ?             # Flag, width, or precision.
           
        
      
        
          
- 
            
            
              
            
            
          <             # Reference start.
           
        
      
        
          
- 
            
            
              
            
            
          (?<name>\w+)  # Name.
           
        
      
        
          
- 
            
            
              
            
            
          (?::\w+)?     # Optional delimiter and directive.
           
        
      
        
          
- 
            
            
              
            
            
          >             # Reference end.
           
        
      
        
          
- 
            
            
              
            
            
          ?             # Specifier.
           
        
      
        
          
- 
            
            
              
            
            
        /x
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize pattern: PATTERN
           
        
      
        
          
- 
            
              33
            
            
              
            
            
          @pattern = pattern
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call template, attributes
           
        
      
        
          
- 
            
              28
            
            
              
                
                  else: 11
                
              
                
                  then: 17
                
              
            
            
          return attributes unless String(template).match? pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              11
            
            
              
            
            
          keys = scan template
           
        
      
        
          
- 
            
              11
            
            
              
            
            
          attributes.slice(*keys).merge!(attributes.except(*keys))
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              35
            
            
              
            
            
        def scan(template) = template.scan(pattern).map { |match| match.first.to_sym }
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats as key=value output.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Property < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = nil
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize template = TEMPLATE, parser: Parsers::Position.new
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        super()
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        @template = template
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        @parser = parser
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*input)
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        *, entry = input
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        attributes = sanitize(entry, :tagged_attributes).tap(&:compact!)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        concat(attributes).chop! << NEW_LINE
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :template, :parser
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def concat attributes
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        parser.call(template, attributes).each.with_object(+"") do |(key, value), line|
           
        
      
        
          
- 
            
              44
            
            
              
            
            
          line << key.to_s << "=" << escape(value) << " "
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Sanitizers
           
        
      
        
          
- 
            
            
              
            
            
      # Sanitizes value as fully quoted string for emojis, spaces, and control characters.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Escape
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        PATTERN = /
           
        
      
        
          
- 
            
            
              
            
            
          \A              # Search string start.
           
        
      
        
          
- 
            
            
              
            
            
          .*              # Match zero or more characters.
           
        
      
        
          
- 
            
            
              
            
            
          (               # Conditional start.
           
        
      
        
          
- 
            
            
              
            
            
          (?!\p{Number})  # Look ahead and ignore unicode numbers.
           
        
      
        
          
- 
            
            
              
            
            
          \p{Emoji}       # Match unicode emoji only.
           
        
      
        
          
- 
            
            
              
            
            
          |               # Or.
           
        
      
        
          
- 
            
            
              
            
            
          [[:space:]]     # Match spaces, tabs, and new lines.
           
        
      
        
          
- 
            
            
              
            
            
          |               # Or.
           
        
      
        
          
- 
            
            
              
            
            
          [[:cntrl:]]     # Match control characters.
           
        
      
        
          
- 
            
            
              
            
            
          )               # Conditional end.
           
        
      
        
          
- 
            
            
              
            
            
          .*              # Match zero or more characters.
           
        
      
        
          
- 
            
            
              
            
            
          \z              # Search string end.
           
        
      
        
          
- 
            
            
              
            
            
        /xu
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize pattern: PATTERN
           
        
      
        
          
- 
            
              10
            
            
              
            
            
          @pattern = pattern
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call value
           
        
      
        
          
- 
            
              53
            
            
              
                
                  else: 2
                
              
                
                  then: 51
                
              
            
            
          return dump value unless value.is_a? Array
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              7
            
            
              
            
            
          value.reduce(+"") { |text, item| text << dump(item) << ", " }
           
        
      
        
          
- 
            
              2
            
            
              
            
            
               .then { |text| %([#{text.delete_suffix ", "}]).dump }
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :pattern
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def dump(value) = value.to_s.gsub(pattern, &:dump)
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Sanitizers
           
        
      
        
          
- 
            
            
              
            
            
      # Sanitizes/removes sensitive values.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      Filter = lambda do |attributes, filters: Cogger.filters|
           
        
      
        
          
- 
            
              127
            
            
              
                
                  then: 3
                
              
                
                  else: 35
                
              
            
            
        filters.each { |key| attributes[key] = "[FILTERED]" if attributes.key? key }
           
        
      
        
          
- 
            
              89
            
            
              
            
            
        attributes
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "date"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Sanitizers
           
        
      
        
          
- 
            
            
              
            
            
      # Sanitizes/formats date/time value.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      FormatTime = lambda do |value, format: Cogger::DATETIME_FORMAT|
           
        
      
        
          
- 
            
              428
            
            
              
                
                  else: 89
                
              
                
                  then: 339
                
              
            
            
        return value unless value.is_a?(::Time) || value.is_a?(Date) || value.is_a?(DateTime)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              89
            
            
              
            
            
        value.strftime format
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
            
              
            
            
    # Formats simple templates that require minimal processing.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Simple < Abstract
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      TEMPLATE = "[%<id>s] %<message>s"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize template = TEMPLATE
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        super()
           
        
      
        
          
- 
            
              11
            
            
              
            
            
        @template = template
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call(*input)
           
        
      
        
          
- 
            
              10
            
            
              
            
            
        *, entry = input
           
        
      
        
          
- 
            
              10
            
            
              
            
            
        attributes = sanitize entry, :tagged
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              10
            
            
              
            
            
        format(template, attributes).tap(&:strip!) << NEW_LINE
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :template, :processor
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Transformers
           
        
      
        
          
- 
            
            
              
            
            
      # Transforms target into colorized string.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Color
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize emoji: Emoji::KEY, key_transformer: Key, registry: Cogger
           
        
      
        
          
- 
            
              6
            
            
              
            
            
          @emoji = emoji
           
        
      
        
          
- 
            
              6
            
            
              
            
            
          @key_transformer = key_transformer
           
        
      
        
          
- 
            
              6
            
            
              
            
            
          @registry = registry
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call target, directive, level
           
        
      
        
          
- 
            
              145
            
            
              
                
                  then: 2
                
              
                
                  else: 143
                
              
            
            
          return target if !target.is_a?(String) || target == emoji
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              143
            
            
              
            
            
          key = key_transformer.call directive, level
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              143
            
            
              
                
                  then: 142
                
              
                
                  else: 1
                
              
            
            
          return client.encode target, key if aliases.key?(key) || defaults.key?(key)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
          target
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :emoji, :key_transformer, :registry
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def aliases = registry.aliases
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def defaults = client.defaults
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def client = registry.color
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Transformers
           
        
      
        
          
- 
            
            
              
            
            
      # Transforms target into emoji.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      class Emoji
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        KEY = "emoji"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def initialize key = KEY, key_transformer: Key, registry: Cogger
           
        
      
        
          
- 
            
              5
            
            
              
            
            
          @key = key
           
        
      
        
          
- 
            
              5
            
            
              
            
            
          @key_transformer = key_transformer
           
        
      
        
          
- 
            
              5
            
            
              
            
            
          @registry = registry
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def call target, directive, level
           
        
      
        
          
- 
            
              48
            
            
              
                
                  else: 47
                
              
                
                  then: 1
                
              
            
            
          return target unless target == key
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              47
            
            
              
            
            
          key = key_transformer.call directive, level
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              47
            
            
              
                
                  then: 46
                
              
                
                  else: 1
                
              
            
            
          registry.aliases.key?(key) ? registry.get_emoji(key) : target
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :key, :key_transformer, :registry
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Formatters
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Transformers
           
        
      
        
          
- 
            
            
              
            
            
      # Transforms directive, based on log level, into a key for color or emoji lookup.
           
        
      
        
          
- 
            
              194
            
            
              
                
                  then: 160
                
              
                
                  else: 33
                
              
            
            
      Key = -> directive, level { (directive == "dynamic" ? level.downcase : directive).to_sym }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "forwardable"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "logger"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/hash"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
            
              
            
            
  # Loads configuration and simultaneously sends messages to multiple streams.
           
        
      
        
          
- 
            
            
              
            
            
  # :reek:TooManyMethods
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  class Hub
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    extend Forwardable
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    using Refinements::Hash
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    using Refines::Logger
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    delegate %i[
           
        
      
        
          
- 
            
            
              
            
            
      close
           
        
      
        
          
- 
            
            
              
            
            
      reopen
           
        
      
        
          
- 
            
            
              
            
            
      debug!
           
        
      
        
          
- 
            
            
              
            
            
      debug?
           
        
      
        
          
- 
            
            
              
            
            
      info!
           
        
      
        
          
- 
            
            
              
            
            
      info?
           
        
      
        
          
- 
            
            
              
            
            
      warn!
           
        
      
        
          
- 
            
            
              
            
            
      warn?
           
        
      
        
          
- 
            
            
              
            
            
      error!
           
        
      
        
          
- 
            
            
              
            
            
      error?
           
        
      
        
          
- 
            
            
              
            
            
      fatal!
           
        
      
        
          
- 
            
            
              
            
            
      fatal?
           
        
      
        
          
- 
            
            
              
            
            
      formatter
           
        
      
        
          
- 
            
            
              
            
            
      formatter=
           
        
      
        
          
- 
            
            
              
            
            
      level
           
        
      
        
          
- 
            
            
              
            
            
      level=
           
        
      
        
          
- 
            
            
              
            
            
    ] => :primary
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    delegate %i[id io tags mode age size suffix] => :configuration
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def initialize(registry: Cogger, model: Configuration, **attributes)
           
        
      
        
          
- 
            
              57
            
            
              
            
            
      @registry = registry
           
        
      
        
          
- 
            
              57
            
            
              
            
            
      @configuration = model[**find_formatter(attributes)]
           
        
      
        
          
- 
            
              57
            
            
              
            
            
      @primary = configuration.to_logger
           
        
      
        
          
- 
            
              57
            
            
              
            
            
      @streams = [@primary]
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_stream **attributes
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attributes[:id] = configuration.id
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      streams.append configuration.with(**find_formatter(attributes)).to_logger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def debug(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def info(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def warn(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def error(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def fatal(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def any(message = nil, **, &) = log(__method__, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def abort(message = nil, **payload, &block)
           
        
      
        
          
- 
            
              4
            
            
              
                
                  then: 3
                
              
                
                  else: 1
                
              
            
            
      error(message, **payload, &block) if message || !payload.empty? || block
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      exit false
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add(level, message = nil, **, &)
           
        
      
        
          
- 
            
              3
            
            
              
            
            
      log(Logger::SEV_LABEL.fetch(level, "ANY").downcase, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    alias unknown any
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def reread = primary.reread
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def inspect
           
        
      
        
          
- 
            
              7
            
            
              
            
            
      %(#<#{self.class} #{configuration.inspect.delete_prefix! "#<Cogger::Configuration "})
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    attr_reader :registry, :configuration, :primary, :streams
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
    # :reek:FeatureEnvy
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def find_formatter attributes
           
        
      
        
          
- 
            
              58
            
            
              
            
            
      attributes.transform_value! :formatter do |value|
           
        
      
        
          
- 
            
              16
            
            
              
                
                  else: 8
                
              
                
                  then: 8
                
              
            
            
        next value unless value.is_a?(Symbol) || value.is_a?(String)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              8
            
            
              
            
            
        formatter, template = registry.get_formatter value
           
        
      
        
          
- 
            
              8
            
            
              
                
                  then: 1
                
              
                
                  else: 7
                
              
            
            
        template ? formatter.new(template) : formatter.new
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def log(level, message = nil, **, &)
           
        
      
        
          
- 
            
              46
            
            
              
            
            
      dispatch(level, message, **, &)
           
        
      
        
          
- 
            
            
              
            
            
    rescue StandardError => error
           
        
      
        
          
- 
            
              7
            
            
              
            
            
      crash message, error
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
    # rubocop:todo Metrics/MethodLength
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def dispatch(level, message, **payload, &)
           
        
      
        
          
- 
            
              46
            
            
              
            
            
      entry = configuration.entry.for(
           
        
      
        
          
- 
            
            
              
            
            
        message,
           
        
      
        
          
- 
            
            
              
            
            
        id: configuration.id,
           
        
      
        
          
- 
            
            
              
            
            
        level:,
           
        
      
        
          
- 
            
            
              
            
            
        tags: configuration.entag(payload.delete(:tags)),
           
        
      
        
          
- 
            
            
              
            
            
        datetime_format: configuration.datetime_format,
           
        
      
        
          
- 
            
            
              
            
            
        **payload,
           
        
      
        
          
- 
            
            
              
            
            
        &
           
        
      
        
          
- 
            
            
              
            
            
      )
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              138
            
            
              
            
            
      configuration.mutex.synchronize { streams.each { |logger| logger.public_send level, entry } }
           
        
      
        
          
- 
            
              39
            
            
              
            
            
      true
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
    # rubocop:enable Metrics/MethodLength
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def crash message, error
           
        
      
        
          
- 
            
              7
            
            
              
            
            
      configuration.with(id: :cogger, io: $stdout, formatter: Formatters::Crash.new)
           
        
      
        
          
- 
            
            
              
            
            
                   .to_logger
           
        
      
        
          
- 
            
            
              
            
            
                   .fatal configuration.entry.for_crash(message, error, id: configuration.id)
           
        
      
        
          
- 
            
              7
            
            
              
            
            
      true
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "logger"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/array"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
# Loads log level from environment.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  using Refinements::Array
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  Level = lambda do |logger = Logger, environment: ENV, allowed: LEVELS|
           
        
      
        
          
- 
            
              36
            
            
              
            
            
    value = String environment.fetch("LOG_LEVEL", "INFO")
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              36
            
            
              
                
                  then: 35
                
              
                
                  else: 1
                
              
            
            
    return logger.const_get value.upcase if allowed.include? value.downcase
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    fail ArgumentError, %(Invalid log level: #{value.inspect}. Use: #{allowed.to_usage "or"}.)
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "pathname"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
            
              
            
            
# Computes default program name based on current file name.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  Program = lambda do |name = $PROGRAM_NAME|
           
        
      
        
          
- 
            
              250
            
            
              
            
            
    Pathname(name).then { |path| path.basename(path.extname).to_s }
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Rack
           
        
      
        
          
- 
            
            
              
            
            
    # Middlware for enriched logging based on the incoming request.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Logger
           
        
      
        
          
- 
            
            
              
            
            
      DEFAULTS = {
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        logger: Cogger.new(formatter: :json),
           
        
      
        
          
- 
            
            
              
            
            
        timer: Cogger::Time::Span.new,
           
        
      
        
          
- 
            
            
              
            
            
        key_map: {
           
        
      
        
          
- 
            
            
              
            
            
          verb: "REQUEST_METHOD",
           
        
      
        
          
- 
            
            
              
            
            
          ip: "REMOTE_ADDR",
           
        
      
        
          
- 
            
            
              
            
            
          path: "PATH_INFO",
           
        
      
        
          
- 
            
            
              
            
            
          params: "QUERY_STRING",
           
        
      
        
          
- 
            
            
              
            
            
          length: "CONTENT_LENGTH"
           
        
      
        
          
- 
            
            
              
            
            
        }
           
        
      
        
          
- 
            
            
              
            
            
      }.freeze
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize application, options = Core::EMPTY_HASH, defaults: DEFAULTS
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        configuration = defaults.merge options
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        @application = application
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        @logger = configuration.fetch :logger
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        @timer = configuration.fetch :timer
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        @key_map = configuration.fetch :key_map
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call environment
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        request = ::Rack::Request.new environment
           
        
      
        
          
- 
            
              8
            
            
              
            
            
        (status, headers, body), duration, unit = timer.call { application.call environment }
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        logger.info tags: [tags_for(request), {status:, duration:, unit:}]
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        [status, headers, body]
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :application, :logger, :timer, :key_map
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def tags_for request
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        key_map.each_key.with_object({}) do |tag, collection|
           
        
      
        
          
- 
            
              20
            
            
              
            
            
          key = key_map.fetch tag, tag
           
        
      
        
          
- 
            
              20
            
            
              
            
            
          collection[String(tag).downcase] = request.get_header key
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "logger"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/string_io"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Refines
           
        
      
        
          
- 
            
            
              
            
            
    # Provides additional enhancements to a log device.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module LogDevice
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      using Refinements::StringIO
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      refine ::Logger::LogDevice do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def reread
           
        
      
        
          
- 
            
              11
            
            
              
                
                  when: 2
                
              
            
            
          case dev
           
        
      
        
          
- 
            
              2
            
            
              
                
                  when: 7
                
              
            
            
            when ::File then dev.class.new(dev).read
           
        
      
        
          
- 
            
              7
            
            
              
                
                  else: 2
                
              
            
            
            when ::StringIO then dev.reread
           
        
      
        
          
- 
            
              2
            
            
              
            
            
            else ""
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Refines
           
        
      
        
          
- 
            
            
              
            
            
    # Provides additional enhancements to a logger.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    module Logger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      using LogDevice
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      refine ::Logger do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        def reread = @logdev.reread
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        alias_method :any, :unknown
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/hash"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "tone"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
            
              
            
            
  # Provides a global regsitry for global configuration.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Registry
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    using Refinements::Hash
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.extended descendant
           
        
      
        
          
- 
            
              38
            
            
              
            
            
      descendant.add_alias(:debug, :white)
           
        
      
        
          
- 
            
            
              
            
            
                .add_alias(:info, :green)
           
        
      
        
          
- 
            
            
              
            
            
                .add_alias(:warn, :yellow)
           
        
      
        
          
- 
            
            
              
            
            
                .add_alias(:error, :red)
           
        
      
        
          
- 
            
            
              
            
            
                .add_alias(:fatal, :bold, :white, :on_red)
           
        
      
        
          
- 
            
            
              
            
            
                .add_alias(:any, :dim, :bright_white)
           
        
      
        
          
- 
            
            
              
            
            
                .add_emojis(
           
        
      
        
          
- 
            
            
              
            
            
                  debug: "๐",
           
        
      
        
          
- 
            
            
              
            
            
                  info: "๐ข",
           
        
      
        
          
- 
            
            
              
            
            
                  warn: "โ ๏ธ",
           
        
      
        
          
- 
            
            
              
            
            
                  error: "๐",
           
        
      
        
          
- 
            
            
              
            
            
                  fatal: "๐ฅ",
           
        
      
        
          
- 
            
            
              
            
            
                  any: "โซ๏ธ"
           
        
      
        
          
- 
            
            
              
            
            
                )
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(:color, Cogger::Formatters::Color)
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(
           
        
      
        
          
- 
            
            
              
            
            
                  :detail,
           
        
      
        
          
- 
            
            
              
            
            
                  Cogger::Formatters::Simple,
           
        
      
        
          
- 
            
            
              
            
            
                  "[%<id>s] [%<level>s] [%<at>s] %<message>s"
           
        
      
        
          
- 
            
            
              
            
            
                )
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(:emoji, Cogger::Formatters::Emoji)
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(:json, Cogger::Formatters::JSON)
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(:property, Cogger::Formatters::Property)
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter(:simple, Cogger::Formatters::Simple)
           
        
      
        
          
- 
            
            
              
            
            
                .add_formatter :rack,
           
        
      
        
          
- 
            
            
              
            
            
                               Cogger::Formatters::Simple,
           
        
      
        
          
- 
            
            
              
            
            
                               "[%<id>s] [%<level>s] [%<at>s] %<verb>s %<status>s " \
           
        
      
        
          
- 
            
            
              
            
            
                               "%<duration>s %<ip>s %<path>s %<length>s %<params>s"
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_alias(key, *styles)
           
        
      
        
          
- 
            
              230
            
            
              
            
            
      color.add_alias(key, *styles)
           
        
      
        
          
- 
            
              230
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def aliases = color.aliases
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_emoji key, value
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      warn "`#{self.class}##{__method__}` is deprecated, use `#add_emojis` instead.",
           
        
      
        
          
- 
            
            
              
            
            
           category: :deprecated
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      emojis[key.to_sym] = value
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_emojis(**attributes)
           
        
      
        
          
- 
            
              44
            
            
              
            
            
      emojis.merge! attributes.symbolize_keys!
           
        
      
        
          
- 
            
              44
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def get_emoji key
           
        
      
        
          
- 
            
              52
            
            
              
            
            
      emojis.fetch(key.to_sym) { fail KeyError, "Unregistered emoji: #{key}." }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def emojis = @emojis ||= {}
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_filter key
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      warn "`#{self.class}##{__method__}` is deprecated, use `#add_filters` instead.",
           
        
      
        
          
- 
            
            
              
            
            
           category: :deprecated
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      filters.add key.to_sym
           
        
      
        
          
- 
            
              4
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_filters(*keys)
           
        
      
        
          
- 
            
              5
            
            
              
            
            
      filters.merge(keys.map(&:to_sym))
           
        
      
        
          
- 
            
              5
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def filters = @filters ||= Set.new
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def add_formatter key, formatter, template = nil
           
        
      
        
          
- 
            
              274
            
            
              
            
            
      formatters[key.to_sym] = [formatter, template || formatter::TEMPLATE]
           
        
      
        
          
- 
            
              273
            
            
              
            
            
      self
           
        
      
        
          
- 
            
            
              
            
            
    rescue NameError
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      raise NameError, "#{formatter}::TEMPLATE must be defined with a default template string."
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def get_formatter key
           
        
      
        
          
- 
            
              16
            
            
              
            
            
      formatters.fetch(key.to_sym) { fail KeyError, "Unregistered formatter: #{key}." }
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def formatters = @formatters ||= {}
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def templates
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      formatters.each.with_object({}) do |(key, (_formatter, template)), collection|
           
        
      
        
          
- 
            
              7
            
            
              
            
            
        collection[key] = template
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def color = @color ||= Tone.new
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def defaults = {emojis:, aliases:, formatters:, filters:, color:}
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "core"
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "refinements/hash"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
            
              
            
            
  # Models a tag which may consist of an array and/or hash.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  Tag = Data.define :singles, :pairs do
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    using Refinements::Hash
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.for(*bag)
           
        
      
        
          
- 
            
              93
            
            
              
            
            
      bag.each.with_object new do |item, tag|
           
        
      
        
          
- 
            
              34
            
            
              
                
                  then: 3
                
              
                
                  else: 31
                
              
            
            
        value = item.is_a?(Proc) ? item.call : item
           
        
      
        
          
- 
            
              34
            
            
              
                
                  then: 17
                
              
                
                  else: 17
                
              
            
            
        value.is_a?(Hash) ? tag.pairs.merge!(value) : tag.singles.append(value)
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def initialize singles: [], pairs: {}
           
        
      
        
          
- 
            
              116
            
            
              
            
            
      super
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def empty? = singles.empty? && pairs.empty?
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              12
            
            
              
                
                  then: 1
                
              
                
                  else: 10
                
              
            
            
    def to_h = empty? ? Core::EMPTY_HASH : {tags: singles.to_a, **pairs}.tap(&:compress!)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              6
            
            
              
                
                  then: 1
                
              
                
                  else: 4
                
              
            
            
    def to_s = empty? ? Core::EMPTY_STRING : "#{format_singles} #{format_pairs}".tap(&:strip!)
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def format_singles
           
        
      
        
          
- 
            
              11
            
            
              
            
            
      singles.map { |value| "[#{value}]" }
           
        
      
        
          
- 
            
            
              
            
            
             .join " "
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def format_pairs
           
        
      
        
          
- 
            
              8
            
            
              
            
            
      pairs.map { |key, value| "[#{key}=#{value}]" }
           
        
      
        
          
- 
            
            
              
            
            
           .join(" ")
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Time
           
        
      
        
          
- 
            
            
              
            
            
    # An adapter for acquiring current time.
           
        
      
        
          
- 
            
              12
            
            
              
            
            
    Clock = -> id = Process::CLOCK_MONOTONIC, unit: :nanosecond { Process.clock_gettime id, unit }
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Time
           
        
      
        
          
- 
            
            
              
            
            
    RANGE = {
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      nanoseconds: ...1_000,
           
        
      
        
          
- 
            
            
              
            
            
      microseconds: 1_000...1_000_000,
           
        
      
        
          
- 
            
            
              
            
            
      milliseconds: 1_000_000...1_000_000_000,
           
        
      
        
          
- 
            
            
              
            
            
      seconds: 1_000_000_000...60_000_000_000,
           
        
      
        
          
- 
            
            
              
            
            
      minutes: 60_000_000_000...
           
        
      
        
          
- 
            
            
              
            
            
    }.freeze
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Time
           
        
      
        
          
- 
            
            
              
            
            
    # Measures duration of a process with nanosecond precision.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    class Span
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def initialize clock = Clock, unit: Unit, range: RANGE
           
        
      
        
          
- 
            
              6
            
            
              
            
            
        @clock = clock
           
        
      
        
          
- 
            
              6
            
            
              
            
            
        @unit = unit
           
        
      
        
          
- 
            
              6
            
            
              
            
            
        @range = range
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def call
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        start = current
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        result = yield
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        span = current - start
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        [result, duration(span), unit.call(span)]
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      attr_reader :clock, :unit, :range
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def duration value
           
        
      
        
          
- 
            
              9
            
            
              
                
                  when: 1
                
              
            
            
        case value
           
        
      
        
          
- 
            
              1
            
            
              
                
                  when: 5
                
              
            
            
          when nanoseconds then value
           
        
      
        
          
- 
            
              5
            
            
              
                
                  when: 1
                
              
            
            
          when microseconds then value / microseconds.min
           
        
      
        
          
- 
            
              1
            
            
              
                
                  when: 1
                
              
            
            
          when milliseconds then value / milliseconds.min
           
        
      
        
          
- 
            
              1
            
            
              
                
                  else: 1
                
              
            
            
          when seconds then value / seconds.min
           
        
      
        
          
- 
            
              1
            
            
              
            
            
          else value / minutes.min
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def current = clock.call
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def nanoseconds
           
        
      
        
          
- 
            
              9
            
            
              
            
            
        @nanoseconds ||= range.fetch __method__
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def microseconds
           
        
      
        
          
- 
            
              13
            
            
              
            
            
        @microseconds ||= range.fetch __method__
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def milliseconds
           
        
      
        
          
- 
            
              4
            
            
              
            
            
        @milliseconds ||= range.fetch __method__
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def seconds
           
        
      
        
          
- 
            
              3
            
            
              
            
            
        @seconds ||= range.fetch __method__
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
      def minutes
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        @minutes ||= range.fetch __method__
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end
           
        
      
    
  
 
      
        
  
  
    
      
        
          
- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Cogger
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  module Time
           
        
      
        
          
- 
            
            
              
            
            
    # Provides unit of measure for duration.
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    Unit = lambda do |duration, range: RANGE|
           
        
      
        
          
- 
            
              14
            
            
              
                
                  when: 2
                
              
            
            
      case duration
           
        
      
        
          
- 
            
              2
            
            
              
                
                  when: 6
                
              
            
            
        when range.fetch(:nanoseconds) then "ns"
           
        
      
        
          
- 
            
              6
            
            
              
                
                  when: 2
                
              
            
            
        when range.fetch(:microseconds) then "ยตs"
           
        
      
        
          
- 
            
              2
            
            
              
                
                  when: 2
                
              
            
            
        when range.fetch(:milliseconds) then "ms"
           
        
      
        
          
- 
            
              2
            
            
              
                
                  else: 2
                
              
            
            
        when range.fetch(:seconds) then "s"
           
        
      
        
          
- 
            
              2
            
            
              
            
            
        else "m"
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end