lumberjack 1.0.12 → 1.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/lumberjack.rb +2 -0
- data/lib/lumberjack/device.rb +2 -0
- data/lib/lumberjack/device/date_rolling_log_file.rb +2 -0
- data/lib/lumberjack/device/log_file.rb +2 -0
- data/lib/lumberjack/device/null.rb +2 -0
- data/lib/lumberjack/device/rolling_log_file.rb +21 -10
- data/lib/lumberjack/device/size_rolling_log_file.rb +2 -0
- data/lib/lumberjack/device/writer.rb +36 -14
- data/lib/lumberjack/formatter.rb +2 -0
- data/lib/lumberjack/formatter/exception_formatter.rb +2 -0
- data/lib/lumberjack/formatter/inspect_formatter.rb +2 -0
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +2 -0
- data/lib/lumberjack/formatter/string_formatter.rb +2 -0
- data/lib/lumberjack/log_entry.rb +2 -0
- data/lib/lumberjack/logger.rb +2 -1
- data/lib/lumberjack/rack.rb +2 -0
- data/lib/lumberjack/rack/request_id.rb +2 -0
- data/lib/lumberjack/rack/unit_of_work.rb +2 -0
- data/lib/lumberjack/severity.rb +2 -0
- data/lib/lumberjack/template.rb +2 -0
- data/spec/device/date_rolling_log_file_spec.rb +7 -3
- data/spec/device/log_file_spec.rb +4 -0
- data/spec/device/rolling_log_file_spec.rb +13 -12
- data/spec/device/size_rolling_log_file_spec.rb +9 -5
- data/spec/spec_helper.rb +7 -1
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aafe117d91082b575618e962e3d66a0b6d3c81b4
|
4
|
+
data.tar.gz: a4d32d48a82b15e8d67e0e00ab3b3637a63b7e99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33d8f2e2e386edad724394264f76c33c17e3df6d9dd394b3444a7abebe12d5e93d3ce8a88726e8b67fcfb2c279615741a9e55b9112d5ec45e50e0c139f481a36
|
7
|
+
data.tar.gz: 129825a3150dad02aecde16130974c2add346fe27d6455e0ea22d6616d6e766306af8c7123ef10ec7e51ca81f06e7a6f1d0cd573abd7566f07b1b15efeed415a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.13
|
data/lib/lumberjack.rb
CHANGED
data/lib/lumberjack/device.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literals: true
|
2
|
+
|
1
3
|
module Lumberjack
|
2
4
|
class Device
|
3
5
|
# This is an abstract class for a device that appends entries to a file and periodically archives
|
@@ -6,6 +8,9 @@ module Lumberjack
|
|
6
8
|
#
|
7
9
|
# The <tt>:keep</tt> option can be used to specify a maximum number of rolled log files to keep.
|
8
10
|
# Older files will be deleted based on the time they were created. The default is to keep all files.
|
11
|
+
#
|
12
|
+
# The <tt>:min_roll_check</tt> option can be used to specify the number of seconds between checking
|
13
|
+
# the file to determine if it needs to be rolled. The default is to check at most once per second.
|
9
14
|
class RollingLogFile < LogFile
|
10
15
|
attr_reader :path
|
11
16
|
attr_accessor :keep
|
@@ -16,6 +21,8 @@ module Lumberjack
|
|
16
21
|
super(path, options)
|
17
22
|
@file_inode = stream.lstat.ino rescue nil
|
18
23
|
@@rolls = []
|
24
|
+
@next_stat_check = Time.now.to_f
|
25
|
+
@min_roll_check = (options[:min_roll_check] || 1.0).to_f
|
19
26
|
end
|
20
27
|
|
21
28
|
# Returns a suffix that will be appended to the file name when it is archived.. The suffix should
|
@@ -48,7 +55,7 @@ module Lumberjack
|
|
48
55
|
reopen_file
|
49
56
|
end
|
50
57
|
rescue => e
|
51
|
-
|
58
|
+
$stderr.write("Failed to roll file #{path}: #{e.inspect}\n#{e.backtrace.join("\n")}\n")
|
52
59
|
end
|
53
60
|
|
54
61
|
protected
|
@@ -60,12 +67,15 @@ module Lumberjack
|
|
60
67
|
|
61
68
|
# Handle rolling the file before flushing.
|
62
69
|
def before_flush # :nodoc:
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
70
|
+
if @min_roll_check <= 0.0 || Time.now.to_f >= @next_stat_check
|
71
|
+
@next_stat_check += @min_roll_check
|
72
|
+
path_inode = File.lstat(path).ino rescue nil
|
73
|
+
if path_inode != @file_inode
|
74
|
+
@file_inode = path_inode
|
75
|
+
reopen_file
|
76
|
+
else
|
77
|
+
roll_file! if roll_file?
|
78
|
+
end
|
69
79
|
end
|
70
80
|
end
|
71
81
|
|
@@ -73,9 +83,10 @@ module Lumberjack
|
|
73
83
|
|
74
84
|
def reopen_file
|
75
85
|
old_stream = stream
|
76
|
-
|
77
|
-
|
78
|
-
@file_inode =
|
86
|
+
new_stream = File.open(path, 'a', encoding: EXTERNAL_ENCODING)
|
87
|
+
new_stream.sync = true if buffer_size > 0
|
88
|
+
@file_inode = new_stream.lstat.ino rescue nil
|
89
|
+
self.stream = new_stream
|
79
90
|
old_stream.close
|
80
91
|
end
|
81
92
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literals: true
|
2
|
+
|
1
3
|
module Lumberjack
|
2
4
|
class Device
|
3
5
|
# This logging device writes log entries as strings to an IO stream. By default, messages will be buffered
|
@@ -19,7 +21,7 @@ module Lumberjack
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def <<(string)
|
22
|
-
@values << string
|
24
|
+
@values << string
|
23
25
|
@size += string.size
|
24
26
|
end
|
25
27
|
|
@@ -27,8 +29,10 @@ module Lumberjack
|
|
27
29
|
@values.empty?
|
28
30
|
end
|
29
31
|
|
30
|
-
def
|
31
|
-
@values
|
32
|
+
def pop!
|
33
|
+
popped = @values
|
34
|
+
clear
|
35
|
+
popped
|
32
36
|
end
|
33
37
|
|
34
38
|
def clear
|
@@ -77,8 +81,11 @@ module Lumberjack
|
|
77
81
|
# Write an entry to the stream. The entry will be converted into a string using the defined template.
|
78
82
|
def write(entry)
|
79
83
|
string = @template.call(entry)
|
80
|
-
|
81
|
-
|
84
|
+
unless string.nil?
|
85
|
+
string = string.encode("UTF-8".freeze, invalid: :replace, undef: :replace)
|
86
|
+
@lock.synchronize do
|
87
|
+
@buffer << string
|
88
|
+
end
|
82
89
|
end
|
83
90
|
flush if @buffer.size >= buffer_size
|
84
91
|
end
|
@@ -91,19 +98,34 @@ module Lumberjack
|
|
91
98
|
|
92
99
|
# Flush the underlying stream.
|
93
100
|
def flush
|
101
|
+
lines = nil
|
94
102
|
@lock.synchronize do
|
95
103
|
before_flush
|
96
|
-
|
97
|
-
|
104
|
+
lines = @buffer.pop!
|
105
|
+
end
|
106
|
+
|
107
|
+
unless lines.empty?
|
108
|
+
out = "#{lines.join(Lumberjack::LINE_SEPARATOR)}#{Lumberjack::LINE_SEPARATOR}"
|
109
|
+
begin
|
98
110
|
begin
|
99
111
|
stream.write(out)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
112
|
+
rescue IOError => e
|
113
|
+
# This condition can happen if another thread closed the stream in the `before_flush` call.
|
114
|
+
# Synchronizing will handle the race condition, but since it's an exceptional case we don't
|
115
|
+
# to lock the thread on every stream write call.
|
116
|
+
@lock.synchronize do
|
117
|
+
if stream.closed?
|
118
|
+
raise e
|
119
|
+
else
|
120
|
+
stream.write(out)
|
121
|
+
end
|
122
|
+
end
|
105
123
|
end
|
106
|
-
|
124
|
+
stream.flush rescue nil
|
125
|
+
rescue => e
|
126
|
+
$stderr.write("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
|
127
|
+
$stderr.write(out)
|
128
|
+
$stderr.flush
|
107
129
|
end
|
108
130
|
end
|
109
131
|
end
|
@@ -111,7 +133,7 @@ module Lumberjack
|
|
111
133
|
protected
|
112
134
|
|
113
135
|
# Callback method that will be executed before data is written to the stream. Subclasses
|
114
|
-
# can override this method if needed.
|
136
|
+
# can override this method if needed. This method will be called in a mutex lock.
|
115
137
|
def before_flush
|
116
138
|
end
|
117
139
|
|
data/lib/lumberjack/formatter.rb
CHANGED
data/lib/lumberjack/log_entry.rb
CHANGED
data/lib/lumberjack/logger.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literals: true
|
2
|
+
|
1
3
|
module Lumberjack
|
2
4
|
# Logger is a thread safe logging object. It has a compatible API with the Ruby
|
3
5
|
# standard library Logger class, the Log4r gem, and ActiveSupport::BufferedLogger.
|
@@ -65,7 +67,6 @@ module Lumberjack
|
|
65
67
|
|
66
68
|
@device = open_device(device, options)
|
67
69
|
@_formatter = Formatter.new
|
68
|
-
@lock = Mutex.new
|
69
70
|
@last_flushed_at = Time.now
|
70
71
|
@silencer = true
|
71
72
|
|
data/lib/lumberjack/rack.rb
CHANGED
data/lib/lumberjack/severity.rb
CHANGED
data/lib/lumberjack/template.rb
CHANGED
@@ -10,12 +10,16 @@ describe Lumberjack::Device::DateRollingLogFile do
|
|
10
10
|
delete_tmp_dir
|
11
11
|
end
|
12
12
|
|
13
|
+
before :each do
|
14
|
+
delete_tmp_files
|
15
|
+
end
|
16
|
+
|
13
17
|
let(:one_day){ 60 * 60 * 24 }
|
14
18
|
|
15
19
|
it "should roll the file daily" do
|
16
20
|
now = Time.now
|
17
21
|
log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
|
18
|
-
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :daily, :template => ":message")
|
22
|
+
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :daily, :template => ":message", :min_roll_check => 0)
|
19
23
|
logger = Lumberjack::Logger.new(device, :buffer_size => 2)
|
20
24
|
Timecop.travel(now) do
|
21
25
|
logger.error("test day one")
|
@@ -33,7 +37,7 @@ describe Lumberjack::Device::DateRollingLogFile do
|
|
33
37
|
it "should roll the file weekly" do
|
34
38
|
now = Time.now
|
35
39
|
log_file = File.join(tmp_dir, "b#{rand(1000000000)}.log")
|
36
|
-
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :weekly, :template => ":message")
|
40
|
+
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :weekly, :template => ":message", :min_roll_check => 0)
|
37
41
|
logger = Lumberjack::Logger.new(device, :buffer_size => 2)
|
38
42
|
Timecop.freeze(now) do
|
39
43
|
logger.error("test week one")
|
@@ -51,7 +55,7 @@ describe Lumberjack::Device::DateRollingLogFile do
|
|
51
55
|
it "should roll the file monthly" do
|
52
56
|
now = Time.now
|
53
57
|
log_file = File.join(tmp_dir, "c#{rand(1000000000)}.log")
|
54
|
-
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :monthly, :template => ":message")
|
58
|
+
device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :monthly, :template => ":message", :min_roll_check => 0)
|
55
59
|
logger = Lumberjack::Logger.new(device, :buffer_size => 2)
|
56
60
|
Timecop.freeze(now) do
|
57
61
|
logger.error("test month one")
|
@@ -11,10 +11,14 @@ describe Lumberjack::Device::RollingLogFile do
|
|
11
11
|
delete_tmp_dir
|
12
12
|
end
|
13
13
|
|
14
|
+
before :each do
|
15
|
+
delete_tmp_files
|
16
|
+
end
|
17
|
+
|
14
18
|
let(:entry){ Lumberjack::LogEntry.new(Time.now, 1, "New log entry", nil, $$, nil) }
|
15
19
|
|
16
20
|
it "should check for rolling the log file on flush" do
|
17
|
-
device = Lumberjack::Device::RollingLogFile.new(File.join(tmp_dir, "test.log"), :buffer_size => 32767)
|
21
|
+
device = Lumberjack::Device::RollingLogFile.new(File.join(tmp_dir, "test.log"), :buffer_size => 32767, :min_roll_check => 0)
|
18
22
|
device.write(entry)
|
19
23
|
expect(device).to receive(:roll_file?).twice.and_return(false)
|
20
24
|
device.flush
|
@@ -23,7 +27,7 @@ describe Lumberjack::Device::RollingLogFile do
|
|
23
27
|
|
24
28
|
it "should roll the file by archiving the existing file and opening a new stream and calling after_roll" do
|
25
29
|
log_file = File.join(tmp_dir, "test_2.log")
|
26
|
-
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :buffer_size => 32767)
|
30
|
+
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :buffer_size => 32767, :min_roll_check => 0)
|
27
31
|
expect(device).to receive(:roll_file?).and_return(false, true)
|
28
32
|
expect(device).to receive(:after_roll)
|
29
33
|
device.stub(:archive_file_suffix => "rolled")
|
@@ -37,7 +41,7 @@ describe Lumberjack::Device::RollingLogFile do
|
|
37
41
|
|
38
42
|
it "should reopen the file if the stream inode doesn't match the file path inode" do
|
39
43
|
log_file = File.join(tmp_dir, "test_3.log")
|
40
|
-
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message")
|
44
|
+
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :min_roll_check => 0)
|
41
45
|
device.stub(:roll_file? => false)
|
42
46
|
device.write(entry)
|
43
47
|
device.flush
|
@@ -59,7 +63,7 @@ describe Lumberjack::Device::RollingLogFile do
|
|
59
63
|
message = "This is a test message that is written to the log file to indicate what the state of the application is."
|
60
64
|
|
61
65
|
logger_test = lambda do
|
62
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => max_size, :template => ":message", :buffer_size => 32767)
|
66
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => max_size, :template => ":message", :buffer_size => 32767, :min_roll_check => 0)
|
63
67
|
threads = []
|
64
68
|
thread_count.times do
|
65
69
|
threads << Thread.new do
|
@@ -67,9 +71,10 @@ describe Lumberjack::Device::RollingLogFile do
|
|
67
71
|
device.write(Lumberjack::LogEntry.new(Time.now, severity, message, "test", $$, nil))
|
68
72
|
device.flush if i % 10 == 0
|
69
73
|
end
|
74
|
+
device.flush
|
70
75
|
end
|
71
76
|
end
|
72
|
-
threads.each{|thread| thread.
|
77
|
+
threads.each{|thread| thread.value}
|
73
78
|
device.close
|
74
79
|
end
|
75
80
|
|
@@ -79,7 +84,7 @@ describe Lumberjack::Device::RollingLogFile do
|
|
79
84
|
process_count.times do
|
80
85
|
outer_threads << Thread.new(&logger_test)
|
81
86
|
end
|
82
|
-
outer_threads.each{|thread| thread.
|
87
|
+
outer_threads.each{|thread| thread.value}
|
83
88
|
else
|
84
89
|
process_count.times do
|
85
90
|
Process.fork(&logger_test)
|
@@ -96,18 +101,14 @@ describe Lumberjack::Device::RollingLogFile do
|
|
96
101
|
lines.each do |line|
|
97
102
|
line.should == message
|
98
103
|
end
|
99
|
-
unless file == log_file
|
100
|
-
#File.size(file).should >= max_size
|
101
|
-
end
|
102
104
|
end
|
103
105
|
|
104
106
|
file_count.should > 3
|
105
|
-
line_count.should == process_count * thread_count * entry_count
|
106
107
|
end
|
107
108
|
|
108
109
|
it "should only keep a specified number of archived log files" do
|
109
110
|
log_file = File.join(tmp_dir, "test_5.log")
|
110
|
-
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :keep => 2, :buffer_size => 32767)
|
111
|
+
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :keep => 2, :buffer_size => 32767, :min_roll_check => 0)
|
111
112
|
expect(device).to receive(:roll_file?).and_return(false, true, true, true)
|
112
113
|
expect(device).to receive(:archive_file_suffix).and_return("delete", "another", "keep")
|
113
114
|
t = Time.now
|
@@ -129,7 +130,7 @@ describe Lumberjack::Device::RollingLogFile do
|
|
129
130
|
let(:log_file) { File.join(tmp_dir, "test_6.log") }
|
130
131
|
|
131
132
|
let(:device) do
|
132
|
-
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :keep => 2, :buffer_size => 32767)
|
133
|
+
device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :keep => 2, :buffer_size => 32767, :min_roll_check => 0)
|
133
134
|
device.stub(:roll_file?).and_return(true)
|
134
135
|
device.stub(:archive_file_suffix => "rolled")
|
135
136
|
device
|
@@ -9,10 +9,14 @@ describe Lumberjack::Device::SizeRollingLogFile do
|
|
9
9
|
after :all do
|
10
10
|
delete_tmp_dir
|
11
11
|
end
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
delete_tmp_files
|
15
|
+
end
|
12
16
|
|
13
17
|
it "should roll a file when it gets to a specified size" do
|
14
18
|
log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
|
15
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => 40, :template => ":message")
|
19
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => 40, :template => ":message", :min_roll_check => 0)
|
16
20
|
logger = Lumberjack::Logger.new(device, :buffer_size => 2)
|
17
21
|
4.times do |i|
|
18
22
|
logger.error("test message #{i + 1}")
|
@@ -26,19 +30,19 @@ describe Lumberjack::Device::SizeRollingLogFile do
|
|
26
30
|
|
27
31
|
it "should be able to specify the max size in kilobytes" do
|
28
32
|
log_file = File.join(tmp_dir, "b#{rand(1000000000)}.log")
|
29
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "32K")
|
33
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "32K", :min_roll_check => 0)
|
30
34
|
device.max_size.should == 32768
|
31
35
|
end
|
32
36
|
|
33
37
|
it "should be able to specify the max size in megabytes" do
|
34
38
|
log_file = File.join(tmp_dir, "c#{rand(1000000000)}.log")
|
35
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M")
|
39
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M", :min_roll_check => 0)
|
36
40
|
device.max_size.should == 104_857_600
|
37
41
|
end
|
38
42
|
|
39
43
|
it "should be able to specify the max size in gigabytes" do
|
40
44
|
log_file = File.join(tmp_dir, "d#{rand(1000000000)}.log")
|
41
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "1G")
|
45
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "1G", :min_roll_check => 0)
|
42
46
|
device.max_size.should == 1_073_741_824
|
43
47
|
end
|
44
48
|
|
@@ -47,7 +51,7 @@ describe Lumberjack::Device::SizeRollingLogFile do
|
|
47
51
|
(3..11).each do |i|
|
48
52
|
File.open("#{log_file}.#{i}", 'w'){|f| f.write(i.to_s)}
|
49
53
|
end
|
50
|
-
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M")
|
54
|
+
device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M", :min_roll_check => 0)
|
51
55
|
device.archive_file_suffix.should == "12"
|
52
56
|
end
|
53
57
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lumberjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -91,10 +91,13 @@ files:
|
|
91
91
|
- spec/severity_spec.rb
|
92
92
|
- spec/spec_helper.rb
|
93
93
|
- spec/template_spec.rb
|
94
|
-
homepage:
|
94
|
+
homepage: https://github.com/bdurand/lumberjack
|
95
95
|
licenses:
|
96
96
|
- MIT
|
97
|
-
metadata:
|
97
|
+
metadata:
|
98
|
+
homepage_uri: https://github.com/bdurand/lumberjack
|
99
|
+
changelog_uri: https://github.com/bdurand/lumberjack/blob/master/CHANGELOG.md
|
100
|
+
source_code_uri: https://github.com/bdurand/lumberjack
|
98
101
|
post_install_message:
|
99
102
|
rdoc_options: []
|
100
103
|
require_paths:
|
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
114
|
version: '0'
|
112
115
|
requirements: []
|
113
116
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
117
|
+
rubygems_version: 2.5.2.2
|
115
118
|
signing_key:
|
116
119
|
specification_version: 4
|
117
120
|
summary: A simple, powerful, and very fast logging utility that can be a drop in replacement
|