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

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: 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