lumberjack_aziz_light 1.0.5

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/MIT_LICENSE +20 -0
  3. data/README.rdoc +100 -0
  4. data/Rakefile +40 -0
  5. data/VERSION +1 -0
  6. data/lib/lumberjack/device/date_rolling_log_file.rb +58 -0
  7. data/lib/lumberjack/device/log_file.rb +18 -0
  8. data/lib/lumberjack/device/null.rb +15 -0
  9. data/lib/lumberjack/device/rolling_log_file.rb +110 -0
  10. data/lib/lumberjack/device/size_rolling_log_file.rb +60 -0
  11. data/lib/lumberjack/device/writer.rb +129 -0
  12. data/lib/lumberjack/device.rb +26 -0
  13. data/lib/lumberjack/formatter/exception_formatter.rb +12 -0
  14. data/lib/lumberjack/formatter/inspect_formatter.rb +10 -0
  15. data/lib/lumberjack/formatter/pretty_print_formatter.rb +23 -0
  16. data/lib/lumberjack/formatter/string_formatter.rb +10 -0
  17. data/lib/lumberjack/formatter.rb +76 -0
  18. data/lib/lumberjack/log_entry.rb +36 -0
  19. data/lib/lumberjack/logger.rb +302 -0
  20. data/lib/lumberjack/rack/unit_of_work.rb +15 -0
  21. data/lib/lumberjack/rack.rb +5 -0
  22. data/lib/lumberjack/severity.rb +23 -0
  23. data/lib/lumberjack/template.rb +71 -0
  24. data/lib/lumberjack.rb +42 -0
  25. data/spec/device/date_rolling_log_file_spec.rb +66 -0
  26. data/spec/device/log_file_spec.rb +26 -0
  27. data/spec/device/null_spec.rb +12 -0
  28. data/spec/device/rolling_log_file_spec.rb +129 -0
  29. data/spec/device/size_rolling_log_file_spec.rb +54 -0
  30. data/spec/device/writer_spec.rb +118 -0
  31. data/spec/formatter/exception_formatter_spec.rb +20 -0
  32. data/spec/formatter/inspect_formatter_spec.rb +13 -0
  33. data/spec/formatter/pretty_print_formatter_spec.rb +14 -0
  34. data/spec/formatter/string_formatter_spec.rb +12 -0
  35. data/spec/formatter_spec.rb +45 -0
  36. data/spec/log_entry_spec.rb +69 -0
  37. data/spec/logger_spec.rb +390 -0
  38. data/spec/lumberjack_spec.rb +29 -0
  39. data/spec/rack/unit_of_work_spec.rb +26 -0
  40. data/spec/severity_spec.rb +23 -0
  41. data/spec/spec_helper.rb +16 -0
  42. data/spec/template_spec.rb +34 -0
  43. metadata +92 -0
@@ -0,0 +1,15 @@
1
+ module Lumberjack
2
+ module Rack
3
+ class UnitOfWork
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Lumberjack.unit_of_work do
10
+ @app.call(env)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Lumberjack
2
+ module Rack
3
+ autoload :UnitOfWork, File.expand_path("../rack/unit_of_work.rb", __FILE__)
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module Lumberjack
2
+ # The standard severity levels for logging messages.
3
+ module Severity
4
+ UNKNOWN = 5
5
+ FATAL = 4
6
+ ERROR = 3
7
+ WARN = 2
8
+ INFO = 1
9
+ DEBUG = 0
10
+
11
+ SEVERITY_LABELS = %w(DEBUG INFO WARN ERROR FATAL UNKNOWN).freeze
12
+
13
+ class << self
14
+ def level_to_label(severity)
15
+ SEVERITY_LABELS[severity] || SEVERITY_LABELS.last
16
+ end
17
+
18
+ def label_to_level(label)
19
+ SEVERITY_LABELS.index(label.to_s.upcase) || UNKNOWN
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,71 @@
1
+ module Lumberjack
2
+ # A template converts entries to strings. Templates can contain the following place holders to
3
+ # reference log entry values:
4
+ #
5
+ # * <tt>:time</tt>
6
+ # * <tt>:severity</tt>
7
+ # * <tt>:progname</tt>
8
+ # * <tt>:unit_of_work_id</tt>
9
+ # * <tt>:message</tt>
10
+ class Template
11
+ TEMPLATE_ARGUMENT_ORDER = %w(:time :severity :progname :pid :unit_of_work_id :message).freeze
12
+ DEFAULT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S."
13
+ MILLISECOND_FORMAT = "%03d"
14
+ MICROSECOND_FORMAT = "%06d"
15
+
16
+ # Create a new template from the markup. The +first_line+ argument is used to format only the first
17
+ # line of a message. Additional lines will be added to the message unformatted. If you wish to format
18
+ # the additional lines, use the <tt>:additional_lines</tt> options to specify a template. Note that you'll need
19
+ # to provide the line separator character in this template if you want to keep the message on multiple lines.
20
+ #
21
+ # The time will be formatted as YYYY-MM-DDTHH:MM:SSS.SSS by default. If you wish to change the format, you
22
+ # can specify the <tt>:time_format</tt> option which can be either a time format template as documented in
23
+ # +Time#strftime+ or the values +:milliseconds+ or +:microseconds+ to use the standard format with the
24
+ # specified precision.
25
+ #
26
+ # Messages will have white space stripped from both ends.
27
+ def initialize(first_line, options = {})
28
+ @first_line_template = compile(first_line)
29
+ additional_lines = options[:additional_lines] || "#{Lumberjack::LINE_SEPARATOR}:message"
30
+ @additional_line_template = compile(additional_lines)
31
+ # Formatting the time is relatively expensive, so only do it if it will be used
32
+ @template_include_time = first_line.include?(":time") || additional_lines.include?(":time")
33
+ @time_format = options[:time_format] || :milliseconds
34
+ end
35
+
36
+ # Convert an entry into a string using the template.
37
+ def call(entry)
38
+ lines = entry.message.strip.split(Lumberjack::LINE_SEPARATOR)
39
+ formatted_time = format_time(entry.time) if @template_include_time
40
+ message = @first_line_template % [formatted_time, entry.severity_label, entry.progname, entry.pid, entry.unit_of_work_id, lines.shift]
41
+ lines.each do |line|
42
+ message << @additional_line_template % [formatted_time, entry.severity_label, entry.progname, entry.pid, entry.unit_of_work_id, line]
43
+ end
44
+ message
45
+ end
46
+
47
+ private
48
+
49
+ def format_time(time) #:nodoc:
50
+ if @time_format.is_a?(String)
51
+ time.strftime(@time_format)
52
+ elsif @time_format == :milliseconds
53
+ time.strftime(DEFAULT_TIME_FORMAT) << MILLISECOND_FORMAT % (time.usec / 1000.0).round
54
+ else
55
+ time.strftime(DEFAULT_TIME_FORMAT) << MICROSECOND_FORMAT % time.usec
56
+ end
57
+ end
58
+
59
+ # Compile the template string into a value that can be used with sprintf.
60
+ def compile(template) #:nodoc:
61
+ template.gsub(/:[a-z0-9_]+/) do |match|
62
+ position = TEMPLATE_ARGUMENT_ORDER.index(match)
63
+ if position
64
+ "%#{position + 1}$s"
65
+ else
66
+ match
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/lumberjack.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'rbconfig'
2
+ require 'time'
3
+ require 'thread'
4
+
5
+ module Lumberjack
6
+ autoload :Device, File.expand_path("../lumberjack/device.rb", __FILE__)
7
+ autoload :Formatter, File.expand_path("../lumberjack/formatter.rb", __FILE__)
8
+ autoload :LogEntry, File.expand_path("../lumberjack/log_entry.rb", __FILE__)
9
+ autoload :Logger, File.expand_path("../lumberjack/logger.rb", __FILE__)
10
+ autoload :Rack, File.expand_path("../lumberjack/rack.rb", __FILE__)
11
+ autoload :Severity, File.expand_path("../lumberjack/severity.rb", __FILE__)
12
+ autoload :Template, File.expand_path("../lumberjack/template.rb", __FILE__)
13
+
14
+ LINE_SEPARATOR = (RbConfig::CONFIG['host_os'].match(/mswin/i) ? "\r\n" : "\n")
15
+
16
+ class << self
17
+ # Define a unit of work within a block. Within the block supplied to this
18
+ # method, calling +unit_of_work_id+ will return the same value that can
19
+ # This can then be used for tying together log entries.
20
+ #
21
+ # You can specify the id for the unit of work if desired. If you don't supply
22
+ # it, a 12 digit hexidecimal number will be automatically generated for you.
23
+ #
24
+ # For the common use case of treating a single web request as a unit of work, see the
25
+ # Lumberjack::Rack::UnitOfWork class.
26
+ def unit_of_work(id = nil)
27
+ save_val = Thread.current[:lumberjack_logger_unit_of_work_id]
28
+ id ||= rand(0xFFFFFFFFFFFF).to_s(16).rjust(12, '0').upcase
29
+ Thread.current[:lumberjack_logger_unit_of_work_id] = id
30
+ begin
31
+ return yield
32
+ ensure
33
+ Thread.current[:lumberjack_logger_unit_of_work_id] = save_val
34
+ end
35
+ end
36
+
37
+ # Get the UniqueIdentifier for the current unit of work.
38
+ def unit_of_work_id
39
+ Thread.current[:lumberjack_logger_unit_of_work_id]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::Device::DateRollingLogFile do
4
+
5
+ before :all do
6
+ create_tmp_dir
7
+ end
8
+
9
+ after :all do
10
+ delete_tmp_dir
11
+ end
12
+
13
+ let(:one_day){ 60 * 60 * 24 }
14
+
15
+ it "should roll the file daily" do
16
+ today = Date.today
17
+ now = Time.now
18
+ log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
19
+ device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :daily, :template => ":message")
20
+ logger = Lumberjack::Logger.new(device, :buffer_size => 2)
21
+ logger.error("test day one")
22
+ logger.flush
23
+ Time.stub!(:now).and_return(now + one_day)
24
+ Date.stub!(:today).and_return(today + 1)
25
+ logger.error("test day two")
26
+ logger.close
27
+
28
+ File.read("#{log_file}.#{today.strftime('%Y-%m-%d')}").should == "test day one#{Lumberjack::LINE_SEPARATOR}"
29
+ File.read(log_file).should == "test day two#{Lumberjack::LINE_SEPARATOR}"
30
+ end
31
+
32
+ it "should roll the file weekly" do
33
+ today = Date.today
34
+ now = Time.now
35
+ log_file = File.join(tmp_dir, "b#{rand(1000000000)}.log")
36
+ device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :weekly, :template => ":message")
37
+ logger = Lumberjack::Logger.new(device, :buffer_size => 2)
38
+ logger.error("test week one")
39
+ logger.flush
40
+ Time.stub!(:now).and_return(now + (7 * one_day))
41
+ Date.stub!(:today).and_return(today + 7)
42
+ logger.error("test week two")
43
+ logger.close
44
+
45
+ File.read("#{log_file}.#{today.strftime('week-of-%Y-%m-%d')}").should == "test week one#{Lumberjack::LINE_SEPARATOR}"
46
+ File.read(log_file).should == "test week two#{Lumberjack::LINE_SEPARATOR}"
47
+ end
48
+
49
+ it "should roll the file monthly" do
50
+ today = Date.today
51
+ now = Time.now
52
+ log_file = File.join(tmp_dir, "c#{rand(1000000000)}.log")
53
+ device = Lumberjack::Device::DateRollingLogFile.new(log_file, :roll => :monthly, :template => ":message")
54
+ logger = Lumberjack::Logger.new(device, :buffer_size => 2)
55
+ logger.error("test month one")
56
+ logger.flush
57
+ Time.stub!(:now).and_return(now + (31 * one_day))
58
+ Date.stub!(:today).and_return(today + 31)
59
+ logger.error("test month two")
60
+ logger.close
61
+
62
+ File.read("#{log_file}.#{today.strftime('%Y-%m')}").should == "test month one#{Lumberjack::LINE_SEPARATOR}"
63
+ File.read(log_file).should == "test month two#{Lumberjack::LINE_SEPARATOR}"
64
+ end
65
+
66
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::Device::LogFile do
4
+
5
+ before :all do
6
+ create_tmp_dir
7
+ end
8
+
9
+ after :all do
10
+ delete_tmp_dir
11
+ end
12
+
13
+ it "should append to a file" do
14
+ log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
15
+ File.open(log_file, 'w') do |f|
16
+ f.puts("Existing contents")
17
+ end
18
+
19
+ device = Lumberjack::Device::LogFile.new(log_file, :template => ":message")
20
+ device.write(Lumberjack::LogEntry.new(Time.now, 1, "New log entry", nil, $$, nil))
21
+ device.close
22
+
23
+ File.read(log_file).should == "Existing contents\nNew log entry#{Lumberjack::LINE_SEPARATOR}"
24
+ end
25
+
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::Device::Null do
4
+
5
+ it "should not generate any output" do
6
+ device = Lumberjack::Device::Null.new
7
+ device.write(Lumberjack::LogEntry.new(Time.now, 1, "New log entry", nil, $$, nil))
8
+ device.flush
9
+ device.close
10
+ end
11
+
12
+ end
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::Device::RollingLogFile do
4
+
5
+ before :all do
6
+ Lumberjack::Device::SizeRollingLogFile #needed by jruby
7
+ create_tmp_dir
8
+ end
9
+
10
+ after :all do
11
+ delete_tmp_dir
12
+ end
13
+
14
+ let(:entry){ Lumberjack::LogEntry.new(Time.now, 1, "New log entry", nil, $$, nil) }
15
+
16
+ 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)
18
+ device.write(entry)
19
+ device.should_receive(:roll_file?).twice.and_return(false)
20
+ device.flush
21
+ device.close
22
+ end
23
+
24
+ it "should roll the file by archiving the existing file and opening a new stream and calling after_roll" do
25
+ log_file = File.join(tmp_dir, "test_2.log")
26
+ device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message", :buffer_size => 32767)
27
+ device.should_receive(:roll_file?).and_return(false, true)
28
+ device.should_receive(:after_roll)
29
+ device.stub!(:archive_file_suffix).and_return("rolled")
30
+ device.write(entry)
31
+ device.flush
32
+ device.write(Lumberjack::LogEntry.new(Time.now, 1, "Another log entry", nil, $$, nil))
33
+ device.close
34
+ File.read("#{log_file}.rolled").should == "New log entry#{Lumberjack::LINE_SEPARATOR}"
35
+ File.read(log_file).should == "Another log entry#{Lumberjack::LINE_SEPARATOR}"
36
+ end
37
+
38
+ it "should reopen the file if the stream inode doesn't match the file path inode" do
39
+ log_file = File.join(tmp_dir, "test_3.log")
40
+ device = Lumberjack::Device::RollingLogFile.new(log_file, :template => ":message")
41
+ device.stub!(:roll_file?).and_return(false)
42
+ device.write(entry)
43
+ device.flush
44
+ File.rename(log_file, "#{log_file}.rolled")
45
+ device.flush
46
+ device.write(Lumberjack::LogEntry.new(Time.now, 1, "Another log entry", nil, $$, nil))
47
+ device.close
48
+ File.read("#{log_file}.rolled").should == "New log entry#{Lumberjack::LINE_SEPARATOR}"
49
+ File.read(log_file).should == "Another log entry#{Lumberjack::LINE_SEPARATOR}"
50
+ end
51
+
52
+ it "should roll the file properly with multiple thread and processes using it" do
53
+ log_file = File.join(tmp_dir, "test_4.log")
54
+ process_count = 8
55
+ thread_count = 4
56
+ entry_count = 400
57
+ max_size = 128
58
+ severity = Lumberjack::Severity::INFO
59
+ message = "This is a test message that is written to the log file to indicate what the state of the application is."
60
+
61
+ logger_test = lambda do
62
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => max_size, :template => ":message", :buffer_size => 32767)
63
+ threads = []
64
+ thread_count.times do
65
+ threads << Thread.new do
66
+ entry_count.times do |i|
67
+ device.write(Lumberjack::LogEntry.new(Time.now, severity, message, "test", $$, nil))
68
+ device.flush if i % 10 == 0
69
+ end
70
+ end
71
+ end
72
+ threads.each{|thread| thread.join}
73
+ device.close
74
+ end
75
+
76
+ # Process.fork is unavailable on jruby so we need to use the java threads instead.
77
+ if RUBY_PLATFORM.match(/java/)
78
+ outer_threads = []
79
+ process_count.times do
80
+ outer_threads << Thread.new(&logger_test)
81
+ end
82
+ outer_threads.each{|thread| thread.join}
83
+ else
84
+ process_count.times do
85
+ Process.fork(&logger_test)
86
+ end
87
+ Process.waitall
88
+ end
89
+
90
+ line_count = 0
91
+ file_count = 0
92
+ Dir.glob("#{log_file}*").each do |file|
93
+ file_count += 1
94
+ lines = File.read(file).split(Lumberjack::LINE_SEPARATOR)
95
+ line_count += lines.size
96
+ lines.each do |line|
97
+ line.should == message
98
+ end
99
+ unless file == log_file
100
+ #File.size(file).should >= max_size
101
+ end
102
+ end
103
+
104
+ file_count.should > 3
105
+ line_count.should == process_count * thread_count * entry_count
106
+ end
107
+
108
+ it "should only keep a specified number of archived log files" do
109
+ 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.should_receive(:roll_file?).and_return(false, true, true, true)
112
+ device.stub!(:archive_file_suffix).and_return("delete", "another", "keep")
113
+ t = Time.now
114
+ File.should_receive(:ctime).with(log_file).any_number_of_times.and_return(t)
115
+ File.should_receive(:ctime).with("#{log_file}.delete").any_number_of_times.and_return(t + 1)
116
+ File.should_receive(:ctime).with("#{log_file}.another").any_number_of_times.and_return(t + 2)
117
+ File.should_receive(:ctime).with("#{log_file}.keep").any_number_of_times.and_return(t + 3)
118
+ device.write(entry)
119
+ device.flush
120
+ device.write(entry)
121
+ device.flush
122
+ device.write(entry)
123
+ device.flush
124
+ device.write(entry)
125
+ device.close
126
+ Dir.glob("#{log_file}*").sort.should == [log_file, "#{log_file}.another", "#{log_file}.keep"]
127
+ end
128
+
129
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lumberjack::Device::SizeRollingLogFile do
4
+
5
+ before :all do
6
+ create_tmp_dir
7
+ end
8
+
9
+ after :all do
10
+ delete_tmp_dir
11
+ end
12
+
13
+ it "should roll a file when it gets to a specified size" do
14
+ log_file = File.join(tmp_dir, "a#{rand(1000000000)}.log")
15
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => 40, :template => ":message")
16
+ logger = Lumberjack::Logger.new(device, :buffer_size => 2)
17
+ 4.times do |i|
18
+ logger.error("test message #{i + 1}")
19
+ logger.flush
20
+ end
21
+ logger.close
22
+
23
+ File.read("#{log_file}.1").split(Lumberjack::LINE_SEPARATOR).should == ["test message 1", "test message 2", "test message 3"]
24
+ File.read(log_file).should == "test message 4#{Lumberjack::LINE_SEPARATOR}"
25
+ end
26
+
27
+ it "should be able to specify the max size in kilobytes" do
28
+ log_file = File.join(tmp_dir, "b#{rand(1000000000)}.log")
29
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "32K")
30
+ device.max_size.should == 32768
31
+ end
32
+
33
+ it "should be able to specify the max size in megabytes" do
34
+ log_file = File.join(tmp_dir, "c#{rand(1000000000)}.log")
35
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M")
36
+ device.max_size.should == 104_857_600
37
+ end
38
+
39
+ it "should be able to specify the max size in gigabytes" do
40
+ log_file = File.join(tmp_dir, "d#{rand(1000000000)}.log")
41
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "1G")
42
+ device.max_size.should == 1_073_741_824
43
+ end
44
+
45
+ it "should figure out the next archive file name available" do
46
+ log_file = File.join(tmp_dir, "filename.log")
47
+ (3..11).each do |i|
48
+ File.open("#{log_file}.#{i}", 'w'){|f| f.write(i.to_s)}
49
+ end
50
+ device = Lumberjack::Device::SizeRollingLogFile.new(log_file, :max_size => "100M")
51
+ device.archive_file_suffix.should == "12"
52
+ end
53
+
54
+ end