lumberjack_aziz_light 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
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