unified_logger 0.1.3
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 +7 -0
- data/lib/unified_logger/job_logger.rb +46 -0
- data/lib/unified_logger/logger.rb +157 -0
- data/lib/unified_logger/railtie.rb +12 -0
- data/lib/unified_logger/request_logger.rb +109 -0
- data/lib/unified_logger/version.rb +3 -0
- data/lib/unified_logger.rb +88 -0
- metadata +102 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8852d1fcbbbc53507a9d23e79b9e08405955b89c60458cd91e7d3305e71a7be4
|
|
4
|
+
data.tar.gz: 46a8534b601d0206ebffdb7237066835d436e960bf0cf17c7f5831d710b00652
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7669986b85d090ae4098b62dd28a9a0b17bf08568b0ae8d75c1a857c3d2ca6060937128a3f6dd31f17216f7e5120f617eecb5c242e14548350a61be46d77bcb4
|
|
7
|
+
data.tar.gz: 81dfd77bfe8205b311ad2dac30fd3f4f7dfcf4aaf6e0a6ab3f5bff84e754cbfbe1ea07b8d925c33a6dfee4147fee6a204eac9d6250dba5c2fe63cda7b7ccb817
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "English"
|
|
2
|
+
|
|
3
|
+
module UnifiedLogger
|
|
4
|
+
class JobLogger
|
|
5
|
+
DEFAULT_MAX_RETRIES = 5
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def log(job)
|
|
9
|
+
yield
|
|
10
|
+
ensure
|
|
11
|
+
log_execution(job) if UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def log_execution(job)
|
|
17
|
+
log = {
|
|
18
|
+
log_type: :job,
|
|
19
|
+
timestamp: UnifiedLogger.formatted_time,
|
|
20
|
+
class_name: job.class.name,
|
|
21
|
+
id: job.job_id,
|
|
22
|
+
queue: job.queue_name,
|
|
23
|
+
params: job.arguments,
|
|
24
|
+
executions_count: job.executions,
|
|
25
|
+
exception_executions: job.exception_executions,
|
|
26
|
+
enqueued_at: job.enqueued_at,
|
|
27
|
+
locale: job.locale,
|
|
28
|
+
duration: job.enqueued_at.present? ? UnifiedLogger.current_time - job.enqueued_at.in_time_zone : "unknown"
|
|
29
|
+
}
|
|
30
|
+
log[:custom] = UnifiedLogger::Logger.fetch_and_reset_custom_logs if UnifiedLogger::Logger.custom_logs.any?
|
|
31
|
+
|
|
32
|
+
if $ERROR_INFO
|
|
33
|
+
log[:exception] = UnifiedLogger::Logger.format_exception($ERROR_INFO)
|
|
34
|
+
log[:status] = job.executions >= DEFAULT_MAX_RETRIES ? :error : :warn
|
|
35
|
+
else
|
|
36
|
+
log[:status] = :ok
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
custom = {}
|
|
40
|
+
UnifiedLogger.transform_job_log_callable&.call(custom)
|
|
41
|
+
log.merge!(custom)
|
|
42
|
+
UnifiedLogger.current_logger.write(UnifiedLogger::Logger.format(log))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
module UnifiedLogger
|
|
2
|
+
class Logger < ::Logger
|
|
3
|
+
CUSTOM_LOGS = Concurrent::ThreadLocalVar.new([])
|
|
4
|
+
SEVERITY_LEVELS = {
|
|
5
|
+
debug: ::Logger::DEBUG,
|
|
6
|
+
info: ::Logger::INFO,
|
|
7
|
+
warn: ::Logger::WARN,
|
|
8
|
+
error: ::Logger::ERROR,
|
|
9
|
+
fatal: ::Logger::FATAL,
|
|
10
|
+
unknown: ::Logger::UNKNOWN
|
|
11
|
+
}.freeze
|
|
12
|
+
SEVERITY_MAP = SEVERITY_LEVELS.invert.freeze
|
|
13
|
+
|
|
14
|
+
def initialize(logging_device = $stdout, *)
|
|
15
|
+
super
|
|
16
|
+
@logging_device = logging_device
|
|
17
|
+
self.formatter = proc {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def debug(message = nil, &block)
|
|
21
|
+
message = block.call if message.nil? && block
|
|
22
|
+
add(::Logger::DEBUG, message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def info(message = nil, &block)
|
|
26
|
+
message = block.call if message.nil? && block
|
|
27
|
+
add(::Logger::INFO, message)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def warn(message = nil, &block)
|
|
31
|
+
message = block.call if message.nil? && block
|
|
32
|
+
add(::Logger::WARN, message)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def error(message = nil, &block)
|
|
36
|
+
message = block.call if message.nil? && block
|
|
37
|
+
add(::Logger::ERROR, message)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def fatal(message = nil, &block)
|
|
41
|
+
message = block.call if message.nil? && block
|
|
42
|
+
add(::Logger::FATAL, message)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def unknown(message = nil, &block)
|
|
46
|
+
message = block.call if message.nil? && block
|
|
47
|
+
add(::Logger::UNKNOWN, message)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def <<(message)
|
|
51
|
+
add(::Logger::UNKNOWN, message.to_s.chomp)
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write(message)
|
|
56
|
+
@logging_device.write("#{message}\n") if @logging_device.respond_to?(:write)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class << self
|
|
60
|
+
def custom_logs
|
|
61
|
+
CUSTOM_LOGS.value
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def reset_thread_logs
|
|
65
|
+
CUSTOM_LOGS.value = []
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fetch_and_reset_custom_logs
|
|
69
|
+
logs = custom_logs
|
|
70
|
+
reset_thread_logs
|
|
71
|
+
logs
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def trim(data)
|
|
75
|
+
data = filter(data)
|
|
76
|
+
size = data.inspect.length
|
|
77
|
+
max = UnifiedLogger.config[:max_log_field_size]
|
|
78
|
+
return data if size < max
|
|
79
|
+
|
|
80
|
+
begin
|
|
81
|
+
json = JSON.generate(data, quirks_mode: true)
|
|
82
|
+
rescue JSON::GeneratorError, Encoding::UndefinedConversionError
|
|
83
|
+
json = data.respond_to?("to_s") ? data.to_s : "unparseable object (instance of #{data.class.name})"
|
|
84
|
+
end
|
|
85
|
+
"#{json[0..max]}... (#{size - max} extra characters omitted)"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def format_exception(exception)
|
|
89
|
+
if exception.is_a?(String)
|
|
90
|
+
{ message: exception }
|
|
91
|
+
elsif exception.is_a?(Exception)
|
|
92
|
+
btc = ActiveSupport::BacktraceCleaner.new
|
|
93
|
+
prefix = UnifiedLogger.backtrace_root + File::SEPARATOR
|
|
94
|
+
btc.add_filter { |line| line.sub(/\A#{Regexp.escape(prefix)}/, "") }
|
|
95
|
+
btc.add_silencer { |line| /request_logger.rb/.match?(line) }
|
|
96
|
+
{ class_name: exception.class.name, message: exception.message, backtrace: btc.clean(exception.backtrace || []) }
|
|
97
|
+
elsif exception.respond_to?(:to_s)
|
|
98
|
+
exception.to_s
|
|
99
|
+
else
|
|
100
|
+
exception.class.name
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def format(log)
|
|
105
|
+
filtered_log = filter(log)
|
|
106
|
+
formatter = UnifiedLogger.log_transformer
|
|
107
|
+
formatter.present? ? formatter.call(filtered_log) : filtered_log.to_json
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def filter(content)
|
|
113
|
+
return content unless content.respond_to?(:each)
|
|
114
|
+
|
|
115
|
+
filter_class = if defined?(ActiveSupport::ParameterFilter)
|
|
116
|
+
ActiveSupport::ParameterFilter
|
|
117
|
+
elsif defined?(ActionDispatch::Http::ParameterFilter)
|
|
118
|
+
ActionDispatch::Http::ParameterFilter
|
|
119
|
+
end
|
|
120
|
+
return content unless filter_class
|
|
121
|
+
|
|
122
|
+
filter_class.new(UnifiedLogger.config[:filter_params]).filter(content)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def add(severity, message = nil, progname = nil, &block)
|
|
127
|
+
if message.nil?
|
|
128
|
+
message = block ? block.call : progname
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
return true if message.blank?
|
|
132
|
+
return true unless severity >= level
|
|
133
|
+
|
|
134
|
+
severity_symbol = SEVERITY_MAP[severity] || :unknown
|
|
135
|
+
append_custom_log(severity_symbol, message)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def append_custom_log(severity, message)
|
|
141
|
+
message = sanitize_log_message(message) if message.is_a?(String)
|
|
142
|
+
log_hash = { timestamp: UnifiedLogger.formatted_time, severity: severity, message: message }
|
|
143
|
+
|
|
144
|
+
CUSTOM_LOGS.value = CUSTOM_LOGS.value + [log_hash]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def sanitize_log_message(text)
|
|
148
|
+
return text unless text.is_a?(String)
|
|
149
|
+
|
|
150
|
+
text = text.gsub(/\e\[[0-9;]*m/, "")
|
|
151
|
+
text = text.gsub(%r{[^a-zA-Z0-9\s.,;:!?'"()\[\]{}\-_@#$%&*+=<>|~`/]}, "")
|
|
152
|
+
text = text.gsub('"', "'")
|
|
153
|
+
text = text.gsub(/\s+/, " ")
|
|
154
|
+
text.strip
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UnifiedLogger
|
|
4
|
+
class Railtie < Rails::Railtie
|
|
5
|
+
initializer "unified_logger.middleware", after: :load_config_initializers do |app|
|
|
6
|
+
if UnifiedLogger.config[:auto_insert_middleware]
|
|
7
|
+
app.middleware.insert_after ActionDispatch::DebugExceptions,
|
|
8
|
+
UnifiedLogger::RequestLogger
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require "English"
|
|
2
|
+
|
|
3
|
+
module UnifiedLogger
|
|
4
|
+
class RequestLogger
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(env)
|
|
10
|
+
return @app.call(env) unless UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger)
|
|
11
|
+
|
|
12
|
+
started = UnifiedLogger.current_time
|
|
13
|
+
status, headers, response = @app.call(env)
|
|
14
|
+
ensure
|
|
15
|
+
if UnifiedLogger.current_logger.is_a?(UnifiedLogger::Logger) && !silenced?(env["REQUEST_PATH"])
|
|
16
|
+
log = build_log(started, env, status, headers, response)
|
|
17
|
+
custom = {}
|
|
18
|
+
UnifiedLogger.transform_request_log_callable&.call(custom, env)
|
|
19
|
+
log.merge!(custom)
|
|
20
|
+
UnifiedLogger.current_logger.write(UnifiedLogger::Logger.format(log))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def silenced?(path)
|
|
27
|
+
UnifiedLogger.config[:silence_paths].any? do |pattern|
|
|
28
|
+
pattern.is_a?(Regexp) ? pattern.match?(path) : pattern == path
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def build_log(started, env, status = nil, headers = nil, response = nil)
|
|
33
|
+
status ||= 500
|
|
34
|
+
headers ||= {}
|
|
35
|
+
response ||= ""
|
|
36
|
+
path_parameters = env["action_dispatch.request.path_parameters"] || {}
|
|
37
|
+
query_string = env["QUERY_STRING"]
|
|
38
|
+
log = {
|
|
39
|
+
log_type: :request,
|
|
40
|
+
timestamp: UnifiedLogger.formatted_time,
|
|
41
|
+
id: env["action_dispatch.request_id"],
|
|
42
|
+
ip: env["action_dispatch.remote_ip"].to_s,
|
|
43
|
+
controller: path_parameters[:controller],
|
|
44
|
+
action: path_parameters[:action],
|
|
45
|
+
request: {
|
|
46
|
+
path: env["REQUEST_PATH"],
|
|
47
|
+
method: env["REQUEST_METHOD"],
|
|
48
|
+
headers: env.select { |e| e.start_with?("HTTP_") }.reject { |h| h.start_with?("HTTP_SEC_") },
|
|
49
|
+
path_params: path_parameters.except(:controller, :action),
|
|
50
|
+
query_params: query_string.blank? ? {} : Rack::Utils.parse_nested_query(query_string),
|
|
51
|
+
body: request_body(env)
|
|
52
|
+
},
|
|
53
|
+
response: {
|
|
54
|
+
headers: headers,
|
|
55
|
+
status: status,
|
|
56
|
+
body: response_body(response, headers["content-type"])
|
|
57
|
+
},
|
|
58
|
+
thread_id: Thread.current.object_id,
|
|
59
|
+
process_id: Process.pid,
|
|
60
|
+
duration: started ? UnifiedLogger.current_time - started : 0
|
|
61
|
+
}
|
|
62
|
+
log[:exception] = UnifiedLogger::Logger.format_exception($ERROR_INFO) if $ERROR_INFO.present?
|
|
63
|
+
log[:custom] = UnifiedLogger::Logger.fetch_and_reset_custom_logs if UnifiedLogger::Logger.custom_logs.any?
|
|
64
|
+
|
|
65
|
+
log
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def request_body(env)
|
|
69
|
+
return nil unless (input = env["rack.input"])
|
|
70
|
+
return env["rack.request.form_hash"] if env["rack.request.form_hash"]
|
|
71
|
+
|
|
72
|
+
input.rewind
|
|
73
|
+
body = input.read
|
|
74
|
+
input.rewind
|
|
75
|
+
|
|
76
|
+
parse_body(body, env["CONTENT_TYPE"])
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def response_body(response, content_type)
|
|
80
|
+
return nil if response.nil? || (response.respond_to?(:empty?) && response.empty?)
|
|
81
|
+
return nil if content_type&.exclude?("application/") && content_type.exclude?("text/plain")
|
|
82
|
+
return response_body(response.body, content_type) if response.respond_to?(:body)
|
|
83
|
+
|
|
84
|
+
body = response.respond_to?(:map) ? response.join : response.to_s
|
|
85
|
+
|
|
86
|
+
parse_body(body, content_type)
|
|
87
|
+
ensure
|
|
88
|
+
response.close if response.respond_to?(:close)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def parse_body(body, content_type)
|
|
92
|
+
return nil if body.nil?
|
|
93
|
+
return nil if body.empty?
|
|
94
|
+
|
|
95
|
+
main_content_type = content_type&.split(";")&.first&.strip&.downcase
|
|
96
|
+
|
|
97
|
+
case main_content_type
|
|
98
|
+
when "application/json"
|
|
99
|
+
JSON.parse(body)
|
|
100
|
+
when "application/x-www-form-urlencoded"
|
|
101
|
+
Rack::Utils.parse_nested_query(body)
|
|
102
|
+
else
|
|
103
|
+
UnifiedLogger::Logger.trim(body)
|
|
104
|
+
end
|
|
105
|
+
rescue JSON::ParserError, TypeError, ArgumentError
|
|
106
|
+
body
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "concurrent"
|
|
2
|
+
require "active_support/core_ext/object/blank"
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
begin
|
|
5
|
+
require "active_support/parameter_filter"
|
|
6
|
+
rescue LoadError
|
|
7
|
+
# ActiveSupport < 6.0; falls back to ActionDispatch::Http::ParameterFilter at runtime
|
|
8
|
+
end
|
|
9
|
+
require "active_support/backtrace_cleaner"
|
|
10
|
+
require "json"
|
|
11
|
+
require "logger"
|
|
12
|
+
|
|
13
|
+
require_relative "unified_logger/version"
|
|
14
|
+
require_relative "unified_logger/logger"
|
|
15
|
+
require_relative "unified_logger/request_logger"
|
|
16
|
+
require_relative "unified_logger/job_logger"
|
|
17
|
+
|
|
18
|
+
module UnifiedLogger
|
|
19
|
+
class DoubleDefineError < StandardError; end
|
|
20
|
+
|
|
21
|
+
DEFAULTS = {
|
|
22
|
+
max_log_field_size: 2048,
|
|
23
|
+
filter_params: %i[passw secret token crypt salt certificate otp ssn set-cookie http_authorization http_cookie pin],
|
|
24
|
+
auto_insert_middleware: true,
|
|
25
|
+
silence_paths: []
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def self.config
|
|
29
|
+
@config ||= DEFAULTS.dup
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.configure(options = {})
|
|
33
|
+
config.merge!(options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
attr_reader :transform_request_log_callable, :transform_job_log_callable, :log_transformer
|
|
38
|
+
|
|
39
|
+
def transform_request_log=(callable)
|
|
40
|
+
raise DoubleDefineError, "transform_request_log already defined" if @transform_request_log_callable
|
|
41
|
+
|
|
42
|
+
@transform_request_log_callable = callable
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def transform_job_log=(callable)
|
|
46
|
+
raise DoubleDefineError, "transform_job_log already defined" if @transform_job_log_callable
|
|
47
|
+
|
|
48
|
+
@transform_job_log_callable = callable
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def log_transformer=(callable)
|
|
52
|
+
raise DoubleDefineError, "log_transformer already defined" if @log_transformer
|
|
53
|
+
|
|
54
|
+
@log_transformer = callable
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
delegate :trim, :format, :format_exception,
|
|
58
|
+
:custom_logs, :fetch_and_reset_custom_logs, :reset_thread_logs,
|
|
59
|
+
to: :"UnifiedLogger::Logger"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.backtrace_root
|
|
63
|
+
if defined?(Rails)
|
|
64
|
+
Rails.root.to_s
|
|
65
|
+
else
|
|
66
|
+
Dir.pwd
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.current_logger
|
|
71
|
+
return unless defined?(Rails)
|
|
72
|
+
|
|
73
|
+
return Rails.logger if Rails.logger.is_a?(UnifiedLogger::Logger)
|
|
74
|
+
return Rails.logger unless Rails.logger.respond_to?(:broadcasts)
|
|
75
|
+
|
|
76
|
+
Rails.logger.broadcasts.find { |l| l.is_a?(UnifiedLogger::Logger) } || Rails.logger
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.current_time
|
|
80
|
+
Time.zone&.now || Time.now.utc
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.formatted_time
|
|
84
|
+
current_time.iso8601(3)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
require "unified_logger/railtie" if defined?(Rails::Railtie)
|
metadata
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: unified_logger
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Marcovecchio
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-03-23 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '4.2'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '4.2'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: concurrent-ruby
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - "~>"
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '1.0'
|
|
39
|
+
type: :runtime
|
|
40
|
+
prerelease: false
|
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - "~>"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '1.0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: rack
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '1.6'
|
|
53
|
+
- - "<"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '4'
|
|
56
|
+
type: :runtime
|
|
57
|
+
prerelease: false
|
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '1.6'
|
|
63
|
+
- - "<"
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '4'
|
|
66
|
+
description: One JSON log line per request or job. Captures request/response data,
|
|
67
|
+
in-app logger calls, exceptions with cleaned backtraces, and sensitive data filtering
|
|
68
|
+
— all in a single event.
|
|
69
|
+
executables: []
|
|
70
|
+
extensions: []
|
|
71
|
+
extra_rdoc_files: []
|
|
72
|
+
files:
|
|
73
|
+
- lib/unified_logger.rb
|
|
74
|
+
- lib/unified_logger/job_logger.rb
|
|
75
|
+
- lib/unified_logger/logger.rb
|
|
76
|
+
- lib/unified_logger/railtie.rb
|
|
77
|
+
- lib/unified_logger/request_logger.rb
|
|
78
|
+
- lib/unified_logger/version.rb
|
|
79
|
+
homepage: https://github.com/marcovecchio/unified_logger
|
|
80
|
+
licenses:
|
|
81
|
+
- MIT
|
|
82
|
+
metadata:
|
|
83
|
+
rubygems_mfa_required: 'true'
|
|
84
|
+
source_code_uri: https://github.com/marcovecchio/unified_logger
|
|
85
|
+
rdoc_options: []
|
|
86
|
+
require_paths:
|
|
87
|
+
- lib
|
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '2.4'
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
requirements: []
|
|
99
|
+
rubygems_version: 3.6.7
|
|
100
|
+
specification_version: 4
|
|
101
|
+
summary: Structured JSON logging for Rack and Rails applications
|
|
102
|
+
test_files: []
|