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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9c87ea941460683699c83e03f4b9b0fda5bcf92
4
- data.tar.gz: c4a9af57b579144b798d47ef6ff19a632050dc25
3
+ metadata.gz: aafe117d91082b575618e962e3d66a0b6d3c81b4
4
+ data.tar.gz: a4d32d48a82b15e8d67e0e00ab3b3637a63b7e99
5
5
  SHA512:
6
- metadata.gz: aab631be08c9ef9a55c755c42268ba4cc68e0f0aa27d625d43f534c649e9c9c6ce5d270a336984484993c6c9211f7e32f35438d9f01201c6024d142cbbf838af
7
- data.tar.gz: 53db84229562c9d90931e9feda302887e13d930d746bb92d2d18a7e4d7029ad7e21205fa82ae35e2e2f8a0247557cb0e06a87f58ea3d7c573e665c13395a2eae
6
+ metadata.gz: 33d8f2e2e386edad724394264f76c33c17e3df6d9dd394b3444a7abebe12d5e93d3ce8a88726e8b67fcfb2c279615741a9e55b9112d5ec45e50e0c139f481a36
7
+ data.tar.gz: 129825a3150dad02aecde16130974c2add346fe27d6455e0ea22d6616d6e766306af8c7123ef10ec7e51ca81f06e7a6f1d0cd573abd7566f07b1b15efeed415a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.12
1
+ 1.0.13
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  require 'rbconfig'
2
4
  require 'time'
3
5
  require 'thread'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  # This is an abstract class for logging devices. Subclasses must implement the +write+ method and
3
5
  # may implement the +close+ and +flush+ methods if applicable.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  require 'date'
2
4
 
3
5
  module Lumberjack
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  require 'fileutils'
2
4
 
3
5
  module Lumberjack
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  require 'date'
2
4
 
3
5
  module Lumberjack
@@ -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
- STDERR.write("Failed to roll file #{path}: #{e.inspect}\n#{e.backtrace.join("\n")}\n")
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
- path_inode = File.lstat(path).ino rescue nil
64
- if path_inode != @file_inode
65
- @file_inode = path_inode
66
- reopen_file
67
- else
68
- roll_file! if roll_file?
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
- self.stream = File.open(path, 'a', encoding: EXTERNAL_ENCODING)
77
- stream.sync = true
78
- @file_inode = stream.lstat.ino rescue nil
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 is a log device that appends entries to a file and rolls the file when it reaches a specified
@@ -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.encode("UTF-8".freeze, invalid: :replace, undef: :replace)
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 join(delimiter)
31
- @values.join(delimiter)
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
- @lock.synchronize do
81
- @buffer << string
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
- unless @buffer.empty?
97
- out = @buffer.join(Lumberjack::LINE_SEPARATOR) << Lumberjack::LINE_SEPARATOR
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
- stream.flush
101
- rescue => e
102
- $stderr.write("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
103
- $stderr.write(out)
104
- $stderr.flush
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
- @buffer.clear
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  # This class controls the conversion of log entry messages into strings. This allows you
3
5
  # to log any object you want and have the logging system worry about converting it into a string.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  class Formatter
3
5
  # Format an exception including the backtrace.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  class Formatter
3
5
  # Format an object by calling +inspect+ on it.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  require 'pp'
2
4
  require 'stringio'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  class Formatter
3
5
  # Format an object by calling +to_s+ on it.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  # An entry in a log is a data structure that captures the log message as well as
3
5
  # information about the system that logged the message.
@@ -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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  module Rack
3
5
  require File.expand_path("../rack/unit_of_work.rb", __FILE__)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  module Rack
3
5
  # Support for using the Rails ActionDispatch request id in the log.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  module Rack
3
5
  class UnitOfWork
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  # The standard severity levels for logging messages.
3
5
  module Severity
@@ -1,3 +1,5 @@
1
+ # frozen_string_literals: true
2
+
1
3
  module Lumberjack
2
4
  # A template converts entries to strings. Templates can contain the following place holders to
3
5
  # reference log entry values:
@@ -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,6 +11,10 @@ describe Lumberjack::Device::LogFile do
11
11
  delete_tmp_dir
12
12
  end
13
13
 
14
+ before :each do
15
+ delete_tmp_files
16
+ end
17
+
14
18
  it "should append to a file" do
15
19
  log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
16
20
  File.open(log_file, 'w') do |f|
@@ -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.join}
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.join}
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
 
@@ -23,4 +23,10 @@ end
23
23
 
24
24
  def delete_tmp_dir
25
25
  FileUtils.rm_r(tmp_dir)
26
- end
26
+ end
27
+
28
+ def delete_tmp_files
29
+ Dir.glob(File.join(tmp_dir, "*")) do |file|
30
+ File.delete(file)
31
+ end
32
+ end
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.12
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: 2017-05-11 00:00:00.000000000 Z
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: http://github.com/bdurand/lumberjack
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.4.5
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