require "time" require "colorize" module Logger annotation LoggerWatcher end struct LOG_LEVEL getter value : Int32 getter color : Symbol delegate in?, to: @value def initialize(@value : Int32, @color : Symbol) end def to_s LOG_LEVELS.keys[@value].to_s.downcase end {% for op, i in %w[ < > == <= >= ] %} def {{op.id}} (other : LOG_LEVEL) @value {{op.id}} other.value end {% end %} end LOG_LEVELS = { "DEBUG" => LOG_LEVEL.new(value: 0, color: :green), "INFO" => LOG_LEVEL.new(value: 1, color: :blue), "WARN" => LOG_LEVEL.new(value: 2, color: :yellow), "ERROR" => LOG_LEVEL.new(value: 3, color: :red), "FATAL" => LOG_LEVEL.new(value: 4, color: :red) } @@min_level : LOG_LEVEL = LOG_LEVELS["INFO"] @@max_level : LOG_LEVEL = LOG_LEVELS["FATAL"] @@debug : Bool = false LOG_MUTEX = ::Mutex.new macro generate_log_line {% verbatim do %} {% if @type && @def %} "{{(@type.module? ? "Module" : "Class").id}}({{@type.name.id}})" + " : " + "Method({{@def.name}})" + " : " {% elsif @type %} "{{(@type.module? ? "Module" : "Class").id}}({{@type.name.id}})" + " : " {% elsif @def %} "Method({{@def.name}})" + " : " {% else %} {{message}} {% end %} {% end %} end {% for level in LOG_LEVELS.keys %} macro {{level.downcase.id}}(message) ::Logger.log {{level}}, Logger.generate_log_line + \{{message}} end {% end %} protected def self.synchronize(&block : -> ) LOG_MUTEX.synchronize do yield end end def self.debug? : Bool LOG_MUTEX.synchronize do @@debug end end {% for level in %w[ min max ] %} def self.{{level.id}}=(selection : String) : Nil Logger.debug "Entering with #{selection}" raise "ERROR : {{level.id}}= : Invalid level" unless _level = LOG_LEVELS[selection.upcase] synchronize { @@{{level.id}}_level = _level } end def self.{{level.id}} : String @@{{level.id}}_level.to_s.downcase end {% end %} def self.valid?(level : LOG_LEVEL) : Bool level.in?(@@min_level.value..@@max_level.value) end def self.debug= (state : Bool) : Nil synchronize { @@debug = state } Logger.debug "Debug set to #{state}" end def self.log(level : String, message : String) _level = LOG_LEVELS[level] if valid?(_level) || debug? synchronize { time = Time.local STDERR.puts [time, level.to_s.colorize(_level.color), message].join(" : ") raise "ERROR : Fatal error detected (#{message})" if level == "FATAL" } end end end