contextual_logger 1.2.0.colin.4 → 1.2.0.colin.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b8180f031cfc4c1facc22a0cfbbadf8970b01a1b7c1d18f974dbf54fd1712d5
4
- data.tar.gz: d310df13569303aa5f6964d1cf9f73583fcfcabcd5950f330b00a30f8eb151f5
3
+ metadata.gz: c4b2dc21d1f78b3b6a4a70a782e717eb607ace39fbb085f68fe5c5fee1086e9e
4
+ data.tar.gz: 17422f6d289ab064d5b212b057870da7c6e283cf24fcf3d419874caf2621b923
5
5
  SHA512:
6
- metadata.gz: e0c0350c9f36cf27071a7e1da1f42363979852304c4b029ca24d0a550c77bfb403815dc09420d5c8d9c164b003f8a22213e5d33216e1647ae63143a3b73447e9
7
- data.tar.gz: 4984642ce8b36e78c3f14f0415ac95d67dec97f9f5651f6c63deb715bbfa27134243f7286e09802146b6629df0bc1077c476ea3e3d5ad783779daa718aef032d
6
+ metadata.gz: 15ff319daf3bcd7c4fd6a9c815cdfc394af288749c52c583fb522d571915fb1fe4bc888a9db8ff0040e4d509a37c9027610aa41a3fa59bcec46dfb551045bd81
7
+ data.tar.gz: 4a7ebd9b1b4f37a950d8cbea6b87ad797264701b87e349246c1bce4edfb0743ed3557c827545665a8c84a37c43c4062aeefced0b76880e558084278093bc26fb
@@ -2,17 +2,20 @@
2
2
 
3
3
  module ContextualLogger
4
4
  module Context
5
- def thread_context_for_logger_instance
5
+ EMPTY_CONTEXT = {}.freeze
6
+
7
+ def thread_context_key_for_logger_instance
6
8
  # We include the object_id here to make these thread/fiber locals unique per logger instance.
7
- @thread_context_for_logger_instance ||= "ContextualLogger::Context.context_for_#{object_id}".to_sym
9
+ @thread_context_key_for_logger_instance ||= "ContextualLogger::Context.context_for_#{object_id}".to_sym
8
10
  end
9
11
 
10
12
  def current_context_override
11
- Thread.current[thread_context_for_logger_instance]
13
+ ContextualLogger.global_context_lock_message ||= "ContextualLogger::Context.current_context_override set for #{self.class.name} #{object_id}"
14
+ Thread.current[thread_context_key_for_logger_instance]
12
15
  end
13
16
 
14
17
  def current_context_override=(context_override)
15
- Thread.current[thread_context_for_logger_instance] = context_override.freeze
18
+ Thread.current[thread_context_key_for_logger_instance] = context_override.freeze
16
19
  end
17
20
  end
18
21
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContextualLogger
4
+ class << self
5
+ attr_accessor :global_context_lock_message # nil or a string indicating what locked the global context
6
+ end
7
+
8
+
9
+ class GlobalContextIsLocked < StandardError
10
+ end
11
+ end
@@ -6,6 +6,13 @@ module ContextualLogger
6
6
  # A logger that deep_merges additional context and then delegates to the given logger.
7
7
  # Keeps it own log level (called override_level) that may be set independently of the logger it delegates to.
8
8
  # If override_level is non-nil, it takes precedence; if it is nil (the default), then it delegates to the logger.
9
+ #
10
+ # Context Precedence:
11
+ # 1. inline **context passed to the logger method
12
+ # 2. `with_context` overrides on this LoggerWithContext object
13
+ # 3. context passed to this LoggerWithContext constructor
14
+ # 4. `with_context` overrides on the logger passed to this constructor
15
+ # 5. `global_context` set on the logger passed to this constructor
9
16
  class LoggerWithContext
10
17
  include LoggerMixin
11
18
 
@@ -16,11 +23,13 @@ module ContextualLogger
16
23
  @logger = logger
17
24
  self.level = level
18
25
  @context = normalize_context(context)
19
- @merged_context_cache = {} # so we don't have to merge every time
20
26
  end
21
27
 
28
+ # TODO: It's a (small) bug that the global_context is memoized at this point. There's a chance that the @logger.current_context
29
+ # changes after this because of an enclosing @logger.with_context block. If that happens, we'll miss that extra context.
30
+ # The tradeoff is that we don't want to keep calling deep_merge.
22
31
  def global_context
23
- @logger.global_context
32
+ @global_context ||= @logger.current_context.deep_merge(@context) # this will include any with_context overrides on the `logger`
24
33
  end
25
34
 
26
35
  def level
@@ -33,10 +42,10 @@ module ContextualLogger
33
42
 
34
43
  def write_entry_to_log(severity, timestamp, progname, message, context:)
35
44
  merged_context =
36
- if @merged_context_cache.size >= 1000 # keep this cache memory use finite
37
- @merged_context_cache[context] || @context.deep_merge(context)
45
+ if context.any?
46
+ current_context.deep_merge(context)
38
47
  else
39
- @merged_context_cache[context] ||= @context.deep_merge(context)
48
+ current_context
40
49
  end
41
50
 
42
51
  @logger.write_entry_to_log(severity, timestamp, progname, message, context: merged_context)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ContextualLogger
4
- VERSION = '1.2.0.colin.4'
4
+ VERSION = '1.2.0.colin.5'
5
5
  end
@@ -6,6 +6,7 @@ require 'json'
6
6
  require_relative './contextual_logger/redactor'
7
7
  require_relative './contextual_logger/context'
8
8
  require_relative './contextual_logger/context_handler'
9
+ require_relative './contextual_logger/global_context_lock_message'
9
10
 
10
11
  module ContextualLogger
11
12
  LOG_LEVEL_NAMES_TO_SEVERITY =
@@ -43,16 +44,23 @@ module ContextualLogger
43
44
  end
44
45
  end
45
46
 
47
+ # Context Precedence when this is mixed into a logger:
48
+ # 1. inline **context passed to the logger method
49
+ # 2. `with_context` overrides on the logger object
50
+ # 3. `global_context` set on the logger passed to this constructor
46
51
  module LoggerMixin
47
52
  include Context
48
53
 
49
54
  delegate :register_secret, :register_secret_regex, to: :redactor
50
55
 
51
56
  def global_context
52
- @global_context ||= {}.freeze
57
+ @global_context ||= Context::EMPTY_CONTEXT
53
58
  end
54
59
 
55
60
  def global_context=(context)
61
+ if (global_context_lock_message = ::ContextualLogger.global_context_lock_message)
62
+ raise ::ContextualLogger::GlobalContextIsLocked, global_context_lock_message
63
+ end
56
64
  @global_context = context.freeze
57
65
  end
58
66
 
@@ -63,18 +71,19 @@ module ContextualLogger
63
71
  # TODO: Deprecate current_context_for_thread in v2.0.
64
72
  alias current_context_for_thread current_context
65
73
 
66
- def with_context(context)
67
- previous_context_override = current_context_override
68
- self.current_context_override = current_context.deep_merge(context)
74
+ def with_context(stacked_context)
75
+ context_handler = ContextHandler.new(self, self.current_context_override)
76
+ self.current_context_override = deep_merge_with_current_context(stacked_context)
77
+
69
78
  if block_given?
70
79
  begin
71
80
  yield
72
81
  ensure
73
- self.current_context_override = previous_context_override
82
+ context_handler.reset!
74
83
  end
75
84
  else
76
85
  # If no block given, return context handler to the caller so they can call reset! themselves.
77
- ContextHandler.new(self, previous_context_override)
86
+ context_handler
78
87
  end
79
88
  end
80
89
 
@@ -112,7 +121,7 @@ module ContextualLogger
112
121
 
113
122
  # Note that this interface needs to stay compatible with the underlying ::Logger#add interface,
114
123
  # which is: def add(severity, message = nil, progname = nil)
115
- def add(arg_severity, arg1 = nil, arg2 = nil, **context) # Ruby will prefer to match hashes up to last ** argument
124
+ def add(arg_severity, arg1 = nil, arg2 = nil, **context) # Ruby will prefer to match hashes to last argument because of **
116
125
  severity = arg_severity || UNKNOWN
117
126
  if log_level_enabled?(severity)
118
127
  if arg1.nil?
@@ -127,7 +136,7 @@ module ContextualLogger
127
136
  message = arg1
128
137
  progname = arg2 || @progname
129
138
  end
130
- write_entry_to_log(severity, Time.now, progname, message, context: current_context.deep_merge(context))
139
+ write_entry_to_log(severity, Time.now, progname, message, context: deep_merge_with_current_context(context))
131
140
  end
132
141
 
133
142
  true
@@ -151,7 +160,7 @@ module ContextualLogger
151
160
  normalized_message = ContextualLogger.normalize_message(message)
152
161
  normalized_progname = ContextualLogger.normalize_message(progname) unless progname.nil?
153
162
  if @formatter
154
- @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message }.merge!(context))
163
+ @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message, **context })
155
164
  else
156
165
  "#{basic_json_log_entry(severity, timestamp, normalized_progname, normalized_message, context: context)}\n"
157
166
  end
@@ -161,12 +170,20 @@ module ContextualLogger
161
170
  message_hash = {
162
171
  message: normalized_progname ? "#{normalized_progname}: #{normalized_message}" : normalized_message,
163
172
  severity: severity,
164
- timestamp: timestamp
173
+ timestamp: timestamp,
174
+ **context
165
175
  }
166
176
  message_hash[:progname] = normalized_progname if normalized_progname
167
177
 
168
- # merge! is faster and OK here since message_hash is still local only to this method
169
- message_hash.merge!(context).to_json
178
+ message_hash.to_json
179
+ end
180
+
181
+ def deep_merge_with_current_context(stacked_context)
182
+ if stacked_context.any?
183
+ current_context.deep_merge(stacked_context)
184
+ else
185
+ current_context
186
+ end
170
187
  end
171
188
  end
172
189
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contextual_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.colin.4
4
+ version: 1.2.0.colin.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Ebentier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-02 00:00:00.000000000 Z
11
+ date: 2023-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -47,6 +47,7 @@ files:
47
47
  - lib/contextual_logger.rb
48
48
  - lib/contextual_logger/context.rb
49
49
  - lib/contextual_logger/context_handler.rb
50
+ - lib/contextual_logger/global_context_lock_message.rb
50
51
  - lib/contextual_logger/logger_with_context.rb
51
52
  - lib/contextual_logger/overrides/active_support/tagged_logging/formatter.rb
52
53
  - lib/contextual_logger/redactor.rb