buffered_logger 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +105 -0
- data/TODO +3 -0
- data/lib/buffered_logger/buffering.rb +66 -0
- data/lib/buffered_logger/formatting.rb +92 -0
- data/lib/buffered_logger/indentation.rb +61 -0
- data/lib/buffered_logger/logger.rb +114 -0
- data/lib/buffered_logger/thread_hash.rb +12 -0
- data/lib/buffered_logger.rb +6 -57
- data/spec/buffering_spec.rb +12 -0
- data/spec/formatting_spec.rb +120 -0
- data/spec/indentation_spec.rb +92 -0
- data/spec/logger_spec.rb +75 -0
- data/spec/spec_helper.rb +4 -0
- metadata +17 -5
data/README
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
ABOUT
|
2
|
+
-------------------------------------------------------------------------------
|
3
|
+
The 'buffered_logger' gem is an extension to ActiveSupport::BufferedLogger which
|
4
|
+
gives the the little logger some much needed formatting support. The actual
|
5
|
+
logging work is still delegated to to active_support/buffered_logger.
|
6
|
+
|
7
|
+
|
8
|
+
FEATURES
|
9
|
+
-------------------------------------------------------------------------------
|
10
|
+
- per thread indentation
|
11
|
+
- per thread auto flush setting
|
12
|
+
- temporary indentation blocks
|
13
|
+
- per severity formatting
|
14
|
+
- ansi color output formats
|
15
|
+
|
16
|
+
|
17
|
+
USAGE
|
18
|
+
-------------------------------------------------------------------------------
|
19
|
+
# default initialization
|
20
|
+
l = BufferedLogger.new(STDOUT)
|
21
|
+
|
22
|
+
# changing the severity level
|
23
|
+
l.level = :warn
|
24
|
+
l.level = 1
|
25
|
+
|
26
|
+
# formatter constructor (initializes the master thread's formatters)
|
27
|
+
l = BufferedLogger.new(STDOUT, :debug,
|
28
|
+
{ :info => "$green INFO: $white %s",
|
29
|
+
:warn => "$yellow WARNING: $white %s",
|
30
|
+
:error => "$red ERROR: $white %s" } )
|
31
|
+
|
32
|
+
# setting formatting after initialization
|
33
|
+
l.info_formatter = "$green INFO: $white %s",
|
34
|
+
l.warn_formatter = "$yellow WARNING: $white %s"
|
35
|
+
l.error_formatter = "$red ERROR: $white %s"
|
36
|
+
|
37
|
+
# checking the current thread's formatting
|
38
|
+
l.info_formatter.to_s
|
39
|
+
l.warn_formatter.to_s
|
40
|
+
...
|
41
|
+
|
42
|
+
# checking the current thread's indentation
|
43
|
+
l.padding.to_s
|
44
|
+
|
45
|
+
# setting the current thread's indentation
|
46
|
+
l.indent(4) # move cursor right 4 spaces
|
47
|
+
l.indent(-2) # move cursor left 2 spaces
|
48
|
+
l.indent(:reset) # reset indentation
|
49
|
+
|
50
|
+
# temporarily indenting using an indent block
|
51
|
+
l.indent do
|
52
|
+
l.info 'some info'
|
53
|
+
...
|
54
|
+
l.info 'some more info'
|
55
|
+
end
|
56
|
+
|
57
|
+
# setting auto_flushing
|
58
|
+
l.auto_flushing = 2
|
59
|
+
|
60
|
+
|
61
|
+
USAGE DETAILS
|
62
|
+
-------------------------------------------------------------------------------
|
63
|
+
* Severity Levels
|
64
|
+
- severity level is optional and defaults to :debug
|
65
|
+
- severity level can be provided as an Integer or Symbol
|
66
|
+
0 - DEBUG
|
67
|
+
1 - INFO
|
68
|
+
2 - WARN
|
69
|
+
3 - ERROR
|
70
|
+
4 - FATAL
|
71
|
+
5 - UNKNOWN
|
72
|
+
|
73
|
+
* ActiveSupport::BufferedLogger
|
74
|
+
- native buffered_logger functionality is preserved
|
75
|
+
$ ActiveSupport::BufferedLogger.public_instance_methods(false)
|
76
|
+
=> ["add", "info", "fatal?", "auto_flushing", "fatal", "silencer", "debug",
|
77
|
+
"info?", "warn?", "auto_flushing=", "silencer=", "level", "error?", "unknown",
|
78
|
+
"debug?", "flush", "level=", "open_log", "warn", "unknown?", "silence",
|
79
|
+
"error", "close"]
|
80
|
+
|
81
|
+
* ANSI Color
|
82
|
+
- colors are only supported when logging to STDOUT
|
83
|
+
- any ansi method may be used in a format string following a '$' symbol
|
84
|
+
$ Term::ANSIColor.instance_methods
|
85
|
+
=> ["black", "on_yellow", "underscore", "rapid_blink", "white", "bold",
|
86
|
+
"yellow", "on_cyan", "strikethrough", "on_green", "uncolored", "blink",
|
87
|
+
"cyan", "reset", "green", "on_magenta", "clear", "concealed", "on_red",
|
88
|
+
"dark", "underline", "magenta", "red", "on_blue", "negative", "on_black",
|
89
|
+
"italic", "blue", "on_white"]
|
90
|
+
|
91
|
+
* Indentation
|
92
|
+
- the padding is calculated on a per thread basis and each thread has an
|
93
|
+
indentation counter which is shared across all severity levels
|
94
|
+
|
95
|
+
* Formatting
|
96
|
+
- formatters are set on a per thread/per severity basis, meaning that every
|
97
|
+
severity level for every thread allows for a custom formatter
|
98
|
+
- the formatter search order is as follows
|
99
|
+
1. current thread's formatter for specified severity
|
100
|
+
2. master thread's formatter for specified severity
|
101
|
+
3. master thread's default formatter
|
102
|
+
|
103
|
+
* Thread Buffering
|
104
|
+
- the auto_flushing setting is set per thread and each thread defaults to
|
105
|
+
the autoflush setting of the master thread unless explicitly configured
|
data/TODO
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module BufferedLogger::Buffering
|
2
|
+
MAX_BUFFER_SIZE = 1000
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@buffer = Hash.new { |h,k| h[k] = [] }
|
6
|
+
@auto_flushing = BufferedLogger::ThreadHash.new
|
7
|
+
@auto_flushing[master_thread] = 1
|
8
|
+
@guard = Mutex.new
|
9
|
+
super()
|
10
|
+
end
|
11
|
+
|
12
|
+
def buffer_text
|
13
|
+
buffer.join('')
|
14
|
+
end
|
15
|
+
|
16
|
+
def auto_flushing
|
17
|
+
@auto_flushing[Thread.current] || @auto_flushing[master_thread]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set the auto-flush period. Set to true to flush after every log message,
|
21
|
+
# to an integer to flush every N messages, or to false, nil, or zero to
|
22
|
+
# never auto-flush. If you turn auto-flushing off, be sure to regularly
|
23
|
+
# flush the log yourself -- it will eat up memory until you do.
|
24
|
+
def auto_flushing=(period)
|
25
|
+
@auto_flushing[Thread.current] =
|
26
|
+
case period
|
27
|
+
when true; 1
|
28
|
+
when false, nil, 0; MAX_BUFFER_SIZE
|
29
|
+
when Integer; period
|
30
|
+
else raise ArgumentError, "Unrecognized auto_flushing period: #{period.inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def flush
|
35
|
+
@guard.synchronize do
|
36
|
+
buffer.each do |content|
|
37
|
+
@log.write(content)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Important to do this even if buffer was empty or else @buffer will
|
41
|
+
# accumulate empty arrays for each request where nothing was logged.
|
42
|
+
clear_buffer
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
flush
|
48
|
+
@log.close if @log.respond_to?(:close)
|
49
|
+
@log = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def auto_flush
|
55
|
+
flush if buffer.size >= auto_flushing
|
56
|
+
end
|
57
|
+
|
58
|
+
def buffer
|
59
|
+
@buffer[Thread.current]
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear_buffer
|
63
|
+
@buffer.delete(Thread.current)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
module BufferedLogger::Formatting
|
4
|
+
DEFAULT_LEVEL = :default
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@formatter = BufferedLogger::ThreadHash.new { |h,k| h[k] = {} }
|
10
|
+
super()
|
11
|
+
end
|
12
|
+
|
13
|
+
def formatter(severity = DEFAULT_LEVEL)
|
14
|
+
@formatter[Thread.current][severity] || @formatter[master_thread][severity] || default_formatter
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_formatter(severity = DEFAULT_LEVEL, format = nil)
|
18
|
+
@formatter[Thread.current][severity] = BufferedLogger::Formatter.new(:format => format, :color => color?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_formatter
|
22
|
+
@formatter[master_thread][DEFAULT_LEVEL] ||= BufferedLogger::Formatter.new(:color => color?)
|
23
|
+
end
|
24
|
+
|
25
|
+
# magic format getters/setters
|
26
|
+
|
27
|
+
def method_missing(method, *args, &block)
|
28
|
+
case method.to_s
|
29
|
+
when /^(#{BufferedLogger::SEVERITY_LEVELS.join('|')})_formatter(=)?$/
|
30
|
+
$2 ? set_formatter($1.to_sym, args[0]) : formatter($1.to_sym)
|
31
|
+
else
|
32
|
+
super(method, *args, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
class BufferedLogger::Formatter
|
40
|
+
include ::Term::ANSIColor
|
41
|
+
|
42
|
+
FORMAT = "%s"
|
43
|
+
COLOR = true
|
44
|
+
|
45
|
+
def initialize(params = {})
|
46
|
+
@format = params[:format] || FORMAT
|
47
|
+
@color = params[:color] == false ? false : COLOR
|
48
|
+
end
|
49
|
+
|
50
|
+
# format accessors
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
@format
|
54
|
+
end
|
55
|
+
|
56
|
+
def format=(format)
|
57
|
+
@format = format.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
# color accessors
|
61
|
+
|
62
|
+
def color?
|
63
|
+
@color
|
64
|
+
end
|
65
|
+
|
66
|
+
def toggle_color
|
67
|
+
@color = !@color
|
68
|
+
end
|
69
|
+
|
70
|
+
# formatting
|
71
|
+
|
72
|
+
def %(message)
|
73
|
+
formatted_message = @format % message.to_s
|
74
|
+
color? ? parse_color(formatted_message) : formatted_message
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def parse_color(message)
|
80
|
+
color_methods = Term::ANSIColor.instance_methods
|
81
|
+
color_matcher = /#{color_methods.map {|m| "\\$#{m}\\s?"}.join('|')}/
|
82
|
+
|
83
|
+
strings = message.split(color_matcher)
|
84
|
+
colors = message.scan(color_matcher).map { |c| c[1..-1].strip }
|
85
|
+
|
86
|
+
colored_message = ''
|
87
|
+
strings[1..-1].each_with_index { |s,i| colored_message << self.send(colors[i], s) }
|
88
|
+
strings[0] + colored_message
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module BufferedLogger::Indentation
|
2
|
+
# padding is set at the thread level
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@padding = BufferedLogger::ThreadHash.new { |h,k| h[k] = BufferedLogger::Padding.new }
|
6
|
+
super()
|
7
|
+
end
|
8
|
+
|
9
|
+
def padding
|
10
|
+
@padding[Thread.current]
|
11
|
+
end
|
12
|
+
|
13
|
+
def indent(level, &block)
|
14
|
+
if block_given?
|
15
|
+
padding.indent(level)
|
16
|
+
ret_val = block.call
|
17
|
+
padding.indent(-level)
|
18
|
+
return ret_val
|
19
|
+
else
|
20
|
+
padding.indent(level)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class BufferedLogger::Padding
|
27
|
+
PADDING_CHAR = ' '
|
28
|
+
PADDING_RESET= :reset
|
29
|
+
attr_reader :padding_char
|
30
|
+
|
31
|
+
def initialize(params = {})
|
32
|
+
@padding = ''
|
33
|
+
@padding_char = params[:padding_char] || PADDING_CHAR
|
34
|
+
indent(params[:indent] || 0)
|
35
|
+
end
|
36
|
+
|
37
|
+
def padding_char=(char)
|
38
|
+
@padding_char = char.to_s[0..1]
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
@padding
|
43
|
+
end
|
44
|
+
|
45
|
+
def indent(indent_level)
|
46
|
+
@padding = \
|
47
|
+
if indent_level == PADDING_RESET
|
48
|
+
''
|
49
|
+
elsif indent_level > 0
|
50
|
+
@padding + (@padding_char * indent_level)
|
51
|
+
else
|
52
|
+
@padding[0..(-1+indent_level)]
|
53
|
+
end
|
54
|
+
indent_level
|
55
|
+
end
|
56
|
+
|
57
|
+
def %(message)
|
58
|
+
@padding + message.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
|
4
|
+
class BufferedLogger
|
5
|
+
include Indentation
|
6
|
+
include Formatting
|
7
|
+
include Buffering
|
8
|
+
|
9
|
+
module Severity
|
10
|
+
DEBUG = 0
|
11
|
+
INFO = 1
|
12
|
+
WARN = 2
|
13
|
+
ERROR = 3
|
14
|
+
FATAL = 4
|
15
|
+
UNKNOWN = 5
|
16
|
+
end
|
17
|
+
include Severity
|
18
|
+
|
19
|
+
SEVERITY_LEVELS = Severity.constants.map { |c| c.downcase.to_sym }.freeze
|
20
|
+
SEVERITY_MAP = Severity.constants.inject({}) do |h,c|
|
21
|
+
h[c.downcase.to_sym] = Severity.const_get(c); h
|
22
|
+
end.freeze
|
23
|
+
|
24
|
+
|
25
|
+
##
|
26
|
+
# :singleton-method:
|
27
|
+
# Set to false to disable the silencer
|
28
|
+
cattr_accessor :silencer
|
29
|
+
self.silencer = true
|
30
|
+
|
31
|
+
attr_accessor :level
|
32
|
+
attr_reader :master_thread
|
33
|
+
private :master_thread
|
34
|
+
|
35
|
+
def initialize(log, level = DEBUG, params = {})
|
36
|
+
@master_thread = Thread.current
|
37
|
+
super()
|
38
|
+
|
39
|
+
@level = severity_to_const(level)
|
40
|
+
if log.respond_to?(:write)
|
41
|
+
@log = log
|
42
|
+
elsif File.exist?(log)
|
43
|
+
@log = open_log(log, (File::WRONLY | File::APPEND))
|
44
|
+
else
|
45
|
+
FileUtils.mkdir_p(File.dirname(log))
|
46
|
+
@log = open_log(log, (File::WRONLY | File::APPEND | File::CREAT))
|
47
|
+
end
|
48
|
+
params.each { |k,v| SEVERITY_LEVELS.include?(k) ? set_formatter(k, v) : next }
|
49
|
+
end
|
50
|
+
|
51
|
+
def open_log(log, mode)
|
52
|
+
open(log, mode).tap do |open_log|
|
53
|
+
open_log.set_encoding(Encoding::BINARY) if open_log.respond_to?(:set_encoding)
|
54
|
+
open_log.sync = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add(severity, message = nil, progname = nil, &block)
|
59
|
+
return if @level > severity
|
60
|
+
message = (message || (block && block.call) || progname).to_s
|
61
|
+
# If a newline is necessary then create a new message ending with a newline.
|
62
|
+
# Ensures that the original message is not mutated.
|
63
|
+
message = "#{message}\n" unless message[-1] == ?\n
|
64
|
+
buffer << message
|
65
|
+
auto_flush
|
66
|
+
message
|
67
|
+
end
|
68
|
+
|
69
|
+
for severity in SEVERITY_LEVELS
|
70
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
71
|
+
def #{severity}(message = nil, progname = nil, &block)
|
72
|
+
add(#{SEVERITY_MAP[severity]}, padding % (formatter(:#{severity}) % message.to_s), progname, &block)
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def #{severity}?
|
77
|
+
#{SEVERITY_MAP[severity]} >= @level
|
78
|
+
end
|
79
|
+
EOT
|
80
|
+
end
|
81
|
+
|
82
|
+
# Silences the logger for the duration of the block.
|
83
|
+
def silence(temporary_level = ERROR)
|
84
|
+
if silencer
|
85
|
+
begin
|
86
|
+
old_logger_level, self.level = level, temporary_level
|
87
|
+
yield self
|
88
|
+
ensure
|
89
|
+
self.level = old_logger_level
|
90
|
+
end
|
91
|
+
else
|
92
|
+
yield self
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def color?
|
99
|
+
@log == STDOUT
|
100
|
+
end
|
101
|
+
|
102
|
+
def severity_to_const(severity)
|
103
|
+
case severity
|
104
|
+
when Integer
|
105
|
+
severity
|
106
|
+
when Symbol
|
107
|
+
SEVERITY_MAP[severity]
|
108
|
+
else
|
109
|
+
severity.to_i
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
data/lib/buffered_logger.rb
CHANGED
@@ -1,58 +1,7 @@
|
|
1
|
-
|
2
|
-
require 'active_support/buffered_logger'
|
3
|
-
require 'forwardable'
|
1
|
+
class BufferedLogger; end
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
DEFAULT_FORMATTER = "%s"
|
11
|
-
DEFAULT_PADDING = ""
|
12
|
-
PADDING_CHAR = " "
|
13
|
-
|
14
|
-
def initialize(log_file, log_level, log_count = nil, log_size = nil)
|
15
|
-
@logger = ActiveSupport::BufferedLogger.new(log_file, log_level)
|
16
|
-
@padding, @formatter = {}, {}
|
17
|
-
end
|
18
|
-
|
19
|
-
def buffer
|
20
|
-
buf = @logger.send(:buffer)
|
21
|
-
buf && buf.join('')
|
22
|
-
end
|
23
|
-
|
24
|
-
# overwrite all the logging methods
|
25
|
-
class_eval do
|
26
|
-
[:debug, :info, :warn, :error, :fatal, :unknown].each do |method|
|
27
|
-
define_method(method) do |message|
|
28
|
-
@logger.send(method, (padding + formatter) % message.to_s)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def indent(indent_level)
|
34
|
-
@padding[Thread.current] = \
|
35
|
-
if indent_level == :reset
|
36
|
-
""
|
37
|
-
elsif indent_level > 0
|
38
|
-
padding + (PADDING_CHAR * indent_level)
|
39
|
-
else
|
40
|
-
padding[0..(-1+indent_level)]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def formatter=(format)
|
45
|
-
@formatter[Thread.current] = format
|
46
|
-
end
|
47
|
-
|
48
|
-
protected
|
49
|
-
|
50
|
-
def padding
|
51
|
-
@padding[Thread.current] ||= DEFAULT_PADDING
|
52
|
-
end
|
53
|
-
|
54
|
-
def formatter
|
55
|
-
@formatter[Thread.current] ||= DEFAULT_FORMATTER
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
3
|
+
require 'buffered_logger/thread_hash'
|
4
|
+
require 'buffered_logger/buffering'
|
5
|
+
require 'buffered_logger/indentation'
|
6
|
+
require 'buffered_logger/formatting'
|
7
|
+
require 'buffered_logger/logger'
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
2
|
+
|
3
|
+
describe BufferedLogger::Formatter do
|
4
|
+
before :each do
|
5
|
+
@f = BufferedLogger::Formatter.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'initialization and accessors' do
|
9
|
+
it "should init a new formatter object" do
|
10
|
+
@f.should be_an_instance_of BufferedLogger::Formatter
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the default format string" do
|
14
|
+
@f.to_s.should == '%s'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set the format string" do
|
18
|
+
@f.format = '%d'
|
19
|
+
@f.to_s.should == '%d'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should check if color is enabled by default' do
|
23
|
+
@f.color?.should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should toggle the color setting' do
|
27
|
+
@f.toggle_color
|
28
|
+
@f.color?.should be_false
|
29
|
+
@f.toggle_color
|
30
|
+
@f.color?.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should construct a formatter object based on params' do
|
34
|
+
f = BufferedLogger::Formatter.new(:format => '%s%s%s', :color => false)
|
35
|
+
f.to_s.should == '%s%s%s'
|
36
|
+
f.color?.should be_false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'formatting' do
|
41
|
+
it 'should parse color codes' do
|
42
|
+
s = "$blue blue $green green $red red"
|
43
|
+
@f.send(:parse_color, s).should == "\e[34mblue \e[0m\e[32mgreen \e[0m\e[31mred\e[0m"
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should format an input string' do
|
47
|
+
s = 'text'
|
48
|
+
(@f % s).should == 'text'
|
49
|
+
@f.format = '### %s ###'
|
50
|
+
(@f % s).should == '### text ###'
|
51
|
+
@f.format = '$blue ### $red %s $blue ###'
|
52
|
+
(@f % s).should == "\e[34m### \e[0m\e[31mtext \e[0m\e[34m###\e[0m"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe BufferedLogger do
|
58
|
+
before :each do
|
59
|
+
@f = StringIO.new
|
60
|
+
@l = BufferedLogger.new(@f)
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'formatting' do
|
64
|
+
it 'should use appropriate formatting for each thread' do
|
65
|
+
@l.send(:set_formatter, :info, "$blue %s")
|
66
|
+
@l.info "oh"
|
67
|
+
|
68
|
+
t = Thread.new do
|
69
|
+
@l.send(:set_formatter, :info, "$red %s")
|
70
|
+
@l.info 'blah'
|
71
|
+
end; t.join
|
72
|
+
|
73
|
+
t = Thread.new do
|
74
|
+
@l.info 'hey'
|
75
|
+
end; t.join
|
76
|
+
|
77
|
+
@l.info "haha"
|
78
|
+
|
79
|
+
# colors are off so the keywords won't be parsed
|
80
|
+
@f.string.should == "$blue oh\n$red blah\n$blue hey\n$blue haha\n"
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should use appropriate formatting for each severity level' do
|
84
|
+
@l.send(:set_formatter, :error, "$red %s")
|
85
|
+
@l.send(:set_formatter, :info, "$blue %s")
|
86
|
+
@l.error 'error'
|
87
|
+
@l.info 'info'
|
88
|
+
@f.string.should == "$red error\n$blue info\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should use the master thread formatter if one isnt set' do
|
92
|
+
@l.send(:set_formatter, :error, "$red %s")
|
93
|
+
@l.error 'test'
|
94
|
+
|
95
|
+
t = Thread.new do
|
96
|
+
@l.error 'blah'
|
97
|
+
end; t.join
|
98
|
+
@f.string.should == "$red test\n$red blah\n"
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should use the master thread default formatter if one isnt set' do
|
102
|
+
t_formatter = nil
|
103
|
+
t = Thread.new do
|
104
|
+
t_formatter = @l.send(:formatter, :info)
|
105
|
+
end; t.join
|
106
|
+
|
107
|
+
t_formatter.should == @l.send(:formatter, :info)
|
108
|
+
t_formatter.should == @l.send(:formatter, :error)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should allow syntactic sugar to get/set formatters' do
|
112
|
+
BufferedLogger::SEVERITY_LEVELS.each do |s|
|
113
|
+
@l.send("#{s}_formatter=", "$green #{s}: $white %s")
|
114
|
+
@l.send("#{s}_formatter").to_s.should == "$green #{s}: $white %s"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
2
|
+
|
3
|
+
describe BufferedLogger::Padding do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@p = BufferedLogger::Padding.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'initialization and accessors' do
|
10
|
+
it "should initialize a new padding object" do
|
11
|
+
@p.should be_an_instance_of BufferedLogger::Padding
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set padding character" do
|
15
|
+
@p.padding_char = '#'
|
16
|
+
@p.padding_char.should == '#'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return the padding string" do
|
20
|
+
@p.to_s.should == ''
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should construct pre-padded strings" do
|
24
|
+
p = BufferedLogger::Padding.new(:indent => 4, :padding_char => '#')
|
25
|
+
p.to_s.should == '####'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'indentation' do
|
30
|
+
it "should indent padding a positive amount" do
|
31
|
+
@p.indent(2)
|
32
|
+
@p.to_s.should == ' '
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should indent padding a negative amount" do
|
36
|
+
@p.indent(3)
|
37
|
+
@p.indent(-2)
|
38
|
+
@p.to_s.should == ' '
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should reset padding indentation" do
|
42
|
+
@p.indent(10)
|
43
|
+
@p.indent(:reset)
|
44
|
+
@p.to_s.should == ''
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'formatting' do
|
49
|
+
it "should apply padding to any input string" do
|
50
|
+
s = 'text'
|
51
|
+
@p.indent(4)
|
52
|
+
(@p % s).should == ' text'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
describe BufferedLogger do
|
60
|
+
before :each do
|
61
|
+
@f = StringIO.new
|
62
|
+
@l = BufferedLogger.new(@f)
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'indentation' do
|
66
|
+
it 'should use appropriate indentation for each thread' do
|
67
|
+
@l.indent(4)
|
68
|
+
@l.info 'hello'
|
69
|
+
|
70
|
+
t = Thread.new do
|
71
|
+
@l.indent(2)
|
72
|
+
@l.info 'blah'
|
73
|
+
end; t.join
|
74
|
+
|
75
|
+
t = Thread.new do
|
76
|
+
@l.info 'hey'
|
77
|
+
end; t.join
|
78
|
+
|
79
|
+
@l.info 'hi'
|
80
|
+
|
81
|
+
@f.string.should == " hello\n blah\nhey\n hi\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should temporarily indent any logging in an indent block' do
|
85
|
+
@l.indent(4) do
|
86
|
+
@l.info 'blah'
|
87
|
+
end
|
88
|
+
@l.info 'blah'
|
89
|
+
@f.string.should == " blah\nblah\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/logger_spec.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
2
|
+
require 'rubygems'
|
3
|
+
require 'active_support/buffered_logger'
|
4
|
+
|
5
|
+
describe BufferedLogger do
|
6
|
+
before :each do
|
7
|
+
@f = StringIO.new
|
8
|
+
@l = BufferedLogger.new(@f)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'initialization and accessors' do
|
12
|
+
it 'should initialize a new logger object' do
|
13
|
+
@l.should be_an_instance_of BufferedLogger
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should initialize a logger object using a severity level symbol' do
|
17
|
+
l = BufferedLogger.new(@f, :info)
|
18
|
+
l.info "info"
|
19
|
+
l.debug "debug"
|
20
|
+
l.warn "warn"
|
21
|
+
@f.string.should == "info\nwarn\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should support color when printing to STDOUT' do
|
25
|
+
l = BufferedLogger.new(STDOUT)
|
26
|
+
l.send(:color?).should == true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not support color when not printing to STDOUT' do
|
30
|
+
@l.send(:color?).should == false
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should autoset formatters during init' do
|
34
|
+
l = BufferedLogger.new(STDOUT, 0, {:info => '$green INFO: $white %s', :warn => '$yellow WARNING: $white %s', :error => '$red ERROR: $white %s'})
|
35
|
+
l.send(:formatter, :info).to_s.should == '$green INFO: $white %s'
|
36
|
+
l.send(:formatter, :warn).to_s.should == '$yellow WARNING: $white %s'
|
37
|
+
l.send(:formatter, :error).to_s.should == '$red ERROR: $white %s'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'delegation and magic methods' do
|
42
|
+
it 'should maintain backwards compatibility with buffered_logger interface' do
|
43
|
+
delegated = ActiveSupport::BufferedLogger.public_instance_methods(false)
|
44
|
+
delegated.each { |method| @l.should respond_to(method) }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should respond to magic methods' do
|
48
|
+
magic = BufferedLogger::SEVERITY_LEVELS
|
49
|
+
magic.each { |method| @l.should respond_to(method) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'logging' do
|
54
|
+
it 'should log to a IO object' do
|
55
|
+
severities = BufferedLogger::SEVERITY_LEVELS
|
56
|
+
severities.each do |s|
|
57
|
+
f = StringIO.new
|
58
|
+
l = BufferedLogger.new(f)
|
59
|
+
l.send(s, "#{s}_message")
|
60
|
+
f.string.should == "#{s}_message\n"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should buffer unflushed statements' do
|
65
|
+
@l.auto_flushing = 0
|
66
|
+
@l.info 'test'
|
67
|
+
@l.info 'test2'
|
68
|
+
@l.buffer_text.should == "test\ntest2\n"
|
69
|
+
@f.string.should == ''
|
70
|
+
@l.flush
|
71
|
+
@f.string.should == "test\ntest2\n"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.2
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Skryl
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-07-19 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: "0"
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
-
description:
|
35
|
+
description: A thread safe logger with formatting extensions. Based on active_support/buffered_logger.
|
36
36
|
email: rut216@gmail.com
|
37
37
|
executables: []
|
38
38
|
|
@@ -41,7 +41,19 @@ extensions: []
|
|
41
41
|
extra_rdoc_files: []
|
42
42
|
|
43
43
|
files:
|
44
|
+
- lib/buffered_logger/buffering.rb
|
45
|
+
- lib/buffered_logger/formatting.rb
|
46
|
+
- lib/buffered_logger/indentation.rb
|
47
|
+
- lib/buffered_logger/logger.rb
|
48
|
+
- lib/buffered_logger/thread_hash.rb
|
44
49
|
- lib/buffered_logger.rb
|
50
|
+
- spec/buffering_spec.rb
|
51
|
+
- spec/formatting_spec.rb
|
52
|
+
- spec/indentation_spec.rb
|
53
|
+
- spec/logger_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
- README
|
56
|
+
- TODO
|
45
57
|
has_rdoc: true
|
46
58
|
homepage: http://github.com/skryl
|
47
59
|
licenses: []
|
@@ -75,6 +87,6 @@ rubyforge_project:
|
|
75
87
|
rubygems_version: 1.6.2
|
76
88
|
signing_key:
|
77
89
|
specification_version: 3
|
78
|
-
summary:
|
90
|
+
summary: A flexible, thread safe logger with custom formatting and ANSI color support
|
79
91
|
test_files: []
|
80
92
|
|