diff --git a/src/logger.cr b/src/logger.cr index 866c44b..e9f373e 100644 --- a/src/logger.cr +++ b/src/logger.cr @@ -1,120 +1,55 @@ -require "time" -require "colorize" +require "log" module Logger - - annotation LoggerWatcher - end - - struct LOG_LEVEL - getter value : Int32 - getter color : Symbol - delegate in?, to: @value - - def initialize(@value : Int32, @color : Symbol) + macro included + annotation LogContext end - def to_s - LOG_LEVELS.keys[@value].to_s.downcase - end + Log = ::Log - {% 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"] - @@log_file : String = "" - @@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 + macro finished + {% defined_level_methods = [] of MacroId %} + {% levels = %i[ debug info notice error fatal ] %} + {% for level in levels %} + {% defined_level_methods << level if @type.has_method? level %} + {% end %} + {% raise "ERROR : You can't include ::Logger when you have the following defined as instance methods: #{defined_level_methods.join(", ").id}" unless defined_level_methods.empty? %} + end - {% for level in LOG_LEVELS.keys %} - macro {{level.downcase.id}}(message, *args) - ::Logger.log({{level}}, Logger.generate_log_line + \{{message}}, \{{*args}}) - 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 - - def self.min=(selection : String) : Nil - Logger.debug "Entering with #{selection}" - raise "ERROR : {{level.id}}= : Invalid level" unless _level = LOG_LEVELS[selection.upcase] - synchronize { - @@min_level = _level - } - end - - def self.min : String - @@min_level.to_s.downcase - end - - def self.log_file=(@@log_file : String) - 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, *args) : Nil - _level = LOG_LEVELS[level] - message = message % args unless args.empty? - if valid?(_level) || debug? - synchronize { - time = Time.local - message = [time, level.to_s.colorize(_level.color), message].join(" : ") - - STDERR.puts message - - unless @@log_file.empty? - File.open(@@log_file, "a") do |file| - file.puts message + macro log_with_context(level, message) + {% if @type.class? %} + {% if vars = @type.instance_vars.select(&.annotation(LogContext)) %} + Log.with_context( {% for var in vars %} {{var.name}}: @{{var.name}}, {% end %} ) do + Log.{{level}} { [ generate_log_line, {{message}}].join(" : ") } end - end - raise "ERROR : Fatal error detected (#{message})" if level == "FATAL" - } - end + {% else %} + Log.{{level}} { [ generate_log_line, {{message}}].join(" : ") } + {% end %} + {% else %} + Log.{{level}} { [ generate_log_line, {{message}}].join(" : ") } + {% end %} + end + + macro generate_log_line + {% verbatim do %} + {% if @type && @def %} + "{{(@type.module? ? "Module" : "Class").id}}({{@type.name}})" + " : " + "Method({{@def.name}})" + {% elsif @type %} + "{{(@type.module? ? "Module" : "Class").id}}({{@type.name}})" + {% elsif @def %} + "Method({{@def.name}})" + {% else %} + {{message}} + {% end %} + {% end %} + end + + {% for level in %i[ trace debug info notice error fatal ].map(&.id) %} + macro {{level.downcase}}(message, *args) + log_with_context {{level}}, (\{{message}} \{% unless args.empty? %} % \{{args}} \{% end %}) + end + {% end %} + {% end %} end end