unified_logger 0.1.5 → 0.1.6

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: a0ea9e1937937ec836c644c3831302f34b27547cb06bb76a3ef4ccb089e98a90
4
- data.tar.gz: d5534540295b6ee5521fe095322844e64ff5f3c9da528dec743e6919540f956e
3
+ metadata.gz: dac24933499290c1a3703ae8da09aaeaf46e8096e68043ce1ba4618f3b61435a
4
+ data.tar.gz: 3876aef726012b9a428a37a951ddd515126538686f91cc793bef629e9f13f5d2
5
5
  SHA512:
6
- metadata.gz: e38c0618abb36baf5dfc6fbd308925f78e5dbabf9a5913072bf2fa116936b7ae9519406966db32aaa373efe97ac9a90d7210881a10d378f4efa1cc089b3e7fc0
7
- data.tar.gz: cbf6d324fa0ce67b90313427c07234b1ec16864f365fbd2c287a5ecbabd4de993ba50a3d8d655e520f96d876c462aed2e2116f9cec9f12c8687334e3993fa36f
6
+ metadata.gz: 4bc1ef83dd6f6be2cce82a64226de3fcef60bff86728a136497eacd396b4991b0260c8740126b21e32336c2e4c42d1c821d9739141b4bf8d7783f7d9a287a9fa
7
+ data.tar.gz: a0e0a7d4b2b6b3907d1c73e6ee569703fa66ec56eda323efd3823563e4396151407bdda27997188b7bfcb912e54f451295d30b6c5874f594c9925669b8527771
@@ -1,41 +1,61 @@
1
1
  module UnifiedLogger
2
2
  class JobLogger
3
- DEFAULT_MAX_RETRIES = 5
4
-
5
3
  class << self
6
- def log(job)
4
+ def log(class_name:, id: nil, queue: nil, params: nil,
5
+ enqueued_at: nil, retry_count: 0, max_retries: nil, **extra)
6
+ started = UnifiedLogger.current_time
7
7
  yield
8
8
  ensure
9
- log_execution(job) if UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger)
9
+ if UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger)
10
+ write_log(class_name: class_name, id: id, queue: queue, params: params,
11
+ enqueued_at: enqueued_at, retry_count: retry_count,
12
+ max_retries: max_retries, started: started, **extra)
13
+ end
10
14
  end
11
15
 
12
16
  private
13
17
 
14
- def log_execution(job)
18
+ def write_log(class_name:, id:, queue:, params:, enqueued_at:,
19
+ retry_count:, max_retries:, started:, **extra)
20
+ enqueued_time = parse_time(enqueued_at)
21
+
15
22
  log = {
16
- log_type: :job,
17
- timestamp: UnifiedLogger.formatted_time,
18
- class_name: job.class.name,
19
- id: job.job_id,
20
- queue: job.queue_name,
21
- params: job.arguments,
22
- executions_count: job.executions,
23
- exception_executions: job.exception_executions,
24
- enqueued_at: job.enqueued_at,
25
- locale: job.locale,
26
- duration: job.enqueued_at.present? ? UnifiedLogger.current_time - job.enqueued_at.in_time_zone : "unknown"
23
+ log_type: :job,
24
+ timestamp: UnifiedLogger.formatted_time,
25
+ class_name: class_name,
26
+ id: id,
27
+ queue: queue,
28
+ params: params,
29
+ retry_count: retry_count,
30
+ enqueued_at: enqueued_at,
31
+ duration: started ? UnifiedLogger.current_time - started : 0,
32
+ queue_duration: enqueued_time && started ? started - enqueued_time : nil,
33
+ thread_id: Thread.current.object_id,
34
+ process_id: Process.pid
27
35
  }
28
- log[:custom] = UnifiedLogger::Logger.fetch_and_reset_custom_logs if UnifiedLogger::Logger.custom_logs.any?
36
+ log.merge!(extra) if extra.any?
37
+ log.compact!
38
+
39
+ log[:logs] = Logger.fetch_and_reset_logs if Logger.logs.any?
40
+ log.merge!(Logger.fetch_and_reset_extra_log_fields) if Logger.extra_log_fields.any?
29
41
 
30
42
  if $!
31
- log[:exception] = UnifiedLogger::Logger.format_exception($!)
32
- log[:status] = job.executions >= DEFAULT_MAX_RETRIES ? :error : :warn
43
+ log[:exception] = Logger.format_exception($!)
44
+ log[:status] = max_retries && retry_count < max_retries ? :warn : :error
33
45
  else
34
46
  log[:status] = :ok
35
47
  end
36
48
 
37
49
  UnifiedLogger.transform_job_log_callable&.call(log)
38
- UnifiedLogger.current_logger.write(UnifiedLogger::Logger.format(log))
50
+ Logger.write_log(log)
51
+ end
52
+
53
+ def parse_time(value)
54
+ case value
55
+ when Numeric then Time.at(value).utc
56
+ when String then Time.parse(value)
57
+ when Time, ActiveSupport::TimeWithZone then value
58
+ end
39
59
  end
40
60
  end
41
61
  end
@@ -1,9 +1,12 @@
1
1
  module UnifiedLogger
2
2
  class Logger < ::Logger
3
- CUSTOM_LOGS = Concurrent::ThreadLocalVar.new([])
3
+ LOGS = Concurrent::ThreadLocalVar.new([])
4
+ EXTRA_LOG_FIELDS = Concurrent::ThreadLocalVar.new({})
5
+ NOTE = 1.5
4
6
  SEVERITY_LEVELS = {
5
7
  debug: ::Logger::DEBUG,
6
8
  info: ::Logger::INFO,
9
+ note: NOTE,
7
10
  warn: ::Logger::WARN,
8
11
  error: ::Logger::ERROR,
9
12
  fatal: ::Logger::FATAL,
@@ -17,6 +20,14 @@ module UnifiedLogger
17
20
  self.formatter = proc {}
18
21
  end
19
22
 
23
+ def level=(severity)
24
+ if severity == :note
25
+ @level = NOTE
26
+ else
27
+ super
28
+ end
29
+ end
30
+
20
31
  def debug(message = nil, &block)
21
32
  message = block.call if message.nil? && block
22
33
  add(::Logger::DEBUG, message)
@@ -27,6 +38,11 @@ module UnifiedLogger
27
38
  add(::Logger::INFO, message)
28
39
  end
29
40
 
41
+ def note(message = nil, &block)
42
+ message = block.call if message.nil? && block
43
+ add(NOTE, message)
44
+ end
45
+
30
46
  def warn(message = nil, &block)
31
47
  message = block.call if message.nil? && block
32
48
  add(::Logger::WARN, message)
@@ -57,18 +73,33 @@ module UnifiedLogger
57
73
  end
58
74
 
59
75
  class << self
60
- def custom_logs
61
- CUSTOM_LOGS.value
76
+ def logs
77
+ LOGS.value
78
+ end
79
+
80
+ def add(hash)
81
+ EXTRA_LOG_FIELDS.value = EXTRA_LOG_FIELDS.value.merge(hash)
82
+ end
83
+
84
+ def extra_log_fields
85
+ EXTRA_LOG_FIELDS.value
86
+ end
87
+
88
+ def fetch_and_reset_extra_log_fields
89
+ fields = extra_log_fields
90
+ EXTRA_LOG_FIELDS.value = {}
91
+ fields
62
92
  end
63
93
 
64
94
  def reset_thread_logs
65
- CUSTOM_LOGS.value = []
95
+ LOGS.value = []
96
+ EXTRA_LOG_FIELDS.value = {}
66
97
  end
67
98
 
68
- def fetch_and_reset_custom_logs
69
- logs = custom_logs
70
- reset_thread_logs
71
- logs
99
+ def fetch_and_reset_logs
100
+ current = logs
101
+ LOGS.value = []
102
+ current
72
103
  end
73
104
 
74
105
  def trim(data)
@@ -107,8 +138,42 @@ module UnifiedLogger
107
138
  formatter.present? ? formatter.call(filtered_log) : filtered_log.to_json
108
139
  end
109
140
 
141
+ def write_log(log)
142
+ logger = UnifiedLogger.current_logger
143
+ max = UnifiedLogger.config[:max_log_size]
144
+ if log.inspect.length <= max || !log.key?(:logs)
145
+ logger.write(format(log))
146
+ else
147
+ entries = log.delete(:logs)
148
+ logger.write(format(log))
149
+ write_overflow_logs(log[:id], log[:log_type], entries, max, logger)
150
+ end
151
+ end
152
+
110
153
  private
111
154
 
155
+ def write_overflow_logs(id, log_type, entries, max, logger)
156
+ index = 1
157
+ group = []
158
+
159
+ entries.each do |entry|
160
+ candidate = group + [entry]
161
+ overflow = { id: id, log_type: log_type, index: index, logs: candidate }
162
+
163
+ if overflow.inspect.length > max && group.any?
164
+ logger.write(format({ id: id, log_type: log_type, index: index, logs: group }))
165
+ index += 1
166
+ group = [entry]
167
+ else
168
+ group = candidate
169
+ end
170
+ end
171
+
172
+ return if group.empty?
173
+
174
+ logger.write(format({ id: id, log_type: log_type, index: index, logs: group }))
175
+ end
176
+
112
177
  def filter(content)
113
178
  return content unless content.respond_to?(:each)
114
179
 
@@ -132,16 +197,16 @@ module UnifiedLogger
132
197
  return true unless severity >= level
133
198
 
134
199
  severity_symbol = SEVERITY_MAP[severity] || :unknown
135
- append_custom_log(severity_symbol, message)
200
+ append_log(severity_symbol, message)
136
201
  end
137
202
 
138
203
  private
139
204
 
140
- def append_custom_log(severity, message)
205
+ def append_log(severity, message)
141
206
  message = sanitize_log_message(message) if message.is_a?(String)
142
207
  log_hash = { timestamp: UnifiedLogger.formatted_time, severity: severity, message: message }
143
208
 
144
- CUSTOM_LOGS.value = CUSTOM_LOGS.value + [log_hash]
209
+ LOGS.value = LOGS.value + [log_hash]
145
210
  end
146
211
 
147
212
  def sanitize_log_message(text)
@@ -13,7 +13,7 @@ module UnifiedLogger
13
13
  if UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger) && !silenced?(env["REQUEST_PATH"])
14
14
  log = build_log(started, env, status, headers, response)
15
15
  UnifiedLogger.transform_request_log_callable&.call(log, env)
16
- UnifiedLogger.current_logger.write(UnifiedLogger::Logger.format(log))
16
+ UnifiedLogger::Logger.write_log(log)
17
17
  end
18
18
  end
19
19
 
@@ -36,7 +36,7 @@ module UnifiedLogger
36
36
  timestamp: UnifiedLogger.formatted_time,
37
37
  id: env["action_dispatch.request_id"],
38
38
  ip: env["action_dispatch.remote_ip"].to_s,
39
- controller: path_parameters[:controller],
39
+ controller: path_parameters[:controller]&.camelize&.concat("Controller"),
40
40
  action: path_parameters[:action],
41
41
  request: {
42
42
  path: env["REQUEST_PATH"],
@@ -56,7 +56,8 @@ module UnifiedLogger
56
56
  duration: started ? UnifiedLogger.current_time - started : 0
57
57
  }
58
58
  log[:exception] = UnifiedLogger::Logger.format_exception($!) if $!.present?
59
- log[:custom] = UnifiedLogger::Logger.fetch_and_reset_custom_logs if UnifiedLogger::Logger.custom_logs.any?
59
+ log[:logs] = UnifiedLogger::Logger.fetch_and_reset_logs if UnifiedLogger::Logger.logs.any?
60
+ log.merge!(UnifiedLogger::Logger.fetch_and_reset_extra_log_fields) if UnifiedLogger::Logger.extra_log_fields.any?
60
61
 
61
62
  log
62
63
  end
@@ -0,0 +1,40 @@
1
+ require "unified_logger"
2
+
3
+ module UnifiedLogger
4
+ class SidekiqServerMiddleware
5
+ def call(job_instance, job_hash, queue)
6
+ UnifiedLogger::JobLogger.log(**attrs_from(job_instance, job_hash, queue)) { yield } # rubocop:disable Style/ExplicitBlockArgument
7
+ end
8
+
9
+ private
10
+
11
+ def attrs_from(job_instance, job_hash, queue)
12
+ aj = job_hash.key?("wrapped") ? job_hash.dig("args", 0) : nil
13
+ retries = job_hash["retry"]
14
+
15
+ {
16
+ class_name: aj&.[]("job_class") || job_hash["wrapped"] || job_instance.class.name,
17
+ id: aj&.[]("job_id") || job_hash["jid"],
18
+ queue: queue,
19
+ params: aj&.[]("arguments") || job_hash["args"],
20
+ retry_count: job_hash["retry_count"].to_i,
21
+ max_retries: resolve_max_retries(retries),
22
+ enqueued_at: aj&.[]("enqueued_at") || job_hash["enqueued_at"]
23
+ }.compact
24
+ end
25
+
26
+ def resolve_max_retries(retries)
27
+ return retries if retries.is_a?(Integer)
28
+
29
+ retries == false ? 0 : 25
30
+ end
31
+ end
32
+ end
33
+
34
+ if defined?(Sidekiq)
35
+ Sidekiq.configure_server do |config|
36
+ config.server_middleware do |chain|
37
+ chain.add UnifiedLogger::SidekiqServerMiddleware
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module UnifiedLogger
2
- VERSION = "0.1.5".freeze
2
+ VERSION = "0.1.6".freeze
3
3
  end
@@ -20,6 +20,7 @@ module UnifiedLogger
20
20
 
21
21
  DEFAULTS = {
22
22
  max_log_field_size: 2048,
23
+ max_log_size: 10_000,
23
24
  filter_params: %i[passw secret token crypt salt certificate otp ssn set-cookie http_authorization http_cookie pin],
24
25
  auto_insert_middleware: true,
25
26
  silence_paths: []
@@ -55,7 +56,8 @@ module UnifiedLogger
55
56
  end
56
57
 
57
58
  delegate :trim, :format, :format_exception,
58
- :custom_logs, :fetch_and_reset_custom_logs, :reset_thread_logs,
59
+ :logs, :fetch_and_reset_logs, :reset_thread_logs,
60
+ :add, :extra_log_fields, :fetch_and_reset_extra_log_fields,
59
61
  to: :"UnifiedLogger::Logger"
60
62
  end
61
63
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unified_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcovecchio
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-03-24 00:00:00.000000000 Z
10
+ date: 2026-03-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -75,6 +75,7 @@ files:
75
75
  - lib/unified_logger/logger.rb
76
76
  - lib/unified_logger/railtie.rb
77
77
  - lib/unified_logger/request_logger.rb
78
+ - lib/unified_logger/sidekiq.rb
78
79
  - lib/unified_logger/version.rb
79
80
  homepage: https://github.com/marcovecchio/unified_logger
80
81
  licenses: