logue 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/README.md +31 -0
- data/lib/logue/format.rb +49 -0
- data/lib/logue/log.rb +244 -0
- data/lib/logue/loggable.rb +101 -0
- data/lib/logue/logger.rb +267 -0
- data/lib/logue/severity.rb +22 -0
- data/lib/logue.rb +17 -0
- data/test/logue/format_test.rb +48 -0
- data/test/logue/testlog/log_stack_test.rb +97 -0
- data/test/logue/testlog/log_test.rb +166 -0
- data/test/logue/testlog/loggable_test.rb +31 -0
- metadata +76 -0
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
logue
|
2
|
+
=====
|
3
|
+
|
4
|
+
A Ruby gem for generating logging and debugging output. Logging statements
|
5
|
+
include the file, line, class and method from which the logging method was
|
6
|
+
called.
|
7
|
+
|
8
|
+
## EXAMPLES
|
9
|
+
|
10
|
+
```
|
11
|
+
require 'logue/log'
|
12
|
+
require 'logue/loggable'
|
13
|
+
|
14
|
+
Logue::Log.level = Logue::Log::DEBUG
|
15
|
+
|
16
|
+
class MyClass
|
17
|
+
include Logue::Loggable
|
18
|
+
|
19
|
+
def mymethod foo
|
20
|
+
info "foo: #{foo}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
MyClass.new.mymethod "bar"
|
25
|
+
```
|
26
|
+
|
27
|
+
Produces:
|
28
|
+
|
29
|
+
```
|
30
|
+
[/tmp/foo.rb : 13] {MyClass#mymethod } foo: bar
|
31
|
+
```
|
data/lib/logue/format.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
module Logue
|
5
|
+
class Format
|
6
|
+
|
7
|
+
def trim_left str, maxlen
|
8
|
+
str[0 ... maxlen.to_i.abs]
|
9
|
+
end
|
10
|
+
|
11
|
+
def trim_right str, maxlen
|
12
|
+
mxln = maxlen.abs
|
13
|
+
|
14
|
+
# magic number 3 for the ellipses ...
|
15
|
+
|
16
|
+
if str.length > mxln
|
17
|
+
path = str.split('/')
|
18
|
+
newstr = "..."
|
19
|
+
path.reverse.each do |element|
|
20
|
+
if newstr.length + element.length > mxln
|
21
|
+
while newstr.length < mxln
|
22
|
+
newstr.insert 0, " "
|
23
|
+
end
|
24
|
+
return newstr
|
25
|
+
else
|
26
|
+
if newstr.length > 3
|
27
|
+
newstr.insert 3, "/"
|
28
|
+
end
|
29
|
+
newstr.insert 3, element
|
30
|
+
end
|
31
|
+
end
|
32
|
+
newstr
|
33
|
+
else
|
34
|
+
str
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_formatted file, line, func, msg, lvl, &blk
|
39
|
+
if trim
|
40
|
+
file = trim_right file, @file_width
|
41
|
+
line = trim_left line, @line_width
|
42
|
+
func = trim_left func, @function_width
|
43
|
+
end
|
44
|
+
|
45
|
+
hdr = sprintf @format, file, line, func
|
46
|
+
print hdr, msg, lvl, &blk
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/logue/log.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
#
|
4
|
+
# = log.rb
|
5
|
+
#
|
6
|
+
# Logging Module
|
7
|
+
#
|
8
|
+
# Author:: Jeff Pace <jpace@incava.org>
|
9
|
+
# Documentation:: Author
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'logue/logger'
|
13
|
+
require 'logue/severity'
|
14
|
+
require 'rubygems'
|
15
|
+
require 'rainbow'
|
16
|
+
|
17
|
+
#
|
18
|
+
# == Log
|
19
|
+
#
|
20
|
+
# Very minimal logging output. If verbose is set, this displays the method and
|
21
|
+
# line number whence called. It can be a mixin to a class, which displays the
|
22
|
+
# class and method from where it called. If not in a class, it displays only the
|
23
|
+
# method.
|
24
|
+
#
|
25
|
+
# Remember: all kids love log.
|
26
|
+
#
|
27
|
+
# == Examples
|
28
|
+
#
|
29
|
+
# See the unit tests in log_test.rb
|
30
|
+
#
|
31
|
+
# == Usage
|
32
|
+
#
|
33
|
+
# The most general usage is simply to call:
|
34
|
+
#
|
35
|
+
# Log.log "some message"
|
36
|
+
#
|
37
|
+
# That will simply log the given message.
|
38
|
+
#
|
39
|
+
# class YourClass
|
40
|
+
# include Loggable
|
41
|
+
#
|
42
|
+
# def some_method(...)
|
43
|
+
# log "my message"
|
44
|
+
#
|
45
|
+
# That will log from the given class and method, showing the line number from
|
46
|
+
# which the logger was called.
|
47
|
+
#
|
48
|
+
# def another_method(...)
|
49
|
+
# stack "my message"
|
50
|
+
#
|
51
|
+
# That will produce a stack trace from the given location.
|
52
|
+
#
|
53
|
+
|
54
|
+
module Logue
|
55
|
+
class Log
|
56
|
+
$LOGGING_LEVEL = nil
|
57
|
+
|
58
|
+
DEFAULT_FILENAME_WIDTH = -25
|
59
|
+
DEFAULT_LINENUM_WIDTH = 4
|
60
|
+
DEFAULT_FUNCTION_WIDTH = -20
|
61
|
+
|
62
|
+
include Log::Severity
|
63
|
+
|
64
|
+
# by default, class methods delegate to a single app-wide log.
|
65
|
+
|
66
|
+
@@log = Logger.new
|
67
|
+
|
68
|
+
# Returns the logger of the log. A class method delegating to an instance
|
69
|
+
# method ... not so good. But temporary.
|
70
|
+
def self.logger
|
71
|
+
@@log
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.method_missing meth, *args, &blk
|
75
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
76
|
+
# only handling foregrounds, not backgrounds
|
77
|
+
if code = validcolors[meth]
|
78
|
+
add_color_method meth.to_s, code + 30
|
79
|
+
send meth, *args, &blk
|
80
|
+
else
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.respond_to? meth
|
86
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
87
|
+
validcolors.include?(meth) || super
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.add_color_method color, code
|
91
|
+
instmeth = Array.new
|
92
|
+
instmeth << "def #{color} msg = \"\", lvl = Log::DEBUG, depth = 1, cname = nil, &blk"
|
93
|
+
instmeth << " log(\"\\e[#{code}m\#{msg\}\\e[0m\", lvl, depth + 1, cname, &blk)"
|
94
|
+
instmeth << "end"
|
95
|
+
instance_eval instmeth.join("\n")
|
96
|
+
|
97
|
+
clsmeth = Array.new
|
98
|
+
clsmeth << "def #{color} msg = \"\", lvl = Log::DEBUG, depth = 1, cname = nil, &blk"
|
99
|
+
clsmeth << " logger.#{color}(\"\\e[#{code}m\#{msg\}\\e[0m\", lvl, depth + 1, cname, &blk)"
|
100
|
+
clsmeth << "end"
|
101
|
+
|
102
|
+
class_eval clsmeth.join("\n")
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.set_default_widths
|
106
|
+
logger.set_default_widths
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.verbose
|
110
|
+
logger.verbose
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.verbose= v
|
114
|
+
logger.verbose = v && v != 0 ? DEBUG : FATAL
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.level= lvl
|
118
|
+
logger.level = lvl
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.quiet
|
122
|
+
logger.quiet
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.quiet= q
|
126
|
+
logger.quiet = q
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.format
|
130
|
+
logger.format
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.format= fmt
|
134
|
+
logger.format = fmt
|
135
|
+
end
|
136
|
+
|
137
|
+
# Assigns output to the given stream.
|
138
|
+
def self.output= io
|
139
|
+
logger.output = io
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.output
|
143
|
+
logger.output
|
144
|
+
end
|
145
|
+
|
146
|
+
# sets whether to colorize the entire line, or just the message.
|
147
|
+
def self.colorize_line= col
|
148
|
+
logger.colorize_line = col
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.colorize_line
|
152
|
+
logger.colorize_line
|
153
|
+
end
|
154
|
+
|
155
|
+
# Assigns output to a file with the given name. Returns the file; client
|
156
|
+
# is responsible for closing it.
|
157
|
+
def self.outfile= fname
|
158
|
+
logger.outfile = fname
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.outfile
|
162
|
+
logger.outfile
|
163
|
+
end
|
164
|
+
|
165
|
+
# Creates a printf format for the given widths, for aligning output.
|
166
|
+
def self.set_widths file_width, line_width, func_width
|
167
|
+
logger.set_widths file_width, line_width, func_width
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.ignore_file fname
|
171
|
+
logger.ignore_file fname
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.ignore_method methname
|
175
|
+
logger.ignored_method methname
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.ignore_class classname
|
179
|
+
logger.ignored_class classname
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.log_file fname
|
183
|
+
logger.log_file fname
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.log_method methname
|
187
|
+
logger.log_method methname
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.log_class classname
|
191
|
+
logger.log_class classname
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.debug msg = "", depth = 1, &blk
|
195
|
+
logger.log msg, DEBUG, depth + 1, &blk
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.info msg = "", depth = 1, &blk
|
199
|
+
logger.log msg, INFO, depth + 1, &blk
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.fatal msg = "", depth = 1, &blk
|
203
|
+
logger.log msg, FATAL, depth + 1, &blk
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.log msg = "", lvl = DEBUG, depth = 1, cname = nil, &blk
|
207
|
+
logger.log msg, lvl, depth + 1, cname, &blk
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.stack msg = "", lvl = DEBUG, depth = 1, cname = nil, &blk
|
211
|
+
logger.stack msg, lvl, depth + 1, cname, &blk
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.warn msg = "", depth = 1, &blk
|
215
|
+
if verbose
|
216
|
+
logger.log msg, WARN, depth + 1, &blk
|
217
|
+
else
|
218
|
+
$stderr.puts "WARNING: " + msg
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.error msg = "", depth = 1, &blk
|
223
|
+
if verbose
|
224
|
+
logger.log msg, ERROR, depth + 1, &blk
|
225
|
+
else
|
226
|
+
$stderr.puts "ERROR: " + msg
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.write msg, depth = 1, cname = nil, &blk
|
231
|
+
if verbose
|
232
|
+
stack msg, Log::WARN, depth + 1, cname, &blk
|
233
|
+
elsif quiet
|
234
|
+
# nothing
|
235
|
+
else
|
236
|
+
$stderr.puts msg
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.set_color lvl, color
|
241
|
+
logger.set_color lvl, color
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
#
|
4
|
+
# = log.rb
|
5
|
+
#
|
6
|
+
# Logging Module
|
7
|
+
#
|
8
|
+
# Author:: Jeff Pace <jpace@incava.org>
|
9
|
+
# Documentation:: Author
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'logue/log'
|
13
|
+
require 'rubygems'
|
14
|
+
require 'rainbow'
|
15
|
+
|
16
|
+
#
|
17
|
+
# == Loggable
|
18
|
+
#
|
19
|
+
# Including this module in a class gives access to the logger methods.
|
20
|
+
#
|
21
|
+
# == Examples
|
22
|
+
#
|
23
|
+
# See the unit tests in log_test.rb
|
24
|
+
#
|
25
|
+
# == Usage
|
26
|
+
#
|
27
|
+
# class YourClass
|
28
|
+
# include Loggable
|
29
|
+
#
|
30
|
+
# def some_method(...)
|
31
|
+
# log "my message"
|
32
|
+
#
|
33
|
+
# That will log from the given class and method, showing the line number from
|
34
|
+
# which the logger was called.
|
35
|
+
#
|
36
|
+
# def another_method(...)
|
37
|
+
# stack "my message"
|
38
|
+
#
|
39
|
+
# That will produce a stack trace from the given location.
|
40
|
+
#
|
41
|
+
|
42
|
+
module Logue
|
43
|
+
module Loggable
|
44
|
+
# Logs the given message, including the class whence invoked.
|
45
|
+
def log msg = "", lvl = Log::DEBUG, depth = 1, &blk
|
46
|
+
Log.log msg, lvl, depth + 1, self.class.to_s, &blk
|
47
|
+
end
|
48
|
+
|
49
|
+
def debug msg = "", depth = 1, &blk
|
50
|
+
Log.log msg, Log::DEBUG, depth + 1, self.class.to_s, &blk
|
51
|
+
end
|
52
|
+
|
53
|
+
def info msg = "", depth = 1, &blk
|
54
|
+
Log.log msg, Log::INFO, depth + 1, self.class.to_s, &blk
|
55
|
+
end
|
56
|
+
|
57
|
+
def warn msg = "", depth = 1, &blk
|
58
|
+
Log.log msg, Log::WARN, depth + 1, self.class.to_s, &blk
|
59
|
+
end
|
60
|
+
|
61
|
+
def error msg = "", depth = 1, &blk
|
62
|
+
Log.log msg, Log::ERROR, depth + 1, self.class.to_s, &blk
|
63
|
+
end
|
64
|
+
|
65
|
+
def fatal msg = "", depth = 1, &blk
|
66
|
+
Log.log msg, Log::FATAL, depth + 1, self.class.to_s, &blk
|
67
|
+
end
|
68
|
+
|
69
|
+
def stack msg = "", lvl = Log::DEBUG, depth = 1, &blk
|
70
|
+
Log.stack msg, lvl, depth + 1, self.class.to_s, &blk
|
71
|
+
end
|
72
|
+
|
73
|
+
def write msg = "", depth = 1, &blk
|
74
|
+
Log.write msg, depth + 1, self.class.to_s, &blk
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing meth, *args, &blk
|
78
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
79
|
+
# only handling foregrounds, not backgrounds
|
80
|
+
if code = validcolors[meth]
|
81
|
+
add_color_method meth.to_s, code + 30
|
82
|
+
send meth, *args, &blk
|
83
|
+
else
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def respond_to? meth
|
89
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
90
|
+
validcolors.include?(meth) || super
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_color_method color, code
|
94
|
+
meth = Array.new
|
95
|
+
meth << "def #{color}(msg = \"\", lvl = Log::DEBUG, depth = 1, cname = nil, &blk)"
|
96
|
+
meth << " Log.#{color} msg, lvl, depth + 1, self.class.to_s, &blk"
|
97
|
+
meth << "end"
|
98
|
+
self.class.module_eval meth.join("\n")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/logue/logger.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
#
|
4
|
+
# = logger.rb
|
5
|
+
#
|
6
|
+
# Logging Module
|
7
|
+
#
|
8
|
+
# Author:: Jeff Pace <jpace@incava.org>
|
9
|
+
# Documentation:: Author
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require 'rainbow'
|
14
|
+
require 'pathname'
|
15
|
+
require 'logue/severity'
|
16
|
+
require 'logue/format'
|
17
|
+
|
18
|
+
#
|
19
|
+
# == Logger
|
20
|
+
#
|
21
|
+
# This class logs messages. You probably don't want to use this directly; Log is
|
22
|
+
# the class containing the necessary class methods.
|
23
|
+
#
|
24
|
+
# == Examples
|
25
|
+
#
|
26
|
+
# See the unit tests in log_test.rb
|
27
|
+
#
|
28
|
+
|
29
|
+
module Logue
|
30
|
+
class Logger
|
31
|
+
$LOGGING_LEVEL = nil
|
32
|
+
|
33
|
+
attr_accessor :quiet
|
34
|
+
attr_accessor :output
|
35
|
+
attr_accessor :colorize_line
|
36
|
+
attr_accessor :level
|
37
|
+
attr_accessor :ignored_files
|
38
|
+
attr_accessor :ignored_methods
|
39
|
+
attr_accessor :ignored_classes
|
40
|
+
attr_accessor :trim
|
41
|
+
|
42
|
+
include Log::Severity
|
43
|
+
|
44
|
+
FRAME_RE = Regexp.new('(.*):(\d+)(?::in \`(.*)\')?')
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
set_defaults
|
48
|
+
end
|
49
|
+
|
50
|
+
def verbose= v
|
51
|
+
@level = case v
|
52
|
+
when TrueClass
|
53
|
+
DEBUG
|
54
|
+
when FalseClass
|
55
|
+
FATAL
|
56
|
+
when Integer
|
57
|
+
v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_defaults
|
62
|
+
$LOGGING_LEVEL = @level = FATAL
|
63
|
+
@ignored_files = Hash.new
|
64
|
+
@ignored_methods = Hash.new
|
65
|
+
@ignored_classes = Hash.new
|
66
|
+
@width = 0
|
67
|
+
@output = $stdout
|
68
|
+
@colors = Array.new
|
69
|
+
@colorize_line = false
|
70
|
+
@quiet = false
|
71
|
+
@trim = true
|
72
|
+
|
73
|
+
set_default_widths
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_default_widths
|
77
|
+
set_widths Log::DEFAULT_FILENAME_WIDTH, Log::DEFAULT_LINENUM_WIDTH, Log::DEFAULT_FUNCTION_WIDTH
|
78
|
+
end
|
79
|
+
|
80
|
+
def verbose
|
81
|
+
level <= DEBUG
|
82
|
+
end
|
83
|
+
|
84
|
+
# Assigns output to a file with the given name. Returns the file; client
|
85
|
+
# is responsible for closing it.
|
86
|
+
def outfile= f
|
87
|
+
@output = f.kind_of?(IO) ? f : File.new(f, "w")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates a printf format for the given widths, for aligning output. To lead
|
91
|
+
# lines with zeros (e.g., "00317") the line_width argument must be a string,
|
92
|
+
# not an integer.
|
93
|
+
def set_widths file_width, line_width, func_width
|
94
|
+
@file_width = file_width
|
95
|
+
@line_width = line_width
|
96
|
+
@function_width = func_width
|
97
|
+
|
98
|
+
@format = "[%#{file_width}s:%#{line_width}d] {%#{func_width}s}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def ignore_file fname
|
102
|
+
ignored_files[fname] = true
|
103
|
+
end
|
104
|
+
|
105
|
+
def ignore_method methname
|
106
|
+
ignored_methods[methname] = true
|
107
|
+
end
|
108
|
+
|
109
|
+
def ignore_class classname
|
110
|
+
ignored_classes[classname] = true
|
111
|
+
end
|
112
|
+
|
113
|
+
def log_file fname
|
114
|
+
ignored_files.delete fname
|
115
|
+
end
|
116
|
+
|
117
|
+
def log_method methname
|
118
|
+
ignored_methods.delete methname
|
119
|
+
end
|
120
|
+
|
121
|
+
def log_class classname
|
122
|
+
ignored_classes.delete classname
|
123
|
+
end
|
124
|
+
|
125
|
+
def debug msg = "", depth = 1, &blk
|
126
|
+
log msg, DEBUG, depth + 1, &blk
|
127
|
+
end
|
128
|
+
|
129
|
+
def info msg = "", depth = 1, &blk
|
130
|
+
log msg, INFO, depth + 1, &blk
|
131
|
+
end
|
132
|
+
|
133
|
+
def warn msg = "", depth = 1, &blk
|
134
|
+
log msg, WARN, depth + 1, &blk
|
135
|
+
end
|
136
|
+
|
137
|
+
def error msg = "", depth = 1, &blk
|
138
|
+
log msg, ERROR, depth + 1, &blk
|
139
|
+
end
|
140
|
+
|
141
|
+
def fatal msg = "", depth = 1, &blk
|
142
|
+
log msg, FATAL, depth + 1, &blk
|
143
|
+
end
|
144
|
+
|
145
|
+
# Logs the given message.
|
146
|
+
def log msg = "", lvl = DEBUG, depth = 1, cname = nil, &blk
|
147
|
+
if lvl >= level
|
148
|
+
frame = nil
|
149
|
+
|
150
|
+
stk = caller 0
|
151
|
+
stk.reverse.each_with_index do |frm, idx|
|
152
|
+
if frm.index(%r{logue/log.*:\d+:in\b})
|
153
|
+
break
|
154
|
+
else
|
155
|
+
frame = frm
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
print_stack_frame frame, cname, msg, lvl, &blk
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Shows the current stack.
|
164
|
+
def stack msg = "", lvl = DEBUG, depth = 1, cname = nil, &blk
|
165
|
+
if lvl >= level
|
166
|
+
stk = caller depth
|
167
|
+
for frame in stk
|
168
|
+
print_stack_frame frame, cname, msg, lvl, &blk
|
169
|
+
cname = nil
|
170
|
+
msg = ""
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def print_stack_frame frame, cname, msg, lvl, &blk
|
176
|
+
md = FRAME_RE.match frame
|
177
|
+
file, line, func = md[1], md[2], (md[3] || "")
|
178
|
+
# file.sub!(/.*\//, "")
|
179
|
+
|
180
|
+
# Ruby 1.9 expands the file name, but 1.8 doesn't:
|
181
|
+
pn = Pathname.new(file).expand_path
|
182
|
+
|
183
|
+
file = pn.to_s
|
184
|
+
|
185
|
+
if cname
|
186
|
+
func = cname + "#" + func
|
187
|
+
end
|
188
|
+
|
189
|
+
if ignored_files[file] || (cname && ignored_classes[cname]) || ignored_methods[func]
|
190
|
+
# skip this one.
|
191
|
+
else
|
192
|
+
print_formatted(file, line, func, msg, lvl, &blk)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def print_formatted file, line, func, msg, lvl, &blk
|
197
|
+
if trim
|
198
|
+
fmt = Format.new
|
199
|
+
file = fmt.trim_right file, @file_width
|
200
|
+
line = fmt.trim_left line, @line_width
|
201
|
+
func = fmt.trim_left func, @function_width
|
202
|
+
end
|
203
|
+
|
204
|
+
hdr = sprintf @format, file, line, func
|
205
|
+
print hdr, msg, lvl, &blk
|
206
|
+
end
|
207
|
+
|
208
|
+
def print hdr, msg, lvl, &blk
|
209
|
+
if blk
|
210
|
+
x = blk.call
|
211
|
+
if x.kind_of? String
|
212
|
+
msg = x
|
213
|
+
else
|
214
|
+
return
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
msg = msg.to_s.chomp
|
219
|
+
|
220
|
+
if lvlcol = @colors[lvl]
|
221
|
+
if colorize_line
|
222
|
+
line = hdr + " " + msg
|
223
|
+
@output.puts line.color(lvlcol)
|
224
|
+
else
|
225
|
+
@output.puts hdr + " " + msg.color(lvlcol)
|
226
|
+
end
|
227
|
+
else
|
228
|
+
@output.puts hdr + " " + msg
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def set_color lvl, color
|
233
|
+
@colors[lvl] = color
|
234
|
+
end
|
235
|
+
|
236
|
+
def method_missing meth, *args, &blk
|
237
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
238
|
+
# only handling foregrounds, not backgrounds
|
239
|
+
if code = validcolors[meth]
|
240
|
+
add_color_method meth.to_s, code + 30
|
241
|
+
send meth, *args, &blk
|
242
|
+
else
|
243
|
+
super
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def respond_to? meth
|
248
|
+
validcolors = Sickill::Rainbow::TERM_COLORS
|
249
|
+
validcolors.include?(meth) || super
|
250
|
+
end
|
251
|
+
|
252
|
+
def add_color_method color, code
|
253
|
+
instmeth = Array.new
|
254
|
+
instmeth << "def #{color}(msg = \"\", lvl = DEBUG, depth = 1, cname = nil, &blk)"
|
255
|
+
instmeth << " log(\"\\e[#{code}m\#{msg\}\\e[0m\", lvl, depth + 1, cname, &blk)"
|
256
|
+
instmeth << "end"
|
257
|
+
instance_eval instmeth.join("\n")
|
258
|
+
|
259
|
+
clsmeth = Array.new
|
260
|
+
clsmeth << "def #{color}(msg = \"\", lvl = DEBUG, depth = 1, cname = nil, &blk)"
|
261
|
+
clsmeth << " logger.#{color}(\"\\e[#{code}m\#{msg\}\\e[0m\", lvl, depth + 1, cname, &blk)"
|
262
|
+
clsmeth << "end"
|
263
|
+
|
264
|
+
class_eval clsmeth.join("\n")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
#
|
4
|
+
# = severity.rb
|
5
|
+
#
|
6
|
+
# Logging Module
|
7
|
+
#
|
8
|
+
# Author:: Jeff Pace <jpace@incava.org>
|
9
|
+
# Documentation:: Author
|
10
|
+
#
|
11
|
+
|
12
|
+
module Logue
|
13
|
+
class Log
|
14
|
+
module Severity
|
15
|
+
DEBUG = 0
|
16
|
+
INFO = 1
|
17
|
+
WARN = 2
|
18
|
+
ERROR = 3
|
19
|
+
FATAL = 4
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/logue.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
loguelibdir = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
$:.unshift(loguelibdir) unless
|
4
|
+
$:.include?(loguelibdir) || $:.include?(File.expand_path(loguelibdir))
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
rbre = Regexp.new('\.rb$')
|
9
|
+
|
10
|
+
Pathname.glob(loguelibdir + '/logue/**/*.rb').each do |file|
|
11
|
+
fname = file.sub(Regexp.new('^' + loguelibdir + '/'), '').sub(rbre, '')
|
12
|
+
require fname
|
13
|
+
end
|
14
|
+
|
15
|
+
module Logue
|
16
|
+
VERSION = '1.0.0'
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'stringio'
|
7
|
+
require 'logue/format'
|
8
|
+
require 'logue/loggable'
|
9
|
+
|
10
|
+
module Logue
|
11
|
+
class FormatTestCase < Test::Unit::TestCase
|
12
|
+
include Logue::Loggable
|
13
|
+
|
14
|
+
def run_trim_left_test expected, length, str = "something"
|
15
|
+
trimmed = Format.new.trim_left(str, length)
|
16
|
+
assert_equal expected, trimmed
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_trim_left_short_positive_number
|
20
|
+
run_trim_left_test "some", 4
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_trim_left_long
|
24
|
+
run_trim_left_test "something", 10
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_trim_left_short_negative_number
|
28
|
+
run_trim_left_test "some", -4
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_trim_right_test expected, length, str = "something"
|
32
|
+
trimmed = Format.new.trim_right(str, length)
|
33
|
+
assert_equal expected, trimmed
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_trim_right_short_positive_number
|
37
|
+
run_trim_right_test " ...", 5
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_trim_right_long
|
41
|
+
run_trim_right_test "something", 10
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_trim_right_short_negative_number
|
45
|
+
run_trim_right_test " ...", -5
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'stringio'
|
7
|
+
require 'logue'
|
8
|
+
|
9
|
+
include Logue
|
10
|
+
|
11
|
+
class LogAbyss
|
12
|
+
include Loggable
|
13
|
+
|
14
|
+
def squeal
|
15
|
+
log "hello from the abyss"
|
16
|
+
stack "turtles all the way down"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class LogDepths
|
21
|
+
include Loggable
|
22
|
+
|
23
|
+
def speak
|
24
|
+
log "hello from the depths"
|
25
|
+
la = LogAbyss.new
|
26
|
+
la.squeal
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class LogInner
|
31
|
+
include Loggable
|
32
|
+
|
33
|
+
def screech
|
34
|
+
ldi = LogDepths.new
|
35
|
+
log "hello from the innerds"
|
36
|
+
ldi.speak
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class LogStackTestCase < Test::Unit::TestCase
|
41
|
+
include Loggable
|
42
|
+
|
43
|
+
def test_stack
|
44
|
+
Log.set_widths(-15, 4, -40)
|
45
|
+
|
46
|
+
log = Proc.new {
|
47
|
+
li = LogInner.new
|
48
|
+
li.screech
|
49
|
+
}
|
50
|
+
|
51
|
+
expected_output = [
|
52
|
+
"[ ...: 35] {LogInner#screech } hello from the innerds",
|
53
|
+
"[ ...: 24] {LogDepths#speak } hello from the depths",
|
54
|
+
"[ ...: 15] {LogAbyss#squeal } hello from the abyss",
|
55
|
+
"[ ...: 16] {LogAbyss#squeal } turtles all the way down",
|
56
|
+
"[ ...: 26] {speak } ",
|
57
|
+
"[ ...: 36] {screech } ",
|
58
|
+
]
|
59
|
+
|
60
|
+
run_test @verbose_setup, log, *expected_output
|
61
|
+
end
|
62
|
+
|
63
|
+
# the ctor is down here so the lines above are less likely to change.
|
64
|
+
def initialize test, name = nil
|
65
|
+
@nonverbose_setup = Proc.new {
|
66
|
+
Log.verbose = false
|
67
|
+
Log.output = StringIO.new
|
68
|
+
}
|
69
|
+
|
70
|
+
@verbose_setup = Proc.new {
|
71
|
+
Log.verbose = true
|
72
|
+
Log.output = StringIO.new
|
73
|
+
}
|
74
|
+
|
75
|
+
super test
|
76
|
+
end
|
77
|
+
|
78
|
+
def run_test setup, log, *expected
|
79
|
+
io = setup.call
|
80
|
+
|
81
|
+
log.call
|
82
|
+
|
83
|
+
assert_not_nil io
|
84
|
+
str = io.string
|
85
|
+
assert_not_nil str
|
86
|
+
|
87
|
+
lines = str.split "\n"
|
88
|
+
|
89
|
+
(0 ... expected.size).each do |idx|
|
90
|
+
if expected[idx]
|
91
|
+
assert_equal expected[idx], lines[idx], "index: #{idx}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Log.output = io
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'stringio'
|
7
|
+
require 'logue/loggable'
|
8
|
+
require 'logue/testlog/logtestee'
|
9
|
+
|
10
|
+
include Logue
|
11
|
+
|
12
|
+
class LogTestCase < Test::Unit::TestCase
|
13
|
+
include Loggable
|
14
|
+
|
15
|
+
def run_log_testee_test(methname, expected, &blk)
|
16
|
+
Log.verbose = true
|
17
|
+
io = StringIO.new
|
18
|
+
Log.output = io
|
19
|
+
Log.set_default_widths
|
20
|
+
|
21
|
+
blk.call if blk
|
22
|
+
|
23
|
+
lt = LogTestee.new
|
24
|
+
lt.send methname
|
25
|
+
|
26
|
+
str = io.string
|
27
|
+
|
28
|
+
lines = str.split "\n"
|
29
|
+
|
30
|
+
(0 ... expected.size).each do |idx|
|
31
|
+
if expected[idx]
|
32
|
+
assert_equal expected[idx], lines[idx], "index: #{idx}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Log.set_default_widths
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_format_test(expected, &blk)
|
40
|
+
Log.verbose = true
|
41
|
+
io = StringIO.new
|
42
|
+
Log.output = io
|
43
|
+
Log.set_default_widths
|
44
|
+
|
45
|
+
blk.call
|
46
|
+
|
47
|
+
lt = LogTestee.new
|
48
|
+
lt.format_test
|
49
|
+
|
50
|
+
assert_equal expected.join(''), io.string
|
51
|
+
|
52
|
+
Log.set_default_widths
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_no_output
|
56
|
+
run_log_testee_test(:log_all, Array.new) do
|
57
|
+
Log.verbose = false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def msg lnum, methname, msg
|
62
|
+
sprintf("[ ...testlog/logtestee.rb: %2d] {%-20s} %s", 16 + lnum, methname[0 .. 19], msg)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_output_arg
|
66
|
+
methname = "log_all"
|
67
|
+
|
68
|
+
expected = Array.new
|
69
|
+
(1 .. 6).each do |lnum|
|
70
|
+
msg = "hello, world?"
|
71
|
+
if lnum == 4 || lnum == 5
|
72
|
+
msg = "EXPECTED OUTPUT TO STDERR: hello, world."
|
73
|
+
end
|
74
|
+
expected << sprintf("[ ...testlog/logtestee.rb: %2d] {%-20s} %s", 16 + lnum, methname[0 .. 19], msg)
|
75
|
+
end
|
76
|
+
|
77
|
+
run_log_testee_test(:log_all, expected)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_output_block_at_level
|
81
|
+
Log.level = Log::DEBUG
|
82
|
+
|
83
|
+
methname = "log_block"
|
84
|
+
|
85
|
+
msg = "block party"
|
86
|
+
|
87
|
+
expected = Array.new
|
88
|
+
expected << sprintf("[ ...testlog/logtestee.rb: %2d] {%-20s} %s", 26, methname[0 .. 19], msg)
|
89
|
+
|
90
|
+
run_log_testee_test(:log_block, expected)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_output_block_below_level
|
94
|
+
expected = Array.new
|
95
|
+
|
96
|
+
run_log_testee_test(:log_block, expected) do
|
97
|
+
Log.level = Log::INFO
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_colors_foreground
|
102
|
+
methname = "log_foregrounds"
|
103
|
+
expected = Array.new
|
104
|
+
expected << sprintf("[ ...testlog/logtestee.rb: %2d] {%-20s} %s", 30, methname[0 .. 19], "\e[37mwhite wedding\e[0m")
|
105
|
+
expected << sprintf("[ ...testlog/logtestee.rb: %2d] {%-20s} %s", 31, methname[0 .. 19], "\e[34mblue iris\e[0m")
|
106
|
+
|
107
|
+
run_log_testee_test(:log_foregrounds, expected)
|
108
|
+
end
|
109
|
+
|
110
|
+
def xxxtest_colors_background
|
111
|
+
expected = Array.new
|
112
|
+
expected << "[ ...test/logue/log_test.rb: 109] {LogTestCase#test_col} \e[46mred\e[0m"
|
113
|
+
|
114
|
+
run_log_testee_test(:log_foregrounds, expected) do
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_format_default
|
119
|
+
expected = Array.new
|
120
|
+
expected << "[ ...testlog/logtestee.rb: 10] {format_test } tamrof\n"
|
121
|
+
|
122
|
+
run_format_test expected do
|
123
|
+
Log.set_default_widths
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_format_flush_filename_left
|
128
|
+
expected = Array.new
|
129
|
+
expected << "[ ...test/logue/testlog/logtestee.rb: 10] {format_test } tamrof\n"
|
130
|
+
|
131
|
+
run_format_test expected do
|
132
|
+
Log.set_widths(-35, Log::DEFAULT_LINENUM_WIDTH, Log::DEFAULT_FUNCTION_WIDTH)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_format_flush_linenum_left
|
137
|
+
expected = Array.new
|
138
|
+
expected << "[ ...testlog/logtestee.rb:10 ] {format_test } tamrof\n"
|
139
|
+
|
140
|
+
run_format_test expected do
|
141
|
+
Log.set_widths(Log::DEFAULT_FILENAME_WIDTH, -10, Log::DEFAULT_FUNCTION_WIDTH)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_format_flush_function_right
|
146
|
+
expected = Array.new
|
147
|
+
expected << "[ ...testlog/logtestee.rb: 10] { format_test} tamrof\n"
|
148
|
+
|
149
|
+
run_format_test expected do
|
150
|
+
Log.set_widths(Log::DEFAULT_FILENAME_WIDTH, Log::DEFAULT_LINENUM_WIDTH, 35)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_format_pad_linenum_zeros
|
155
|
+
expected = Array.new
|
156
|
+
expected << "[ ...testlog/logtestee.rb:00000010] {format_test } tamrof\n"
|
157
|
+
|
158
|
+
run_format_test expected do
|
159
|
+
Log.set_widths(Log::DEFAULT_FILENAME_WIDTH, "08", Log::DEFAULT_FUNCTION_WIDTH)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_respond_to_color
|
164
|
+
assert Log.respond_to? :blue
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'stringio'
|
7
|
+
require 'logue/log'
|
8
|
+
require 'logue/loggable'
|
9
|
+
require 'logue/testlog/lgbl_testee'
|
10
|
+
|
11
|
+
class LoggableTestCase < Test::Unit::TestCase
|
12
|
+
include Logue::Loggable
|
13
|
+
|
14
|
+
def test_instance_colors
|
15
|
+
Logue::Log.verbose = true
|
16
|
+
io = StringIO.new
|
17
|
+
Logue::Log.output = io
|
18
|
+
|
19
|
+
expected = Array.new
|
20
|
+
expected << "[...testlog/lgbl_testee.rb: 11] {LgblTestee#crystal } hello!\n"
|
21
|
+
expected << "[...testlog/lgbl_testee.rb: 12] {LgblTestee#crystal } [34mazul ... [0m\n"
|
22
|
+
expected << "[...testlog/lgbl_testee.rb: 13] {LgblTestee#crystal } [31mrojo?[0m\n"
|
23
|
+
|
24
|
+
te = LgblTestee.new
|
25
|
+
te.crystal
|
26
|
+
|
27
|
+
# puts io.string
|
28
|
+
|
29
|
+
assert_equal expected.join(''), io.string
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeff Pace
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rainbow
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.1.4
|
30
|
+
description: A module that adds logging/trace functionality.
|
31
|
+
email: jeugenepace@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README.md
|
36
|
+
files:
|
37
|
+
- lib/logue.rb
|
38
|
+
- lib/logue/format.rb
|
39
|
+
- lib/logue/log.rb
|
40
|
+
- lib/logue/loggable.rb
|
41
|
+
- lib/logue/logger.rb
|
42
|
+
- lib/logue/severity.rb
|
43
|
+
- test/logue/format_test.rb
|
44
|
+
- test/logue/testlog/log_stack_test.rb
|
45
|
+
- test/logue/testlog/log_test.rb
|
46
|
+
- test/logue/testlog/loggable_test.rb
|
47
|
+
- README.md
|
48
|
+
homepage: http://jeugenepace.github.com/logue
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.23
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A minimalist logging module.
|
72
|
+
test_files:
|
73
|
+
- test/logue/format_test.rb
|
74
|
+
- test/logue/testlog/log_stack_test.rb
|
75
|
+
- test/logue/testlog/log_test.rb
|
76
|
+
- test/logue/testlog/loggable_test.rb
|