module JLo
  #
  # This formatter (a.k.a. `J.Lo`) turns log events into pure love (and
  # JSON).  Use it on your stdlib logger like this:
  #
  #   logger.formatter = J.Lo
  #
  class JSONEvent
    # Let's be explicit about the used Logstash schema.
    # (see https://logstash.jira.com/browse/LOGSTASH-675)
    LOGSTASH_SCHEMA_VERSION = '1'

    class << self
      # This is the interface required by a Logger Formatter.
      def call(*args)
        new(*args).to_s
      end
    end

    def initialize(severity, time, progname, message)
      @severity, @time, @progname, @message =
        severity, time, progname, message
    end

    # @returns [String] JSON-ified event data on a single line
    def to_s
      to_json + "\n"
    end

    # @returns [String] JSON-ified event data
    def to_json
      data.to_json
    end

    # @returns [Hash] all the fancy event data
    def to_hash
      data
    end

    private

    # @returns [Hash] event as hash
    def data
      message.merge :@timestamp => timestamp,
                    :@version   => version,
                    :severity   => @severity,
                    :progname   => @progname
    end

    # @returns [String] ISO8601-compliant timestamp
    def timestamp
      @time.iso8601
    end

    # @returns [String] Used Logstash schema version
    def version
      LOGSTASH_SCHEMA_VERSION
    end

    # @returns [Hash] actual log message
    def message
      if @message.is_a? String
        { :message => @message }
      elsif @message.is_a? Hash
        @message
      elsif is_an_exception?(@message)
        {
          :exception => @message.class,
          :message => @message.message,
          :backtrace => @message.backtrace.join("\n")
        }
      end
    end

    # @returns [Boolean] true if exception, otherwise false
    def is_an_exception?(obj)
      [:message, :backtrace].all?{ |m| obj.respond_to?(m) }
    end
  end
end
