contextual_logger 1.2.0.colin.3 → 1.2.0.colin.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bd0747cf5faa06b9907d60198830c374f83f226df121efa9a0b7049315f9132
4
- data.tar.gz: 808bbac948431f55a8f4a07532884f3ed310a63652c536512aa5dd435454c6fb
3
+ metadata.gz: c4b2dc21d1f78b3b6a4a70a782e717eb607ace39fbb085f68fe5c5fee1086e9e
4
+ data.tar.gz: 17422f6d289ab064d5b212b057870da7c6e283cf24fcf3d419874caf2621b923
5
5
  SHA512:
6
- metadata.gz: f3607fbfd8f6ddbc8b3b29943fd4787c16509997262b2d3ae309d41471d013da89ef76585d804775721ce1ac9fe75260a9eaf356ffee1cacc9bf2fc65ed4b273
7
- data.tar.gz: 3e929c9f55c3bd12a1b65ba3e5135c1e56f5dc87b1597b3a6da9adfcc038f47bd0b8e2a01f9b6d294bfca549d681bef8a9cf67482771e6e4d0aa1db6d86e137b
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.3'
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
 
@@ -60,18 +68,22 @@ module ContextualLogger
60
68
  current_context_override || global_context
61
69
  end
62
70
 
63
- def with_context(context)
64
- previous_context_override = current_context_override
65
- self.current_context_override = current_context.deep_merge(context)
71
+ # TODO: Deprecate current_context_for_thread in v2.0.
72
+ alias current_context_for_thread current_context
73
+
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
+
66
78
  if block_given?
67
79
  begin
68
80
  yield
69
81
  ensure
70
- self.current_context_override = previous_context_override
82
+ context_handler.reset!
71
83
  end
72
84
  else
73
85
  # If no block given, return context handler to the caller so they can call reset! themselves.
74
- ContextHandler.new(self, previous_context_override)
86
+ context_handler
75
87
  end
76
88
  end
77
89
 
@@ -109,7 +121,7 @@ module ContextualLogger
109
121
 
110
122
  # Note that this interface needs to stay compatible with the underlying ::Logger#add interface,
111
123
  # which is: def add(severity, message = nil, progname = nil)
112
- 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 **
113
125
  severity = arg_severity || UNKNOWN
114
126
  if log_level_enabled?(severity)
115
127
  if arg1.nil?
@@ -124,7 +136,7 @@ module ContextualLogger
124
136
  message = arg1
125
137
  progname = arg2 || @progname
126
138
  end
127
- 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))
128
140
  end
129
141
 
130
142
  true
@@ -148,7 +160,7 @@ module ContextualLogger
148
160
  normalized_message = ContextualLogger.normalize_message(message)
149
161
  normalized_progname = ContextualLogger.normalize_message(progname) unless progname.nil?
150
162
  if @formatter
151
- @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message }.merge!(context))
163
+ @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message, **context })
152
164
  else
153
165
  "#{basic_json_log_entry(severity, timestamp, normalized_progname, normalized_message, context: context)}\n"
154
166
  end
@@ -158,12 +170,20 @@ module ContextualLogger
158
170
  message_hash = {
159
171
  message: normalized_progname ? "#{normalized_progname}: #{normalized_message}" : normalized_message,
160
172
  severity: severity,
161
- timestamp: timestamp
173
+ timestamp: timestamp,
174
+ **context
162
175
  }
163
176
  message_hash[:progname] = normalized_progname if normalized_progname
164
177
 
165
- # merge! is faster and OK here since message_hash is still local only to this method
166
- 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
167
187
  end
168
188
  end
169
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.3
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-01 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