lumberjack 1.2.7 → 1.4.2
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 +4 -4
- data/ARCHITECTURE.md +244 -0
- data/CHANGELOG.md +251 -56
- data/README.md +197 -62
- data/VERSION +1 -1
- data/lib/lumberjack/context.rb +25 -5
- data/lib/lumberjack/device/date_rolling_log_file.rb +17 -8
- data/lib/lumberjack/device/log_file.rb +14 -7
- data/lib/lumberjack/device/multi.rb +8 -7
- data/lib/lumberjack/device/null.rb +2 -2
- data/lib/lumberjack/device/rolling_log_file.rb +46 -22
- data/lib/lumberjack/device/size_rolling_log_file.rb +10 -10
- data/lib/lumberjack/device/writer.rb +45 -21
- data/lib/lumberjack/device.rb +28 -13
- data/lib/lumberjack/formatter/date_time_formatter.rb +5 -5
- data/lib/lumberjack/formatter/exception_formatter.rb +4 -4
- data/lib/lumberjack/formatter/id_formatter.rb +4 -3
- data/lib/lumberjack/formatter/inspect_formatter.rb +1 -1
- data/lib/lumberjack/formatter/multiply_formatter.rb +25 -0
- data/lib/lumberjack/formatter/object_formatter.rb +1 -1
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +7 -5
- data/lib/lumberjack/formatter/redact_formatter.rb +23 -0
- data/lib/lumberjack/formatter/round_formatter.rb +21 -0
- data/lib/lumberjack/formatter/string_formatter.rb +1 -1
- data/lib/lumberjack/formatter/strip_formatter.rb +1 -1
- data/lib/lumberjack/formatter/structured_formatter.rb +3 -1
- data/lib/lumberjack/formatter/tagged_message.rb +39 -0
- data/lib/lumberjack/formatter/truncate_formatter.rb +27 -0
- data/lib/lumberjack/formatter.rb +96 -28
- data/lib/lumberjack/log_entry.rb +90 -19
- data/lib/lumberjack/logger.rb +318 -86
- data/lib/lumberjack/rack/context.rb +21 -2
- data/lib/lumberjack/rack/request_id.rb +8 -4
- data/lib/lumberjack/rack/unit_of_work.rb +7 -3
- data/lib/lumberjack/rack.rb +4 -4
- data/lib/lumberjack/severity.rb +22 -3
- data/lib/lumberjack/tag_context.rb +78 -0
- data/lib/lumberjack/tag_formatter.rb +124 -25
- data/lib/lumberjack/tagged_logger_support.rb +26 -12
- data/lib/lumberjack/tagged_logging.rb +1 -1
- data/lib/lumberjack/tags.rb +8 -8
- data/lib/lumberjack/template.rb +17 -5
- data/lib/lumberjack/utils.rb +182 -0
- data/lib/lumberjack.rb +64 -35
- data/lumberjack.gemspec +18 -15
- metadata +23 -54
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Device
|
|
@@ -14,35 +14,43 @@ module Lumberjack
|
|
|
14
14
|
class RollingLogFile < LogFile
|
|
15
15
|
attr_reader :path
|
|
16
16
|
attr_accessor :keep
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
def initialize(path, options = {})
|
|
19
19
|
@path = File.expand_path(path)
|
|
20
20
|
@keep = options[:keep]
|
|
21
|
-
super
|
|
22
|
-
@file_inode =
|
|
21
|
+
super
|
|
22
|
+
@file_inode = begin
|
|
23
|
+
stream.lstat.ino
|
|
24
|
+
rescue
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
23
27
|
@@rolls = []
|
|
24
28
|
@next_stat_check = Time.now.to_f
|
|
25
29
|
@min_roll_check = (options[:min_roll_check] || 1.0).to_f
|
|
26
30
|
end
|
|
27
|
-
|
|
31
|
+
|
|
28
32
|
# Returns a suffix that will be appended to the file name when it is archived.. The suffix should
|
|
29
33
|
# change after it is time to roll the file. The log file will be renamed when it is rolled.
|
|
30
34
|
def archive_file_suffix
|
|
31
35
|
raise NotImplementedError
|
|
32
36
|
end
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
# Return +true+ if the file should be rolled.
|
|
35
39
|
def roll_file?
|
|
36
40
|
raise NotImplementedError
|
|
37
41
|
end
|
|
38
|
-
|
|
42
|
+
|
|
39
43
|
# Roll the log file by renaming it to the archive file name and then re-opening a stream to the log
|
|
40
44
|
# file path. Rolling a file is safe in multi-threaded or multi-process environments.
|
|
41
|
-
def roll_file!
|
|
45
|
+
def roll_file! # :nodoc:
|
|
42
46
|
do_once(stream) do
|
|
43
47
|
archive_file = "#{path}.#{archive_file_suffix}"
|
|
44
48
|
stream.flush
|
|
45
|
-
current_inode =
|
|
49
|
+
current_inode = begin
|
|
50
|
+
File.stat(path).ino
|
|
51
|
+
rescue
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
46
54
|
if @file_inode && current_inode == @file_inode && !File.exist?(archive_file) && File.exist?(path)
|
|
47
55
|
begin
|
|
48
56
|
File.rename(path, archive_file)
|
|
@@ -59,41 +67,49 @@ module Lumberjack
|
|
|
59
67
|
end
|
|
60
68
|
|
|
61
69
|
protected
|
|
62
|
-
|
|
70
|
+
|
|
63
71
|
# This method will be called after a file has been rolled. Subclasses can
|
|
64
72
|
# implement code to reset the state of the device. This method is thread safe.
|
|
65
73
|
def after_roll
|
|
66
74
|
end
|
|
67
|
-
|
|
75
|
+
|
|
68
76
|
# Handle rolling the file before flushing.
|
|
69
77
|
def before_flush # :nodoc:
|
|
70
78
|
if @min_roll_check <= 0.0 || Time.now.to_f >= @next_stat_check
|
|
71
79
|
@next_stat_check += @min_roll_check
|
|
72
|
-
path_inode =
|
|
80
|
+
path_inode = begin
|
|
81
|
+
File.lstat(path).ino
|
|
82
|
+
rescue
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
73
85
|
if path_inode != @file_inode
|
|
74
86
|
@file_inode = path_inode
|
|
75
87
|
reopen_file
|
|
76
|
-
|
|
77
|
-
roll_file!
|
|
88
|
+
elsif roll_file?
|
|
89
|
+
roll_file!
|
|
78
90
|
end
|
|
79
91
|
end
|
|
80
92
|
end
|
|
81
|
-
|
|
93
|
+
|
|
82
94
|
private
|
|
83
95
|
|
|
84
96
|
def reopen_file
|
|
85
97
|
old_stream = stream
|
|
86
|
-
new_stream = File.open(path,
|
|
98
|
+
new_stream = File.open(path, "a", encoding: EXTERNAL_ENCODING)
|
|
87
99
|
new_stream.sync = true if buffer_size > 0
|
|
88
|
-
@file_inode =
|
|
100
|
+
@file_inode = begin
|
|
101
|
+
new_stream.lstat.ino
|
|
102
|
+
rescue
|
|
103
|
+
nil
|
|
104
|
+
end
|
|
89
105
|
self.stream = new_stream
|
|
90
106
|
old_stream.close
|
|
91
107
|
end
|
|
92
108
|
end
|
|
93
|
-
|
|
109
|
+
|
|
94
110
|
def cleanup_files!
|
|
95
111
|
if keep
|
|
96
|
-
files = Dir.glob("#{path}.*").collect{|f| [f, File.ctime(f)]}.sort{|a,b| b.last <=> a.last}.collect{|a| a.first}
|
|
112
|
+
files = Dir.glob("#{path}.*").collect { |f| [f, File.ctime(f)] }.sort { |a, b| b.last <=> a.last }.collect { |a| a.first }
|
|
97
113
|
if files.size > keep
|
|
98
114
|
files[keep, files.length].each do |f|
|
|
99
115
|
File.delete(f)
|
|
@@ -101,7 +117,7 @@ module Lumberjack
|
|
|
101
117
|
end
|
|
102
118
|
end
|
|
103
119
|
end
|
|
104
|
-
|
|
120
|
+
|
|
105
121
|
def do_once(file)
|
|
106
122
|
begin
|
|
107
123
|
file.flock(File::LOCK_EX)
|
|
@@ -110,11 +126,19 @@ module Lumberjack
|
|
|
110
126
|
return
|
|
111
127
|
end
|
|
112
128
|
begin
|
|
113
|
-
verify =
|
|
129
|
+
verify = begin
|
|
130
|
+
file.lstat
|
|
131
|
+
rescue
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
114
134
|
# Execute only if the file we locked is still the same one that needed to be rolled
|
|
115
135
|
yield if verify && verify.ino == @file_inode && verify.size > 0
|
|
116
136
|
ensure
|
|
117
|
-
|
|
137
|
+
begin
|
|
138
|
+
file.flock(File::LOCK_UN)
|
|
139
|
+
rescue
|
|
140
|
+
nil
|
|
141
|
+
end
|
|
118
142
|
end
|
|
119
143
|
end
|
|
120
144
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Device
|
|
@@ -8,30 +8,30 @@ module Lumberjack
|
|
|
8
8
|
# production.log.1, then production.log.2, etc.
|
|
9
9
|
class SizeRollingLogFile < RollingLogFile
|
|
10
10
|
attr_reader :max_size
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# Create an new log device to the specified file. The maximum size of the log file is specified with
|
|
13
13
|
# the :max_size option. The unit can also be specified: "32K", "100M", "2G" are all valid.
|
|
14
14
|
def initialize(path, options = {})
|
|
15
15
|
@manual = options[:manual]
|
|
16
16
|
@max_size = options[:max_size]
|
|
17
17
|
if @max_size.is_a?(String)
|
|
18
|
-
if @max_size
|
|
18
|
+
if @max_size =~ /^(\d+(\.\d+)?)([KMG])?$/i
|
|
19
19
|
@max_size = $~[1].to_f
|
|
20
20
|
units = $~[3].to_s.upcase
|
|
21
21
|
case units
|
|
22
22
|
when "K"
|
|
23
23
|
@max_size *= 1024
|
|
24
24
|
when "M"
|
|
25
|
-
@max_size *= 1024
|
|
25
|
+
@max_size *= 1024**2
|
|
26
26
|
when "G"
|
|
27
|
-
@max_size *= 1024
|
|
27
|
+
@max_size *= 1024**3
|
|
28
28
|
end
|
|
29
29
|
@max_size = @max_size.round
|
|
30
30
|
else
|
|
31
31
|
raise ArgumentError.new("illegal value for :max_size (#{@max_size})")
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
super
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -44,15 +44,15 @@ module Lumberjack
|
|
|
44
44
|
rescue SystemCallError
|
|
45
45
|
false
|
|
46
46
|
end
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
protected
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
# Calculate the next archive file name extension.
|
|
51
51
|
def next_archive_number # :nodoc:
|
|
52
52
|
max = 0
|
|
53
53
|
Dir.glob("#{path}.*").each do |filename|
|
|
54
|
-
if
|
|
55
|
-
suffix = filename.split(
|
|
54
|
+
if /\.\d+\z/ =~ filename
|
|
55
|
+
suffix = filename.split(".").last.to_i
|
|
56
56
|
max = suffix if suffix > max
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Device
|
|
@@ -55,34 +55,42 @@ module Lumberjack
|
|
|
55
55
|
# :additional_lines and :time_format options will be passed through to the
|
|
56
56
|
# Template constuctor.
|
|
57
57
|
#
|
|
58
|
-
# The default template is "[:time :severity :progname(:pid)
|
|
59
|
-
# with additional lines formatted as "\n
|
|
60
|
-
# work id will only appear if it is present.
|
|
58
|
+
# The default template is "[:time :severity :progname(:pid)] :message"
|
|
59
|
+
# with additional lines formatted as "\n :message".
|
|
61
60
|
#
|
|
62
61
|
# The size of the internal buffer in bytes can be set by providing :buffer_size (defaults to 32K).
|
|
62
|
+
#
|
|
63
|
+
# @param [IO] stream The stream to write log entries to.
|
|
64
|
+
# @param [Hash] options The options for the device.
|
|
63
65
|
def initialize(stream, options = {})
|
|
64
66
|
@lock = Mutex.new
|
|
65
67
|
@stream = stream
|
|
66
68
|
@stream.sync = true if @stream.respond_to?(:sync=)
|
|
67
69
|
@buffer = Buffer.new
|
|
68
|
-
@buffer_size =
|
|
69
|
-
template =
|
|
70
|
+
@buffer_size = options[:buffer_size] || 0
|
|
71
|
+
template = options[:template] || DEFAULT_FIRST_LINE_TEMPLATE
|
|
70
72
|
if template.respond_to?(:call)
|
|
71
73
|
@template = template
|
|
72
74
|
else
|
|
73
|
-
additional_lines =
|
|
74
|
-
@template = Template.new(template, :
|
|
75
|
+
additional_lines = options[:additional_lines] || DEFAULT_ADDITIONAL_LINES_TEMPLATE
|
|
76
|
+
@template = Template.new(template, additional_lines: additional_lines, time_format: options[:time_format])
|
|
75
77
|
end
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
# Set the buffer size in bytes. The device will only be physically written to when the buffer size
|
|
79
81
|
# is exceeded.
|
|
82
|
+
#
|
|
83
|
+
# @param [Integer] value The size of the buffer in bytes.
|
|
84
|
+
# @return [void]
|
|
80
85
|
def buffer_size=(value)
|
|
81
86
|
@buffer_size = value
|
|
82
87
|
flush
|
|
83
88
|
end
|
|
84
89
|
|
|
85
90
|
# Write an entry to the stream. The entry will be converted into a string using the defined template.
|
|
91
|
+
#
|
|
92
|
+
# @param [LogEntry, String] entry The entry to write to the stream.
|
|
93
|
+
# @return [void]
|
|
86
94
|
def write(entry)
|
|
87
95
|
string = (entry.is_a?(LogEntry) ? @template.call(entry) : entry)
|
|
88
96
|
return if string.nil?
|
|
@@ -105,12 +113,16 @@ module Lumberjack
|
|
|
105
113
|
end
|
|
106
114
|
|
|
107
115
|
# Close the underlying stream.
|
|
116
|
+
#
|
|
117
|
+
# @return [void]
|
|
108
118
|
def close
|
|
109
119
|
flush
|
|
110
120
|
stream.close
|
|
111
121
|
end
|
|
112
122
|
|
|
113
123
|
# Flush the underlying stream.
|
|
124
|
+
#
|
|
125
|
+
# @return [void]
|
|
114
126
|
def flush
|
|
115
127
|
lines = nil
|
|
116
128
|
@lock.synchronize do
|
|
@@ -120,39 +132,47 @@ module Lumberjack
|
|
|
120
132
|
write_to_stream(lines) if lines
|
|
121
133
|
end
|
|
122
134
|
|
|
135
|
+
# Get the datetime format.
|
|
136
|
+
#
|
|
137
|
+
# @return [String] The datetime format.
|
|
123
138
|
def datetime_format
|
|
124
139
|
@template.datetime_format if @template.respond_to?(:datetime_format)
|
|
125
140
|
end
|
|
126
141
|
|
|
142
|
+
# Set the datetime format.
|
|
143
|
+
#
|
|
144
|
+
# @param [String] format The datetime format.
|
|
145
|
+
# @return [void]
|
|
127
146
|
def datetime_format=(format)
|
|
128
147
|
if @template.respond_to?(:datetime_format=)
|
|
129
148
|
@template.datetime_format = format
|
|
130
149
|
end
|
|
131
150
|
end
|
|
132
151
|
|
|
152
|
+
# Return the underlying stream. Provided for API compatibility with Logger devices.
|
|
153
|
+
#
|
|
154
|
+
# @return [IO] The underlying stream.
|
|
155
|
+
def dev
|
|
156
|
+
@stream
|
|
157
|
+
end
|
|
158
|
+
|
|
133
159
|
protected
|
|
134
160
|
|
|
135
161
|
# Set the underlying stream.
|
|
136
|
-
|
|
137
|
-
@stream = stream
|
|
138
|
-
end
|
|
162
|
+
attr_writer :stream
|
|
139
163
|
|
|
140
164
|
# Get the underlying stream.
|
|
141
|
-
|
|
142
|
-
@stream
|
|
143
|
-
end
|
|
165
|
+
attr_reader :stream
|
|
144
166
|
|
|
145
167
|
private
|
|
146
168
|
|
|
147
169
|
def write_to_stream(lines)
|
|
148
170
|
return if lines.empty?
|
|
149
171
|
lines = lines.first if lines.is_a?(Array) && lines.size == 1
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if lines.is_a?(Array)
|
|
153
|
-
out = "#{lines.join(Lumberjack::LINE_SEPARATOR)}#{Lumberjack::LINE_SEPARATOR}"
|
|
172
|
+
out = if lines.is_a?(Array)
|
|
173
|
+
"#{lines.join(Lumberjack::LINE_SEPARATOR)}#{Lumberjack::LINE_SEPARATOR}"
|
|
154
174
|
else
|
|
155
|
-
|
|
175
|
+
"#{lines}#{Lumberjack::LINE_SEPARATOR}"
|
|
156
176
|
end
|
|
157
177
|
|
|
158
178
|
begin
|
|
@@ -170,9 +190,13 @@ module Lumberjack
|
|
|
170
190
|
end
|
|
171
191
|
end
|
|
172
192
|
end
|
|
173
|
-
|
|
193
|
+
begin
|
|
194
|
+
stream.flush
|
|
195
|
+
rescue
|
|
196
|
+
nil
|
|
197
|
+
end
|
|
174
198
|
rescue => e
|
|
175
|
-
$stderr.write("#{e.class.name}: #{e.message}#{
|
|
199
|
+
$stderr.write("#{e.class.name}: #{e.message}#{" at " + e.backtrace.first if e.backtrace}")
|
|
176
200
|
$stderr.write(out)
|
|
177
201
|
$stderr.flush
|
|
178
202
|
end
|
data/lib/lumberjack/device.rb
CHANGED
|
@@ -1,41 +1,56 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
# This is an abstract class for logging devices. Subclasses must implement the +write+ method and
|
|
5
5
|
# may implement the +close+ and +flush+ methods if applicable.
|
|
6
6
|
class Device
|
|
7
|
-
require_relative "device/writer
|
|
8
|
-
require_relative "device/log_file
|
|
9
|
-
require_relative "device/rolling_log_file
|
|
10
|
-
require_relative "device/date_rolling_log_file
|
|
11
|
-
require_relative "device/size_rolling_log_file
|
|
12
|
-
require_relative "device/multi
|
|
13
|
-
require_relative "device/null
|
|
7
|
+
require_relative "device/writer"
|
|
8
|
+
require_relative "device/log_file"
|
|
9
|
+
require_relative "device/rolling_log_file"
|
|
10
|
+
require_relative "device/date_rolling_log_file"
|
|
11
|
+
require_relative "device/size_rolling_log_file"
|
|
12
|
+
require_relative "device/multi"
|
|
13
|
+
require_relative "device/null"
|
|
14
14
|
|
|
15
15
|
# Subclasses must implement this method to write a LogEntry.
|
|
16
|
+
#
|
|
17
|
+
# @param [Lumberjack::LogEntry] entry The entry to write.
|
|
18
|
+
# @return [void]
|
|
16
19
|
def write(entry)
|
|
17
20
|
raise NotImplementedError
|
|
18
21
|
end
|
|
19
|
-
|
|
22
|
+
|
|
20
23
|
# Subclasses may implement this method to close the device.
|
|
24
|
+
#
|
|
25
|
+
# @return [void]
|
|
21
26
|
def close
|
|
22
27
|
flush
|
|
23
28
|
end
|
|
24
|
-
|
|
29
|
+
|
|
25
30
|
# Subclasses may implement this method to reopen the device.
|
|
31
|
+
#
|
|
32
|
+
# @param [Object] logdev The log device to use.
|
|
33
|
+
# @return [void]
|
|
26
34
|
def reopen(logdev = nil)
|
|
27
35
|
flush
|
|
28
36
|
end
|
|
29
|
-
|
|
37
|
+
|
|
30
38
|
# Subclasses may implement this method to flush any buffers used by the device.
|
|
39
|
+
#
|
|
40
|
+
# @return [void]
|
|
31
41
|
def flush
|
|
32
42
|
end
|
|
33
|
-
|
|
43
|
+
|
|
34
44
|
# Subclasses may implement this method to get the format for log timestamps.
|
|
45
|
+
#
|
|
46
|
+
# @return [String] The format for log timestamps.
|
|
35
47
|
def datetime_format
|
|
36
48
|
end
|
|
37
|
-
|
|
49
|
+
|
|
38
50
|
# Subclasses may implement this method to set a format for log timestamps.
|
|
51
|
+
#
|
|
52
|
+
# @param [String] format The format for log timestamps.
|
|
53
|
+
# @return [void]
|
|
39
54
|
def datetime_format=(format)
|
|
40
55
|
end
|
|
41
56
|
end
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Formatter
|
|
5
5
|
# Format a Date, Time, or DateTime object. If you don't specify a format in the constructor,
|
|
6
6
|
# it will use the ISO-8601 format.
|
|
7
7
|
class DateTimeFormatter
|
|
8
|
-
|
|
9
8
|
attr_reader :format
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
# @param [String] format The format to use when formatting the date/time object.
|
|
11
11
|
def initialize(format = nil)
|
|
12
12
|
@format = format.dup.to_s.freeze unless format.nil?
|
|
13
13
|
end
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def call(obj)
|
|
16
16
|
if @format && obj.respond_to?(:strftime)
|
|
17
17
|
obj.strftime(@format)
|
|
18
18
|
elsif obj.respond_to?(:iso8601)
|
|
19
|
-
obj.iso8601
|
|
19
|
+
obj.iso8601(6)
|
|
20
20
|
else
|
|
21
21
|
obj.to_s
|
|
22
22
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Formatter
|
|
@@ -7,15 +7,16 @@ module Lumberjack
|
|
|
7
7
|
# passed to this object and the returned array is what will be logged. You can
|
|
8
8
|
# use this to clean out superfluous lines.
|
|
9
9
|
class ExceptionFormatter
|
|
10
|
-
|
|
11
10
|
attr_accessor :backtrace_cleaner
|
|
12
11
|
|
|
12
|
+
# @param [#call] backtrace_cleaner An object that responds to `call` and takes
|
|
13
|
+
# an array of strings (the backtrace) and returns an array of strings (the
|
|
13
14
|
def initialize(backtrace_cleaner = nil)
|
|
14
15
|
self.backtrace_cleaner = backtrace_cleaner
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def call(exception)
|
|
18
|
-
message = "#{exception.class.name}: #{exception.message}"
|
|
19
|
+
message = +"#{exception.class.name}: #{exception.message}"
|
|
19
20
|
trace = exception.backtrace
|
|
20
21
|
if trace
|
|
21
22
|
trace = clean_backtrace(trace)
|
|
@@ -33,7 +34,6 @@ module Lumberjack
|
|
|
33
34
|
trace
|
|
34
35
|
end
|
|
35
36
|
end
|
|
36
|
-
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Lumberjack
|
|
4
4
|
class Formatter
|
|
@@ -6,14 +6,15 @@ module Lumberjack
|
|
|
6
6
|
# as a default formatter for objects pulled from a data store. By default it will use :id as the
|
|
7
7
|
# id attribute.
|
|
8
8
|
class IdFormatter
|
|
9
|
+
# @param [Symbol, String] id_attribute The attribute to use as the id.
|
|
9
10
|
def initialize(id_attribute = :id)
|
|
10
11
|
@id_attribute = id_attribute
|
|
11
12
|
end
|
|
12
|
-
|
|
13
|
+
|
|
13
14
|
def call(obj)
|
|
14
15
|
if obj.respond_to?(@id_attribute)
|
|
15
16
|
id = obj.send(@id_attribute)
|
|
16
|
-
{
|
|
17
|
+
{"class" => obj.class.name, "id" => id}
|
|
17
18
|
else
|
|
18
19
|
obj.to_s
|
|
19
20
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
class Formatter
|
|
5
|
+
# This formatter can be used to multiply a numeric value by a specified multiplier and
|
|
6
|
+
# optionally round to a specified number of decimal places.
|
|
7
|
+
class MultiplyFormatter
|
|
8
|
+
# @param multiplier [Numeric] The multiplier to apply to the value.
|
|
9
|
+
# @param decimals [Integer, nil] The number of decimal places to round the result to.
|
|
10
|
+
# If nil, no rounding is applied.
|
|
11
|
+
def initialize(multiplier, decimals = nil)
|
|
12
|
+
@multiplier = multiplier
|
|
13
|
+
@decimals = decimals
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def call(value)
|
|
17
|
+
return value unless value.is_a?(Numeric)
|
|
18
|
+
|
|
19
|
+
value *= @multiplier
|
|
20
|
+
value = value.round(@decimals) if @decimals
|
|
21
|
+
value
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "pp"
|
|
4
|
+
require "stringio"
|
|
5
5
|
|
|
6
6
|
module Lumberjack
|
|
7
7
|
class Formatter
|
|
8
8
|
# Format an object with it's pretty print method.
|
|
9
9
|
class PrettyPrintFormatter
|
|
10
10
|
attr_accessor :width
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# Create a new formatter. The maximum width of the message can be specified with the width
|
|
13
13
|
# parameter (defaults to 79 characters).
|
|
14
|
+
#
|
|
15
|
+
# @param [Integer] width The maximum width of the message.
|
|
14
16
|
def initialize(width = 79)
|
|
15
17
|
@width = width
|
|
16
18
|
end
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
def call(obj)
|
|
19
21
|
s = StringIO.new
|
|
20
22
|
PP.pp(obj, s)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
class Formatter
|
|
5
|
+
# Log sensitive information in a redacted format showing the firat and last
|
|
6
|
+
# characters of the value, with the rest replaced by asterisks. The number of
|
|
7
|
+
# characters shown is dependent onthe length of the value; short values will
|
|
8
|
+
# not show any characters in order to avoid revealing too much information.
|
|
9
|
+
class RedactFormatter
|
|
10
|
+
def call(obj)
|
|
11
|
+
return obj unless obj.is_a?(String)
|
|
12
|
+
|
|
13
|
+
if obj.length > 8
|
|
14
|
+
"#{obj[0..1]}#{"*" * (obj.length - 4)}#{obj[-2..-1]}"
|
|
15
|
+
elsif obj.length > 5
|
|
16
|
+
"#{obj[0]}#{"*" * (obj.length - 2)}#{obj[-1]}"
|
|
17
|
+
else
|
|
18
|
+
"*****"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
class Formatter
|
|
5
|
+
# Round numeric values to a set number of decimal places. This is useful when logging
|
|
6
|
+
# floating point numbers to reduce noise and rounding errors in the logs.
|
|
7
|
+
class RoundFormatter
|
|
8
|
+
def initialize(precision = 3)
|
|
9
|
+
@precision = precision
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(obj)
|
|
13
|
+
if obj.is_a?(Numeric)
|
|
14
|
+
obj.round(@precision)
|
|
15
|
+
else
|
|
16
|
+
obj
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "set"
|
|
4
4
|
|
|
@@ -9,6 +9,8 @@ module Lumberjack
|
|
|
9
9
|
class RecusiveReferenceError < StandardError
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
# @param [Formatter] formatter The formatter to call on each element
|
|
13
|
+
# in the structure.
|
|
12
14
|
def initialize(formatter = nil)
|
|
13
15
|
@formatter = formatter
|
|
14
16
|
end
|