Skip to content

Commit 5422958

Browse files
tmp commit
1 parent 06e5805 commit 5422958

File tree

10 files changed

+114
-35
lines changed

10 files changed

+114
-35
lines changed

lib/semantic_logger/base.rb

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@
66
#
77
module 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(

lib/semantic_logger/formatters/raw.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def tags
6464
# Named Tags
6565
def named_tags
6666
hash[:named_tags] = log.named_tags if log.named_tags && !log.named_tags.empty?
67+
# TODO: Test
68+
# TODO: Different hash entry instead?
69+
# Always overrides thread named_tags with instance_named_tags
70+
hash[:named_tags] = hash.fetch(:named_tags, {}).merge(log.instance_named_tags) if log.instance_named_tags && !log.instance_named_tags.empty?
6771
end
6872

6973
# Duration

lib/semantic_logger/log.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ module SemanticLogger
2828
# tags
2929
# Any tags active on the thread when the log call was made
3030
#
31+
# instance_named_tags
32+
# Any named tags active on the logger instance when the log call was made
33+
#
3134
# level_index
3235
# Internal index of the log level
3336
#
@@ -55,16 +58,17 @@ class Log
5558

5659
attr_accessor :level, :level_index, :name, :message, :time, :duration,
5760
:payload, :exception, :thread_name, :backtrace,
58-
:tags, :named_tags, :context,
61+
:tags, :named_tags, :instance_named_tags, :context,
5962
:metric, :metric_amount, :dimensions
6063

61-
def initialize(name, level, index = nil)
64+
def initialize(name, level, index = nil, instance_named_tags = {})
6265
@level = level
6366
@thread_name = Thread.current.name
6467
@name = name
6568
@time = Time.now
6669
@tags = SemanticLogger.tags
6770
@named_tags = SemanticLogger.named_tags
71+
@instance_named_tags = instance_named_tags
6872
@level_index = index.nil? ? Levels.index(level) : index
6973
end
7074

lib/semantic_logger/loggable.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def self.included(base)
4242

4343
# Returns [SemanticLogger::Logger] class level logger
4444
def self.logger
45-
@semantic_logger ||= SemanticLogger[self].child(**@logger_child_named_tags)
45+
@semantic_logger ||= SemanticLogger[self].child(**@logger_instance_named_tags)
4646
end
4747

4848
# Replace instance class level logger
@@ -115,7 +115,7 @@ def #{method_name}(*args, &block)
115115
end
116116

117117
def logger_child(**named_tags)
118-
@logger_child_named_tags = named_tags
118+
@logger_instance_named_tags = named_tags
119119
end
120120

121121
private

lib/semantic_logger/logger.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ module SemanticLogger
44
class Logger < Base
55
include SemanticLogger::Concerns::Compatibility
66

7+
# def self.copy(instance)
8+
# raise ArgumentError, "Cannot copy instances different from #{self}" if instance.class != self
9+
10+
# new(instance.name, instance.level, instance.filter, instance.instance_named_tags)
11+
# end
12+
713
def self.subscribe(object = nil, &block)
814
subscriber = block || object
915

@@ -56,7 +62,11 @@ def self.sync?
5662
# regular expression. All other messages will be ignored
5763
# Proc: Only include log messages where the supplied Proc returns true
5864
# The Proc must return true or false
59-
def initialize(klass, level = nil, filter = nil)
65+
#
66+
# instance_named_tags
67+
# Named tags to be added to all log messages for this logger instance
68+
# Default: {}
69+
def initialize(klass, level = nil, filter = nil, instance_named_tags = {})
6070
super
6171
end
6272

lib/semantic_logger/subscriber.rb

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33
# Abstract base class for all appenders.
44
module SemanticLogger
55
class Subscriber < SemanticLogger::Base
6+
# def self.copy(instance)
7+
# raise ArgumentError, "Cannot copy instances different from #{self}" if instance.class != self
8+
9+
# new(
10+
# level: instance.level,
11+
# formatter: instance.formatter,
12+
# filter: instance.filter,
13+
# application: instance.application,
14+
# environment: instance.environment,
15+
# host: instance.host,
16+
# metrics: instance.metrics?,
17+
# instance_named_tags: instance.instance_named_tags
18+
# )
19+
# end
20+
621
# Every appender has its own formatter
722
attr_reader :formatter
823
attr_writer :application, :environment, :host, :logger, :metrics
@@ -78,6 +93,11 @@ def console_output?
7893
false
7994
end
8095

96+
# Whether to log metric only entries with this subscriber
97+
def metrics?
98+
@metrics
99+
end
100+
81101
private
82102

83103
# Initializer for Abstract Class SemanticLogger::Subscriber
@@ -108,8 +128,12 @@ def console_output?
108128
# metrics: [Boolean]
109129
# Whether to log metric only entries with this subscriber.
110130
# Default: false
131+
#
132+
# instance_named_tags: [Hash]
133+
# Named tags to be added to all log messages for this subscriber
134+
# Default: {}
111135
def initialize(level: nil, formatter: nil, filter: nil, application: nil, environment: nil, host: nil,
112-
metrics: false, &block)
136+
metrics: false, instance_named_tags: {}, &block)
113137
self.formatter = block || formatter
114138
@application = application
115139
@environment = environment
@@ -118,7 +142,7 @@ def initialize(level: nil, formatter: nil, filter: nil, application: nil, enviro
118142

119143
# Subscribers don't take a class name, so use this class name if a subscriber
120144
# is logged to directly.
121-
super(self.class, level, filter)
145+
super(self.class, level, filter, instance_named_tags)
122146
end
123147

124148
# Return the level index for fast comparisons.
@@ -127,10 +151,5 @@ def initialize(level: nil, formatter: nil, filter: nil, application: nil, enviro
127151
def level_index
128152
@level_index || 0
129153
end
130-
131-
# Whether to log metric only entries with this subscriber
132-
def metrics?
133-
@metrics
134-
end
135154
end
136155
end

lib/semantic_logger/test/capture_log_events.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ module Test
2020
# end
2121
# end
2222
class CaptureLogEvents < SemanticLogger::Subscriber
23+
def self.copy(instance)
24+
new_instance = super
25+
new_instance.events = []
26+
new_instance
27+
end
28+
2329
attr_accessor :events
2430

2531
# By default collect all log levels, and collect metric only log events.

lib/semantic_logger/test/minitest.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ def semantic_logger_events(deprecated_klass = nil, klass: deprecated_klass, sile
2020
logger.events
2121
end
2222

23+
# TODO: Add instance_named_tags
2324
# Verify a single log event has all the required attributes.
2425
def assert_semantic_logger_event(event, level: nil, name: nil, message: nil, message_includes: nil,
2526
payload: nil, payload_includes: nil,
2627
exception: nil, exception_includes: nil, backtrace: nil,
2728
thread_name: nil, tags: nil, named_tags: nil, context: nil,
28-
level_index: nil, duration: nil, time: nil,
29+
instance_named_tags: nil, level_index: nil, duration: nil, time: nil,
2930
metric: nil, metric_amount: nil, dimensions: nil)
3031
assert event, "No log event occurred"
3132

@@ -35,6 +36,7 @@ def assert_semantic_logger_event(event, level: nil, name: nil, message: nil, mes
3536
assert_semantic_logger_entry(event, :thread_name, thread_name)
3637
assert_semantic_logger_entry(event, :tags, tags)
3738
assert_semantic_logger_entry(event, :named_tags, named_tags)
39+
assert_semantic_logger_entry(event, :instance_named_tags, instance_named_tags)
3840
assert_semantic_logger_entry(event, :context, context)
3941
assert_semantic_logger_entry(event, :metric, metric)
4042
assert_semantic_logger_entry(event, :metric_amount, metric_amount)

test/loggable_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ class TestChildClassLogger
8989
end
9090

9191
describe "sample child class logger" do
92-
it "has child named tags set" do
93-
assert_equal TestChildClassLogger::TAG_DATA, TestChildClassLogger.logger.child_named_tags
92+
it "has instance named tags set" do
93+
assert_equal TestChildClassLogger::TAG_DATA, TestChildClassLogger.logger.instance_named_tags
9494
end
9595
end
9696
end

test/logger_test.rb

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,35 @@ def self.call(log)
155155
end
156156

157157
describe ".child" do
158-
it "creates a child logger" do
159-
tag_data = {tag1: "value1", tag2: "value2"}
160-
child_logger = logger.child(**tag_data)
158+
it "creates a child logger with instance named tags merged with parent" do
159+
parent_tag_data = {parent_tag: "parent_value"}
160+
child_tag_data = {tag1: "value1", tag2: "value2"}
161+
parent_logger = logger.child(**parent_tag_data)
162+
child_logger = parent_logger.child(**child_tag_data)
163+
161164
child_logger.info("hello world")
162165

163-
assert_equal tag_data, child_logger.child_named_tags
164-
assert log = child_logger.events.first
165-
assert_equal "hello world", log.message
166-
assert_equal tag_data, log.payload
166+
assert_equal parent_tag_data, parent_logger.instance_named_tags
167+
assert_equal parent_tag_data.merge(child_tag_data), child_logger.instance_named_tags
168+
end
169+
170+
it "outputs log entries with different instance named tags from the parent" do
171+
parent_tag_data = {parent_tag: "parent_value"}
172+
child_tag_data = {tag1: "value1", tag2: "value2"}
173+
parent_logger = logger.child(**parent_tag_data)
174+
child_logger = parent_logger.child(**child_tag_data)
175+
176+
parent_logger.info("hello parent")
177+
178+
assert log_parent = parent_logger.events.first
179+
assert_equal "hello parent", log_parent.message
180+
assert_equal parent_tag_data, log_parent.instance_named_tags
181+
182+
child_logger.info("hello child")
183+
184+
assert log_child = child_logger.events.first
185+
assert_equal "hello child", log_child.message
186+
assert_equal parent_tag_data.merge(child_tag_data), log_child.instance_named_tags
167187
end
168188
end
169189
end

0 commit comments

Comments
 (0)