lumberjack 1.0.0
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.
- data/MIT_LICENSE +20 -0
- data/README.rdoc +86 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/lib/lumberjack.rb +39 -0
- data/lib/lumberjack/device.rb +26 -0
- data/lib/lumberjack/device/date_rolling_log_file.rb +58 -0
- data/lib/lumberjack/device/log_file.rb +18 -0
- data/lib/lumberjack/device/null.rb +15 -0
- data/lib/lumberjack/device/rolling_log_file.rb +109 -0
- data/lib/lumberjack/device/size_rolling_log_file.rb +58 -0
- data/lib/lumberjack/device/writer.rb +119 -0
- data/lib/lumberjack/formatter.rb +76 -0
- data/lib/lumberjack/formatter/exception_formatter.rb +12 -0
- data/lib/lumberjack/formatter/inspect_formatter.rb +10 -0
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +23 -0
- data/lib/lumberjack/formatter/string_formatter.rb +10 -0
- data/lib/lumberjack/log_entry.rb +36 -0
- data/lib/lumberjack/logger.rb +302 -0
- data/lib/lumberjack/rack.rb +5 -0
- data/lib/lumberjack/rack/unit_of_work.rb +15 -0
- data/lib/lumberjack/severity.rb +23 -0
- data/lib/lumberjack/template.rb +71 -0
- data/spec/device/date_rolling_log_file_spec.rb +66 -0
- data/spec/device/date_rolling_log_file_spec.rbc +2118 -0
- data/spec/device/log_file_spec.rb +26 -0
- data/spec/device/log_file_spec.rbc +727 -0
- data/spec/device/null_spec.rb +12 -0
- data/spec/device/null_spec.rbc +362 -0
- data/spec/device/rolling_log_file_spec.rb +117 -0
- data/spec/device/rolling_log_file_spec.rbc +2894 -0
- data/spec/device/size_rolling_log_file_spec.rb +54 -0
- data/spec/device/size_rolling_log_file_spec.rbc +1961 -0
- data/spec/device/stream_spec.rbc +3310 -0
- data/spec/device/writer_spec.rb +118 -0
- data/spec/entry_spec.rbc +2333 -0
- data/spec/formatter/exception_formatter_spec.rb +20 -0
- data/spec/formatter/exception_formatter_spec.rbc +620 -0
- data/spec/formatter/inspect_formatter_spec.rb +13 -0
- data/spec/formatter/inspect_formatter_spec.rbc +360 -0
- data/spec/formatter/pretty_print_formatter_spec.rb +14 -0
- data/spec/formatter/pretty_print_formatter_spec.rbc +380 -0
- data/spec/formatter/string_formatter_spec.rb +12 -0
- data/spec/formatter/string_formatter_spec.rbc +314 -0
- data/spec/formatter_spec.rb +45 -0
- data/spec/formatter_spec.rbc +1431 -0
- data/spec/log_entry_spec.rb +69 -0
- data/spec/logger_spec.rb +390 -0
- data/spec/logger_spec.rbc +10043 -0
- data/spec/lumberjack_spec.rb +22 -0
- data/spec/lumberjack_spec.rbc +523 -0
- data/spec/rack/unit_of_work_spec.rb +26 -0
- data/spec/rack/unit_of_work_spec.rbc +697 -0
- data/spec/severity_spec.rb +23 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/spec_helper.rbc +391 -0
- data/spec/template_spec.rb +34 -0
- data/spec/template_spec.rbc +1563 -0
- data/spec/unique_identifier_spec.rbc +329 -0
- metadata +128 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
module Lumberjack
|
2
|
+
class Device
|
3
|
+
# This logging device writes log entries as strings to an IO stream.
|
4
|
+
class Writer < Device
|
5
|
+
DEFAULT_FIRST_LINE_TEMPLATE = "[:time :severity :progname(:pid) #:unit_of_work_id] :message".freeze
|
6
|
+
DEFAULT_ADDITIONAL_LINES_TEMPLATE = "#{Lumberjack::LINE_SEPARATOR}> [#:unit_of_work_id] :message".freeze
|
7
|
+
|
8
|
+
# The size of the internal buffer. Defaults to 32K.
|
9
|
+
attr_accessor :buffer_size
|
10
|
+
|
11
|
+
# Internal buffer to batch writes to the stream.
|
12
|
+
class Buffer # :nodoc:
|
13
|
+
attr_reader :size
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@values = []
|
17
|
+
@size = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def <<(string)
|
21
|
+
@values << string
|
22
|
+
@size += string.size
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty?
|
26
|
+
@values.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def join(delimiter)
|
30
|
+
@values.join(delimiter)
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear
|
34
|
+
@values = []
|
35
|
+
@size = 0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a new device to write log entries to a stream. Entries are converted to strings
|
40
|
+
# using a Template. The template can be specified using the <tt>:template</tt> option. This can
|
41
|
+
# either be a Proc or a string that will compile into a Template object.
|
42
|
+
#
|
43
|
+
# If the template is a Proc, it should accept an LogEntry as its only argument and output a string.
|
44
|
+
#
|
45
|
+
# If the template is a template string, it will be used to create a Template. The
|
46
|
+
# <tt>:additional_lines</tt> and <tt>:time_format</tt> options will be passed through to the
|
47
|
+
# Template constuctor.
|
48
|
+
#
|
49
|
+
# The default template is <tt>"[:time :severity :progname(:pid) #:unit_of_work_id] :message"</tt>
|
50
|
+
# with additional lines formatted as <tt>"\n [#:unit_of_work_id] :message"</tt>. The unit of
|
51
|
+
# work id will only appear if it is present.
|
52
|
+
def initialize(stream, options = {})
|
53
|
+
@lock = Mutex.new
|
54
|
+
@stream = stream
|
55
|
+
@stream.sync = true if @stream.respond_to?(:sync=)
|
56
|
+
@buffer = Buffer.new
|
57
|
+
@buffer_size = (options[:buffer_size] || 32 * 1024)
|
58
|
+
template = (options[:template] || DEFAULT_FIRST_LINE_TEMPLATE)
|
59
|
+
if template.respond_to?(:call)
|
60
|
+
@template = template
|
61
|
+
else
|
62
|
+
additional_lines = (options[:additional_lines] || DEFAULT_ADDITIONAL_LINES_TEMPLATE)
|
63
|
+
@template = Template.new(template, :additional_lines => additional_lines, :time_format => options[:time_format])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Write an entry to the stream. The entry will be converted into a string using the defined template.
|
68
|
+
def write(entry)
|
69
|
+
string = @template.call(entry)
|
70
|
+
@lock.synchronize do
|
71
|
+
@buffer << string
|
72
|
+
end
|
73
|
+
flush if @buffer.size >= buffer_size
|
74
|
+
end
|
75
|
+
|
76
|
+
# Close the underlying stream.
|
77
|
+
def close
|
78
|
+
flush
|
79
|
+
stream.close
|
80
|
+
end
|
81
|
+
|
82
|
+
# Flush the underlying stream.
|
83
|
+
def flush
|
84
|
+
@lock.synchronize do
|
85
|
+
before_flush
|
86
|
+
unless @buffer.empty?
|
87
|
+
out = @buffer.join(Lumberjack::LINE_SEPARATOR) << Lumberjack::LINE_SEPARATOR
|
88
|
+
begin
|
89
|
+
stream.write(out)
|
90
|
+
stream.flush
|
91
|
+
rescue => e
|
92
|
+
$stderr.write("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
|
93
|
+
$stderr.write(out)
|
94
|
+
$stderr.flush
|
95
|
+
end
|
96
|
+
@buffer.clear
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
# Callback method that will be executed before data is written to the stream. Subclasses
|
104
|
+
# can override this method if needed.
|
105
|
+
def before_flush
|
106
|
+
end
|
107
|
+
|
108
|
+
# Set the underlying stream.
|
109
|
+
def stream=(stream)
|
110
|
+
@stream = stream
|
111
|
+
end
|
112
|
+
|
113
|
+
# Get the underlying stream.
|
114
|
+
def stream
|
115
|
+
@stream
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Lumberjack
|
2
|
+
# This class controls the conversion of log entry messages into strings. This allows you
|
3
|
+
# to log any object you want and have the logging system worry about converting it into a string.
|
4
|
+
#
|
5
|
+
# Formats are added to a Formatter by associating them with a class using the +add+ method. Formats
|
6
|
+
# are any object that responds to the +call+ method.
|
7
|
+
#
|
8
|
+
# By default, all object will be converted to strings using their inspect method except for Strings
|
9
|
+
# and Exceptions. Strings are not converted and Exceptions are converted using the ExceptionFormatter.
|
10
|
+
class Formatter
|
11
|
+
autoload :ExceptionFormatter, File.expand_path("../formatter/exception_formatter.rb", __FILE__)
|
12
|
+
autoload :InspectFormatter, File.expand_path("../formatter/inspect_formatter.rb", __FILE__)
|
13
|
+
autoload :PrettyPrintFormatter, File.expand_path("../formatter/pretty_print_formatter.rb", __FILE__)
|
14
|
+
autoload :StringFormatter, File.expand_path("../formatter/string_formatter.rb", __FILE__)
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@class_formatters = {}
|
18
|
+
@default_formatter = InspectFormatter.new
|
19
|
+
add(Object, @default_formatter)
|
20
|
+
add(String, :string)
|
21
|
+
add(Exception, :exception)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add a formatter for a class. The formatter can be specified as either an object
|
25
|
+
# that responds to the +call+ method or as a symbol representing one of the predefined
|
26
|
+
# formatters, or as a block to the method call.
|
27
|
+
#
|
28
|
+
# The predefined formatters are: <tt>:inspect</tt>, <tt>:string</tt>, <tt>:exception</tt>, and <tt>:pretty_print</tt>.
|
29
|
+
#
|
30
|
+
# === Examples
|
31
|
+
#
|
32
|
+
# # Use a predefined formatter
|
33
|
+
# formatter.add(MyClass, :pretty_print)
|
34
|
+
#
|
35
|
+
# # Pass in a formatter object
|
36
|
+
# formatter.add(MyClass, Lumberjack::Formatter::PrettyPrintFormatter.new)
|
37
|
+
#
|
38
|
+
# # Use a block
|
39
|
+
# formatter.add(MyClass){|obj| obj.humanize}
|
40
|
+
#
|
41
|
+
# # Add statements can be chained together
|
42
|
+
# formatter.add(MyClass, :pretty_print).add(YourClass){|obj| obj.humanize}
|
43
|
+
def add(klass, formatter = nil, &block)
|
44
|
+
formatter ||= block
|
45
|
+
if formatter.is_a?(Symbol)
|
46
|
+
formatter_class_name = "#{formatter.to_s.gsub(/(^|_)([a-z])/){|m| $~[2].upcase}}Formatter"
|
47
|
+
formatter = Formatter.const_get(formatter_class_name).new
|
48
|
+
end
|
49
|
+
@class_formatters[klass] = formatter
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Remove the formatter associated with a class. Remove statements can be chained together.
|
54
|
+
def remove(klass)
|
55
|
+
@class_formatters.delete(klass)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Format a message object as a string.
|
60
|
+
def format(message)
|
61
|
+
formatter_for(message.class).call(message)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Find the formatter for a class by looking it up using the class hierarchy.
|
67
|
+
def formatter_for(klass) #:nodoc:
|
68
|
+
while klass != nil do
|
69
|
+
formatter = @class_formatters[klass]
|
70
|
+
return formatter if formatter
|
71
|
+
klass = klass.superclass
|
72
|
+
end
|
73
|
+
@default_formatter
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Lumberjack
|
2
|
+
class Formatter
|
3
|
+
# Format an exception including the backtrace.
|
4
|
+
class ExceptionFormatter
|
5
|
+
def call(exception)
|
6
|
+
message = "#{exception.class.name}: #{exception.message}"
|
7
|
+
message << "#{Lumberjack::LINE_SEPARATOR} #{exception.backtrace.join("#{Lumberjack::LINE_SEPARATOR} ")}" if exception.backtrace
|
8
|
+
message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Lumberjack
|
5
|
+
class Formatter
|
6
|
+
# Format an object with it's pretty print method.
|
7
|
+
class PrettyPrintFormatter
|
8
|
+
attr_accessor :width
|
9
|
+
|
10
|
+
# Create a new formatter. The maximum width of the message can be specified with the width
|
11
|
+
# parameter (defaults to 79 characters).
|
12
|
+
def initialize(width = 79)
|
13
|
+
@width = width
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(obj)
|
17
|
+
s = StringIO.new
|
18
|
+
PP.pp(obj, s)
|
19
|
+
s.string.chomp
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Lumberjack
|
2
|
+
# An entry in a log is a data structure that captures the log message as well as
|
3
|
+
# information about the system that logged the message.
|
4
|
+
class LogEntry
|
5
|
+
attr_accessor :time, :message, :severity, :progname, :pid, :unit_of_work_id
|
6
|
+
|
7
|
+
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S".freeze
|
8
|
+
|
9
|
+
def initialize(time, severity, message, progname, pid, unit_of_work_id)
|
10
|
+
@time = time
|
11
|
+
@severity = (severity.is_a?(Fixnum) ? severity : Severity.label_to_level(severity))
|
12
|
+
@message = message
|
13
|
+
@progname = progname
|
14
|
+
@pid = pid
|
15
|
+
@unit_of_work_id = unit_of_work_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def severity_label
|
19
|
+
Severity.level_to_label(severity)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
buf = "[#{time.strftime(TIME_FORMAT)}.#{(time.usec / 1000.0).round.to_s.rjust(3, '0')} #{severity_label} #{progname}(#{pid})"
|
24
|
+
if unit_of_work_id
|
25
|
+
buf << " #"
|
26
|
+
buf << unit_of_work_id
|
27
|
+
end
|
28
|
+
buf << "] "
|
29
|
+
buf << message
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,302 @@
|
|
1
|
+
module Lumberjack
|
2
|
+
# Logger is a thread safe logging object. It has a compatible API with the Ruby
|
3
|
+
# standard library Logger class, the Log4r gem, and ActiveSupport::BufferedLogger.
|
4
|
+
#
|
5
|
+
# === Example
|
6
|
+
#
|
7
|
+
# logger = Lumberjack::Logger.new
|
8
|
+
# logger.info("Starting processing")
|
9
|
+
# logger.debug("Processing options #{options.inspect}")
|
10
|
+
# logger.fatal("OMG the application is on fire!")
|
11
|
+
#
|
12
|
+
# Log entries are written to a logging Device if their severity meets or exceeds the log level.
|
13
|
+
#
|
14
|
+
# Devices may use buffers internally and the log entries are not guaranteed to be written until you call
|
15
|
+
# the +flush+ method. Sometimes this can result in problems when trying to track down extraordinarily
|
16
|
+
# long running sections of code since it is likely that none of the messages logged before the long
|
17
|
+
# running code will appear in the log until the entire process finishes. You can set the +:flush_seconds+
|
18
|
+
# option on the constructor to force the device to be flushed periodically. This will create a new
|
19
|
+
# monitoring thread, but its use is highly recommended.
|
20
|
+
#
|
21
|
+
# Each log entry records the log message and severity along with the time it was logged, the
|
22
|
+
# program name, process id, and unit of work id. The message will be converted to a string, but
|
23
|
+
# otherwise, it is up to the device how these values are recorded. Messages are converted to strings
|
24
|
+
# using a Formatter associated with the logger.
|
25
|
+
class Logger
|
26
|
+
include Severity
|
27
|
+
|
28
|
+
# The Formatter object used to convert messages into strings.
|
29
|
+
attr_reader :formatter
|
30
|
+
|
31
|
+
# The time that the device was last flushed.
|
32
|
+
attr_reader :last_flushed_at
|
33
|
+
|
34
|
+
# The name of the program associated with log messages.
|
35
|
+
attr_writer :progname
|
36
|
+
|
37
|
+
# The device being written to.
|
38
|
+
attr_reader :device
|
39
|
+
|
40
|
+
# Set +silencer+ to false to disable silencing the log.
|
41
|
+
attr_accessor :silencer
|
42
|
+
|
43
|
+
# Create a new logger to log to a Device.
|
44
|
+
#
|
45
|
+
# The +device+ argument can be in any one of several formats.
|
46
|
+
#
|
47
|
+
# If it is a Device object, that object will be used.
|
48
|
+
# If it has a +write+ method, it will be wrapped in a Device::Writer class.
|
49
|
+
# If it is <tt>:null</tt>, it will be a Null device that won't record any output.
|
50
|
+
# Otherwise, it will be assumed to be file path and wrapped in a Device::LogFile class.
|
51
|
+
#
|
52
|
+
# This method can take the following options:
|
53
|
+
#
|
54
|
+
# * <tt>:level</tt> - The logging level below which messages will be ignored.
|
55
|
+
# * <tt>:progname</tt> - The name of the program that will be recorded with each log entry.
|
56
|
+
# * <tt>:flush_seconds</tt> - The maximum number of seconds between flush calls.
|
57
|
+
# * <tt>:roll</tt> - If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
|
58
|
+
# * <tt>:max_size</tt> - If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
|
59
|
+
#
|
60
|
+
# All other options are passed to the device constuctor.
|
61
|
+
def initialize(device = STDOUT, options = {})
|
62
|
+
@thread_settings = {}
|
63
|
+
|
64
|
+
options = options.dup
|
65
|
+
self.level = options.delete(:level) || INFO
|
66
|
+
self.progname = options.delete(:progname)
|
67
|
+
max_flush_seconds = options.delete(:flush_seconds).to_f
|
68
|
+
|
69
|
+
@device = open_device(device, options)
|
70
|
+
@formatter = Formatter.new
|
71
|
+
@lock = Mutex.new
|
72
|
+
@last_flushed_at = Time.now
|
73
|
+
@silencer = true
|
74
|
+
|
75
|
+
create_flusher_thread(max_flush_seconds) if max_flush_seconds > 0
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get the level of severity of entries that are logged. Entries with a lower
|
79
|
+
# severity level will be ignored.
|
80
|
+
def level
|
81
|
+
thread_local_value(:lumberjack_logger_level) || @level
|
82
|
+
end
|
83
|
+
|
84
|
+
# Add a message to the log with a given severity. The message can be either
|
85
|
+
# passed in the +message+ argument or supplied with a block. This method
|
86
|
+
# is not normally called. Instead call one of the helper functions
|
87
|
+
# +fatal+, +error+, +warn+, +info+, or +debug+.
|
88
|
+
#
|
89
|
+
# The severity can be passed in either as one of the Severity constants,
|
90
|
+
# or as a Severity label.
|
91
|
+
#
|
92
|
+
# === Example
|
93
|
+
#
|
94
|
+
# logger.add(Lumberjack::Severity::ERROR, exception)
|
95
|
+
# logger.add(Lumberjack::Severity::INFO, "Request completed")
|
96
|
+
# logger.add(:warn, "Request took a long time")
|
97
|
+
# logger.add(Lumberjack::Severity::DEBUG){"Start processing with options #{options.inspect}"}
|
98
|
+
def add(severity, message = nil, progname = nil)
|
99
|
+
severity = Severity.label_to_level(severity) if severity.is_a?(String) || severity.is_a?(Symbol)
|
100
|
+
if severity && severity >= level
|
101
|
+
time = Time.now
|
102
|
+
message = yield if message.nil? && block_given?
|
103
|
+
message = @formatter.format(message)
|
104
|
+
entry = LogEntry.new(time, severity, message, progname || self.progname, $$, Lumberjack.unit_of_work_id)
|
105
|
+
begin
|
106
|
+
device.write(entry)
|
107
|
+
rescue => e
|
108
|
+
$stderr.puts("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
|
109
|
+
$stderr.puts(entry.to_s)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
alias_method :log, :add
|
116
|
+
|
117
|
+
# Flush the logging device.
|
118
|
+
def flush
|
119
|
+
device.flush
|
120
|
+
@last_flushed_at = Time.now
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
|
124
|
+
# Close the logging device.
|
125
|
+
def close
|
126
|
+
flush
|
127
|
+
@device.close if @device.respond_to?(:close)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Log a +FATAL+ message. The message can be passed in either the +message+ argument or in a block.
|
131
|
+
def fatal(message = nil, progname = nil, &block)
|
132
|
+
add(FATAL, message, progname, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Return +true+ if +FATAL+ messages are being logged.
|
136
|
+
def fatal?
|
137
|
+
level <= FATAL
|
138
|
+
end
|
139
|
+
|
140
|
+
# Log an +ERROR+ message. The message can be passed in either the +message+ argument or in a block.
|
141
|
+
def error(message = nil, progname = nil, &block)
|
142
|
+
add(ERROR, message, progname, &block)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Return +true+ if +ERROR+ messages are being logged.
|
146
|
+
def error?
|
147
|
+
level <= ERROR
|
148
|
+
end
|
149
|
+
|
150
|
+
# Log a +WARN+ message. The message can be passed in either the +message+ argument or in a block.
|
151
|
+
def warn(message = nil, progname = nil, &block)
|
152
|
+
add(WARN, message, progname, &block)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return +true+ if +WARN+ messages are being logged.
|
156
|
+
def warn?
|
157
|
+
level <= WARN
|
158
|
+
end
|
159
|
+
|
160
|
+
# Log an +INFO+ message. The message can be passed in either the +message+ argument or in a block.
|
161
|
+
def info(message = nil, progname = nil, &block)
|
162
|
+
add(INFO, message, progname, &block)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Return +true+ if +INFO+ messages are being logged.
|
166
|
+
def info?
|
167
|
+
level <= INFO
|
168
|
+
end
|
169
|
+
|
170
|
+
# Log a +DEBUG+ message. The message can be passed in either the +message+ argument or in a block.
|
171
|
+
def debug(message = nil, progname = nil, &block)
|
172
|
+
add(DEBUG, message, progname, &block)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Return +true+ if +DEBUG+ messages are being logged.
|
176
|
+
def debug?
|
177
|
+
level <= DEBUG
|
178
|
+
end
|
179
|
+
|
180
|
+
# Log a message when the severity is not known. Unknown messages will always appear in the log.
|
181
|
+
# The message can be passed in either the +message+ argument or in a block.
|
182
|
+
def unknown(message = nil, progname = nil, &block)
|
183
|
+
add(UNKNOWN, message, progname, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
alias_method :<<, :unknown
|
187
|
+
|
188
|
+
# Set the minimum level of severity of messages to log.
|
189
|
+
def level=(severity)
|
190
|
+
if severity.is_a?(Fixnum)
|
191
|
+
@level = severity
|
192
|
+
else
|
193
|
+
@level = Severity.label_to_level(severity)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Silence the logger by setting a new log level inside a block. By default, only +ERROR+ or +FATAL+
|
198
|
+
# messages will be logged.
|
199
|
+
#
|
200
|
+
# === Example
|
201
|
+
#
|
202
|
+
# logger.level = Lumberjack::Severity::INFO
|
203
|
+
# logger.silence do
|
204
|
+
# do_something # Log level inside the block is +ERROR+
|
205
|
+
# end
|
206
|
+
def silence(temporary_level = ERROR, &block)
|
207
|
+
if silencer
|
208
|
+
push_thread_local_value(:lumberjack_logger_level, temporary_level, &block)
|
209
|
+
else
|
210
|
+
yield
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Set the program name that is associated with log messages. If a block
|
215
|
+
# is given, the program name will be valid only within the block.
|
216
|
+
def set_progname(value, &block)
|
217
|
+
if block
|
218
|
+
push_thread_local_value(:lumberjack_logger_progname, value, &block)
|
219
|
+
else
|
220
|
+
self.progname = value
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Get the program name associated with log messages.
|
225
|
+
def progname
|
226
|
+
thread_local_value(:lumberjack_logger_progname) || @progname
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Set a local value for a thread tied to this object.
|
232
|
+
def set_thread_local_value(name, value) #:nodoc:
|
233
|
+
values = Thread.current[name]
|
234
|
+
unless values
|
235
|
+
values = {}
|
236
|
+
Thread.current[name] = values
|
237
|
+
end
|
238
|
+
if value.nil?
|
239
|
+
values.delete(self)
|
240
|
+
Thread.current[name] = nil if values.empty?
|
241
|
+
else
|
242
|
+
values[self] = value
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Get a local value for a thread tied to this object.
|
247
|
+
def thread_local_value(name) #:nodoc:
|
248
|
+
values = Thread.current[name]
|
249
|
+
values[self] if values
|
250
|
+
end
|
251
|
+
|
252
|
+
# Set a local value for a thread tied to this object within a block.
|
253
|
+
def push_thread_local_value(name, value) #:nodoc:
|
254
|
+
save_val = thread_local_value(name)
|
255
|
+
set_thread_local_value(name, value)
|
256
|
+
begin
|
257
|
+
yield
|
258
|
+
ensure
|
259
|
+
set_thread_local_value(name, save_val)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Open a logging device.
|
264
|
+
def open_device(device, options) #:nodoc:
|
265
|
+
if device.is_a?(Device)
|
266
|
+
device
|
267
|
+
elsif device.respond_to?(:write)
|
268
|
+
Device::Writer.new(device, options)
|
269
|
+
elsif device == :null
|
270
|
+
Device::Null.new
|
271
|
+
else
|
272
|
+
device = device.to_s
|
273
|
+
if options[:roll]
|
274
|
+
Device::DateRollingLogFile.new(device, options)
|
275
|
+
elsif options[:max_size]
|
276
|
+
Device::SizeRollingLogFile.new(device, options)
|
277
|
+
else
|
278
|
+
Device::LogFile.new(device, options)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Create a thread that will periodically call flush.
|
284
|
+
def create_flusher_thread(flush_seconds) #:nodoc:
|
285
|
+
if flush_seconds > 0
|
286
|
+
begin
|
287
|
+
logger = self
|
288
|
+
Thread.new do
|
289
|
+
loop do
|
290
|
+
begin
|
291
|
+
sleep(flush_seconds)
|
292
|
+
logger.flush if Time.now - logger.last_flushed_at >= flush_seconds
|
293
|
+
rescue => e
|
294
|
+
STDERR.puts("Error flushing log: #{e.inspect}")
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|