Skip to content

Instantly share code, notes, and snippets.

@bcardiff
Created April 16, 2018 17:36
Show Gist options
  • Save bcardiff/ea21543eff6437c508abb48c060116ef to your computer and use it in GitHub Desktop.
Save bcardiff/ea21543eff6437c508abb48c060116ef to your computer and use it in GitHub Desktop.
Logger POC with lazy init
# A Logger allow sending logging information to a stream.
# Each logger instance is built and binded to a specific
# context that is sent on each entry.
#
# When requesting a logger via `Logger#get` a context needs to be
# specified. Context are meant to be dot seperated path as:
# `"http.client"`. Class names and modules are translated into that format.
#
# ```
# class HTTP::Client
# @@logger = Logger.get self # Same as Logger.get "http.client"
# # ...
# end
# ```
struct Logger2
enum Severity
DEBUG
INFO
end
# Handlers are responsible of sending the log entry to the
# actual stream
abstract class Handler
abstract def log(severity : Severity, message, context : String)
end
@handler : Handler?
private def initialize(@context : String)
end
def log(severity, message)
handler = @handler ||= @@handler_factory.call(@context)
handler.log(severity, message, @context)
end
{% for name in Logger2::Severity.constants %}
def {{name.id.downcase}}(message)
log(Logger2::Severity::{{name.id}}, message)
end
{% end %}
def self.get(context : Class) : Logger2
get(context.name.gsub(/::/, ".").downcase)
end
def self.get(context : String) : Logger2
new(context)
end
@@handler_factory : String -> Handler = ->(context : String) { NullLoggerHandler.new.as(Handler) }
# Set handler factory to be used in `Logger.get`
def self.set_handler_factory(&block : String -> Handler)
@@handler_factory = block
end
end
class NullLoggerHandler < Logger2::Handler
def log(severity, message, context)
end
end
# A IO logger with severity level filtering
class BasicLoggerHandler < Logger2::Handler
property level = Logger2::Severity::INFO
def initialize(@io : IO = STDOUT)
end
def log(severity, message, context)
return if severity < level
label = severity.to_s
@io << label[0] << ", [" << Time.now << " #" << Process.pid << "] "
@io << label.rjust(5) << " -- " << context << ": " << message.to_s
@io.puts
@io.flush
end
end
# Out of stdlib
# App code
class Foo
@@logger = Logger2.get "app.foo"
@bar = App::Bar.new
def do
@@logger.info "doing do"
@bar.do_to
end
end
module App
class Bar
@@logger = Logger2.get self
def do_to
@@logger.debug "doing do to"
end
end
end
# Allow apps to define logger handler based on context
# Apps / frameworks are resposible of initializing
# configurations
Logger2.set_handler_factory do |context|
BasicLoggerHandler.new.tap do |handler|
handler.level = Logger2::Severity::DEBUG if context =~ /^app\./
end
end
foo = Foo.new
foo.do
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment