contextual_logger 1.2.0.colin.6 → 1.2.0.pre.1

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: 4e69ef52ab71f4f66d8f0d933f9ac6e74b5f2d8c218cd7b5865086f1ae00a6ff
4
- data.tar.gz: e7245b4c4074d6f112730ed3b89b681b21a12042b96d03e751329f1a8f302363
3
+ metadata.gz: d5ee8cad9d62ca2d8aeec81f2626b56b4aa6b1db2c6b626518a4708d590ddb4c
4
+ data.tar.gz: 71be08f271be68de04f942abfa301a2a5ec54be54d0399bb01db8bcf52a07037
5
5
  SHA512:
6
- metadata.gz: 7ced2de731f75eef24afa7d327c0947299202a92f904df2a424af43c3520de8cfdcc8b21d1967a198f17cb6510fe3406449e969077f9bcb0b8b173dfe94d6a52
7
- data.tar.gz: 36e6d8e0e7c44e9444bd8907700b3072aa4f8f3767c2b7937dc5d59a747acfeb33c1943a8a4ed65a68ba5851ca16c5164daf948d2390b6bec19472721cefb21c
6
+ metadata.gz: 2b455d41a46223ea9c6e2583a7d03d81940743215c4eb1dd5977d6ffc8f8ffcb618ce27a3b975fed211987b592e0cfdbc1e691ceef155641764c5d8938da0679
7
+ data.tar.gz: 6600b357b1dc7b25ee8e746f17280a7e74ac184b38a03340f48e835659259135321a0c0ff0d7c387a7b06b9804b82ad63f8b76a911790a6fb5c2f99a61c0cfdc
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContextualLogger
4
+ module Context
5
+ class Handler
6
+ THREAD_CONTEXT_NAMESPACE = 'ContextualLoggerCurrentLoggingContext'
7
+
8
+ attr_reader :previous_context, :context
9
+
10
+ def self.current_context
11
+ Thread.current[THREAD_CONTEXT_NAMESPACE] || {}
12
+ end
13
+
14
+ def initialize(context, previous_context: nil)
15
+ @previous_context = previous_context || self.class.current_context
16
+ @context = context
17
+ end
18
+
19
+ def set!
20
+ Thread.current[THREAD_CONTEXT_NAMESPACE] = context
21
+ end
22
+
23
+ def reset!
24
+ Thread.current[THREAD_CONTEXT_NAMESPACE] = previous_context
25
+ end
26
+ end
27
+ end
28
+ end
@@ -6,13 +6,6 @@ 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
16
9
  class LoggerWithContext
17
10
  include LoggerMixin
18
11
 
@@ -23,13 +16,7 @@ module ContextualLogger
23
16
  @logger = logger
24
17
  self.level = level
25
18
  @context = normalize_context(context)
26
- end
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.
31
- def global_context
32
- @global_context ||= @logger.current_context.deep_merge(@context) # this will include any with_context overrides on the `logger`
19
+ @merged_context_cache = {} # so we don't have to merge every time
33
20
  end
34
21
 
35
22
  def level
@@ -42,10 +29,10 @@ module ContextualLogger
42
29
 
43
30
  def write_entry_to_log(severity, timestamp, progname, message, context:)
44
31
  merged_context =
45
- if context.any?
46
- current_context.deep_merge(context)
32
+ if @merged_context_cache.size >= 1000 # keep this cache memory use finite
33
+ @merged_context_cache[context] || @context.deep_merge(context)
47
34
  else
48
- current_context
35
+ @merged_context_cache[context] ||= @context.deep_merge(context)
49
36
  end
50
37
 
51
38
  @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.6'
4
+ VERSION = '1.2.0.pre.1'
5
5
  end
@@ -4,9 +4,7 @@ require 'active_support'
4
4
  require 'active_support/core_ext/module/delegation'
5
5
  require 'json'
6
6
  require_relative './contextual_logger/redactor'
7
- require_relative './contextual_logger/context'
8
- require_relative './contextual_logger/context_handler'
9
- require_relative './contextual_logger/global_context_lock_message'
7
+ require_relative './contextual_logger/context/handler'
10
8
 
11
9
  module ContextualLogger
12
10
  LOG_LEVEL_NAMES_TO_SEVERITY =
@@ -44,37 +42,16 @@ module ContextualLogger
44
42
  end
45
43
  end
46
44
 
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
51
45
  module LoggerMixin
52
- include Context
53
-
54
46
  delegate :register_secret, :register_secret_regex, to: :redactor
55
47
 
56
- def global_context
57
- @global_context ||= Context::EMPTY_CONTEXT
58
- end
59
-
60
48
  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
64
- @global_context = context.freeze
49
+ Context::Handler.new(context).set!
65
50
  end
66
51
 
67
- def current_context
68
- current_context_override || global_context
69
- end
70
-
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, current_context_override)
76
- self.current_context_override = deep_merge_with_current_context(stacked_context)
77
-
52
+ def with_context(context)
53
+ context_handler = Context::Handler.new(current_context_for_thread.deep_merge(context))
54
+ context_handler.set!
78
55
  if block_given?
79
56
  begin
80
57
  yield
@@ -82,11 +59,15 @@ module ContextualLogger
82
59
  context_handler.reset!
83
60
  end
84
61
  else
85
- # If no block given, return context handler to the caller so they can call reset! themselves.
62
+ # If no block given, the context handler is returned to the caller so they can handle reset! themselves.
86
63
  context_handler
87
64
  end
88
65
  end
89
66
 
67
+ def current_context_for_thread
68
+ Context::Handler.current_context
69
+ end
70
+
90
71
  # In the methods generated below, we assume that presence of context means new code that is
91
72
  # aware of ContextualLogger...and that that code never uses progname.
92
73
  # This is important because we only get 3 args total (not including &block) passed to `add`,
@@ -121,7 +102,7 @@ module ContextualLogger
121
102
 
122
103
  # Note that this interface needs to stay compatible with the underlying ::Logger#add interface,
123
104
  # which is: def add(severity, message = nil, progname = nil)
124
- def add(arg_severity, arg1 = nil, arg2 = nil, **context) # Ruby will prefer to match hashes to last argument because of **
105
+ def add(arg_severity, arg1 = nil, arg2 = nil, **context) # Ruby will prefer to match hashes up to last ** argument
125
106
  severity = arg_severity || UNKNOWN
126
107
  if log_level_enabled?(severity)
127
108
  if arg1.nil?
@@ -136,7 +117,7 @@ module ContextualLogger
136
117
  message = arg1
137
118
  progname = arg2 || @progname
138
119
  end
139
- write_entry_to_log(severity, Time.now, progname, message, context: deep_merge_with_current_context(context))
120
+ write_entry_to_log(severity, Time.now, progname, message, context: current_context_for_thread.deep_merge(context))
140
121
  end
141
122
 
142
123
  true
@@ -160,7 +141,7 @@ module ContextualLogger
160
141
  normalized_message = ContextualLogger.normalize_message(message)
161
142
  normalized_progname = ContextualLogger.normalize_message(progname) unless progname.nil?
162
143
  if @formatter
163
- @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message, **context })
144
+ @formatter.call(severity, timestamp, normalized_progname, { message: normalized_message }.merge!(context))
164
145
  else
165
146
  "#{basic_json_log_entry(severity, timestamp, normalized_progname, normalized_message, context: context)}\n"
166
147
  end
@@ -170,20 +151,12 @@ module ContextualLogger
170
151
  message_hash = {
171
152
  message: normalized_progname ? "#{normalized_progname}: #{normalized_message}" : normalized_message,
172
153
  severity: severity,
173
- timestamp: timestamp,
174
- **context
154
+ timestamp: timestamp
175
155
  }
176
156
  message_hash[:progname] = normalized_progname if normalized_progname
177
157
 
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
158
+ # merge! is faster and OK here since message_hash is still local only to this method
159
+ message_hash.merge!(context).to_json
187
160
  end
188
161
  end
189
162
  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.6
4
+ version: 1.2.0.pre.1
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-12 00:00:00.000000000 Z
11
+ date: 2023-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -45,9 +45,7 @@ extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
47
  - lib/contextual_logger.rb
48
- - lib/contextual_logger/context.rb
49
- - lib/contextual_logger/context_handler.rb
50
- - lib/contextual_logger/global_context_lock_message.rb
48
+ - lib/contextual_logger/context/handler.rb
51
49
  - lib/contextual_logger/logger_with_context.rb
52
50
  - lib/contextual_logger/overrides/active_support/tagged_logging/formatter.rb
53
51
  - lib/contextual_logger/redactor.rb
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ContextualLogger
4
- module Context
5
- EMPTY_CONTEXT = {}.freeze
6
-
7
- def thread_context_key_for_logger_instance
8
- # We include the object_id here to make these thread/fiber locals unique per logger instance.
9
- @thread_context_key_for_logger_instance ||= "ContextualLogger::Context.context_for_#{object_id}".to_sym
10
- end
11
-
12
- def current_context_override
13
- Thread.current[thread_context_key_for_logger_instance]
14
- end
15
-
16
- def current_context_override=(context_override)
17
- ContextualLogger.global_context_lock_message ||= "ContextualLogger::Context.current_context_override set for #{self.class.name} #{object_id}: #{context_override.inspect}"
18
- Thread.current[thread_context_key_for_logger_instance] = context_override.freeze
19
- end
20
- end
21
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ContextualLogger
4
- class ContextHandler
5
- def initialize(instance, previous_context_override)
6
- @instance = instance
7
- @previous_context_override = previous_context_override
8
- end
9
-
10
- def reset!
11
- @instance.current_context_override = @previous_context_override
12
- end
13
- end
14
- end
@@ -1,10 +0,0 @@
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
- class GlobalContextIsLocked < StandardError
9
- end
10
- end