66#
77module SemanticLogger
88 class Base
9+ # Creates a copy of an existing logger.
10+ # This method can be overridden by subclasses to provide a specialized implementation.
11+ # `child` logger uses this method.
12+ def self . copy ( instance )
13+ raise ArgumentError , "Cannot copy instances different from #{ self } " if instance . class != self
14+
15+ instance . dup
16+ end
17+
918 # Class name to be logged
10- attr_accessor :name , :filter , :child_named_tags
19+ attr_accessor :name , :filter
20+ attr_reader :instance_named_tags
1121
1222 # Set the logging level for this logger
1323 #
@@ -252,12 +262,19 @@ def should_log?(log)
252262
253263 # Creates a new logger with the given instance named tags
254264 def child ( **named_tags )
255- new_named_tags = child_named_tags . merge ( named_tags )
256- new_logger = dup
257- new_logger . child_named_tags = new_named_tags
265+ new_named_tags = instance_named_tags . merge ( named_tags )
266+ new_logger = self . class . copy ( self )
267+ new_logger . instance_named_tags = new_named_tags
258268 new_logger
259269 end
260270
271+ protected
272+
273+ def instance_named_tags = ( named_tags )
274+ # Prevent accidental mutation of log named tags
275+ @instance_named_tags = named_tags . dup . freeze
276+ end
277+
261278 private
262279
263280 # Initializer for Abstract Class SemanticLogger::Base
@@ -283,7 +300,7 @@ def child(**named_tags)
283300 # (/\AExclude/ =~ log.message).nil?
284301 # end
285302 # end
286- def initialize ( klass , level = nil , filter = nil )
303+ def initialize ( klass , level = nil , filter = nil , instance_named_tags = { } )
287304 # Support filtering all messages to this logger instance.
288305 unless filter . nil? || filter . is_a? ( Regexp ) || filter . is_a? ( Proc ) || filter . respond_to? ( :call )
289306 raise ":filter must be a Regexp, Proc, or implement :call"
@@ -298,7 +315,7 @@ def initialize(klass, level = nil, filter = nil)
298315 else
299316 self . level = level
300317 end
301- @child_named_tags = { }
318+ self . instance_named_tags = instance_named_tags
302319 end
303320
304321 # Return the level index for fast comparisons
@@ -334,7 +351,7 @@ def log_internal(level, index, message = nil, payload = nil, exception = nil)
334351 payload = nil
335352 end
336353
337- log = Log . new ( name , level , index )
354+ log = Log . new ( name , level , index , instance_named_tags )
338355 should_log =
339356 if exception . nil? && payload . nil? && message . is_a? ( Hash )
340357 # All arguments as a hash in the message.
@@ -358,9 +375,6 @@ def log_internal(level, index, message = nil, payload = nil, exception = nil)
358375 end
359376 end
360377
361- # Add child named tags to the log
362- log . payload = child_named_tags . merge ( log . payload || { } )
363-
364378 # Log level may change during assign due to :on_exception_level
365379 self . log ( log ) if should_log && should_log? ( log )
366380 end
@@ -388,7 +402,7 @@ def measure_internal(level, index, message, params)
388402 exception = e
389403 ensure
390404 # Must use ensure block otherwise a `return` in the yield above will skip the log entry
391- log = Log . new ( name , level , index )
405+ log = Log . new ( name , level , index , instance_named_tags )
392406 exception ||= params [ :exception ]
393407 message = params [ :message ] if params [ :message ]
394408 duration =
@@ -401,8 +415,8 @@ def measure_internal(level, index, message, params)
401415 # Extract options after block completes so that block can modify any of the options
402416 payload = params [ :payload ]
403417
404- # Add child named tags
405- payload = child_named_tags . merge ( payload || { } )
418+ # Add instance named tags
419+ payload = instance_named_tags . merge ( payload || { } )
406420
407421 # May return false due to elastic logging
408422 should_log = log . assign (
0 commit comments