Moved the majority of the macros outside of the finished block. Un-needed

This commit is contained in:
Tristan Ancelet
2026-08-31 12:28:38 -05:00
parent 7b0d516408
commit b4f00010c2
+65 -53
View File
@@ -1,16 +1,70 @@
require "log" require "log"
module Logger module Logger
# This allows the user to mark an instance variable to be kept as context when
# any ::Logger generated macro is used within and outside of class/instance methods
annotation LogContext
end
# Tells the ::Logger macros that if any log macros get run in a annotated method
# that it will keep track of the arguments of the method as it runs. Alongside
# providing the user the ability to exclude arguments (like when passing a
# plain text password into a method)
#
# For this you will need to make sure to use the exclude: key with an array of
# method names (strings %w[ abc ] is easiest)
annotation LogMethod
end
# Macro for doing the actual logging based on how the user has
# the Logger annotations
private macro log_with_context(level, message)
{% if @def && @def.annotation(LogMethod) %}
{% anno = @def.annotation(LogMethod) %}
{% exclude = (anno[:exclude] || [] of MacroId).map(&.id) %}
{% args = @def.args.reject{|a| exclude.includes?(a.name)} %}
{% unless args.empty? %}
Log.with_context( {% for arg in args %} {{arg.name}}: {{arg.name}}, {% end %} ) do
Log.{{level}} { generate_log_line {{message}} }
end
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% elsif @type && @def %}
{% if @type.class? && @type.methods.includes?(@def) %}
{% 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}} }
end
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% elsif @type.module? %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
end
# Generates the log-line (everything that isn't ::Log managed)
private macro generate_log_line(message)
{% if @def %}
[ "Method({{@def.name}})", {{message}} ].join(" : ")
{% else %}
{{message}}
{% end %}
end
{% for level in %i[ trace debug info notice warn error fatal ].map(&.id) %}
# Macro for running ::Log.{{level}} with message and splat args
macro {{level.downcase}}(message, *args)
log_with_context {{level}}, (\{{message}} \{% unless args.empty? %} % \{{args}} \{% end %})
end
{% end %}
macro included macro included
annotation LogContext
end
annotation LogMethod
end
annotation LogConfig
end
{% if @type && ! @type.has_constant?("Log") %} {% if @type && ! @type.has_constant?("Log") %}
Log = ::Log.for(self) Log = ::Log.for(self)
{% end %} {% end %}
@@ -22,52 +76,10 @@ module Logger
{% for level in levels %} {% for level in levels %}
{% defined_level_methods << level if @type.has_method? level %} {% defined_level_methods << level if @type.has_method? level %}
{% end %} {% 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? %} {% unless defined_level_methods.empty? %}
end {% raise "ERROR : You can't include ::Logger when you have the following defined as instance methods: #{defined_level_methods.join(", ").id}" %}
macro log_with_context(level, message)
{% if @def && @def.annotation(LogMethod) %}
{% anno = @def.annotation(LogMethod) %}
{% exclude = (anno[:exclude] || [] of MacroId).map(&.id) %}
{% args = @def.args.reject{|a| exclude.includes?(a.name)} %}
{% unless args.empty? %}
Log.with_context( {% for arg in args %} {{arg.name}}: {{arg.name}}, {% end %} ) do
Log.{{level}} { generate_log_line {{message}} }
end
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% elsif @type %}
{% if @type.class? %}
{% class_def = @type.methods.includes?(@def) %}
{% if (vars = @type.instance_vars.select(&.annotation(LogContext))) && class_def %}
Log.with_context( {% for var in vars %} {{var.name}}: @{{var.name}}, {% end %} ) do
Log.{{level}} { generate_log_line {{message}} }
end
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% elsif @type.module? %}
Log.{{level}} { generate_log_line {{message}} }
{% end %}
{% else %}
Log.{{level}} { generate_log_line {{message}} }
{% end %} {% end %}
end end
macro generate_log_line(message)
{% if @def %}
[ "Method({{@def.name}})", {{message}}].join(" : ")
{% else %}
{{message}}
{% end %}
end
{% for level in %i[ trace debug info notice warn error fatal ].map(&.id) %}
macro {{level.downcase}}(message, *args)
log_with_context {{level}}, (\{{message}} \{% unless args.empty? %} % \{{args}} \{% end %})
end
{% end %}
{% end %} {% end %}
end end
end end