tagged_logger 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.markdown +40 -4
- data/README.html +67 -28
- data/README.markdown +64 -33
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/examples/changing_format.rb +12 -0
- data/examples/one_log_per_classes.rb +24 -6
- data/examples/one_tag_per_classes.rb +11 -6
- data/examples/per_class_customization.rb +11 -8
- data/examples/rule_with_regex.rb +4 -1
- data/examples/simplest_usage.rb +6 -5
- data/lib/tagged_logger.rb +51 -32
- data/tagged_logger.gemspec +7 -4
- data/test/expected_examples_output.txt +39 -0
- data/test/test.rb +73 -67
- data/test/test_examples.rb +8 -0
- data/todo.txt +5 -19
- metadata +6 -3
- data/examples/simplest_customization.rb +0 -10
data/CHANGES.markdown
CHANGED
@@ -2,12 +2,48 @@
|
|
2
2
|
|
3
3
|
## Version 0.2.5
|
4
4
|
|
5
|
-
* If somebody is not ready to define any logging rules, but still want to use
|
5
|
+
* If somebody is not ready to define any logging rules, but still want to use *#logger()* everywhere:
|
6
6
|
|
7
|
-
|
7
|
+
TaggedLogger.init
|
8
8
|
|
9
|
-
* Runs about 3 times faster by executing code responsible for rule matching
|
10
|
-
So rather than iterating over **all** rules on every _#logger_ call only subset of rules specific to
|
9
|
+
* Runs about 3 times faster by executing code responsible for rule matching on the first *#logger()* call and "precompiling" it.
|
10
|
+
So rather than iterating over **all** rules on every _#logger_ call only subset of rules specific to *#logger()* callee get executed.
|
11
11
|
|
12
12
|
* Code simplified
|
13
13
|
|
14
|
+
## Version 0.3.0
|
15
|
+
|
16
|
+
* The DSL for defining rules is changed - instead of
|
17
|
+
|
18
|
+
output /A/ => ...
|
19
|
+
|
20
|
+
use one of:
|
21
|
+
|
22
|
+
debug /A/, :to => ...
|
23
|
+
info /A/, :to => ...
|
24
|
+
warn /A/, :to => ...
|
25
|
+
error /A/, :to => ...
|
26
|
+
fatal /A/, :to => ...
|
27
|
+
|
28
|
+
and instead of
|
29
|
+
|
30
|
+
output /A/ do
|
31
|
+
#...
|
32
|
+
end
|
33
|
+
|
34
|
+
use
|
35
|
+
|
36
|
+
debug /A/ do #or #info, #warn, #error, #fatal
|
37
|
+
#...
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
These rules are more specific since they name logging level explictly which makes DSL shorter,
|
42
|
+
also such form has allowed to make some optimization.
|
43
|
+
|
44
|
+
* The *#format()* could be used inside *rules* block:
|
45
|
+
|
46
|
+
TaggedLogger.rules do
|
47
|
+
format { |level, tag, msg| "#{level}-#{tag}: #{msg}\n"}
|
48
|
+
info /.*/, :to => Logger.new(STDOUT)
|
49
|
+
end
|
data/README.html
CHANGED
@@ -11,11 +11,11 @@
|
|
11
11
|
|
12
12
|
<h2 id='what_is_it_for'>What is it for?</h2>
|
13
13
|
|
14
|
-
<p>
|
14
|
+
<p>Every time you want to log something, simply write:</p>
|
15
15
|
|
16
|
-
<pre><code>logger.debug("verbose debug information") #warn, #info, #error, #fatal also
|
16
|
+
<pre><code>logger.debug("verbose debug information") #warn, #info, #error, #fatal also works</code></pre>
|
17
17
|
|
18
|
-
<p>and do not worry about what kind of logger you use and how your code accesses it. You may
|
18
|
+
<p>and do not worry about what kind of logger you use and how your code accesses it. You may configure these things later, one day writing to STDOUT works for you, another day you’ll need something more sophisticated, like several log files each serving different components and for different audience.</p>
|
19
19
|
|
20
20
|
<h2 id='installation'>Installation</h2>
|
21
21
|
|
@@ -23,69 +23,108 @@
|
|
23
23
|
|
24
24
|
<h2 id='usage'>Usage</h2>
|
25
25
|
|
26
|
-
<p>
|
26
|
+
<p>After specifying some logging rules:</p>
|
27
27
|
|
28
28
|
<pre><code>TaggedLogger.rules do
|
29
|
-
|
29
|
+
info A, :to => Logger.new("log_for_A_class.log") #1 rule
|
30
|
+
error /.*/, :to => Logger.new(ERROR) #2 rule
|
31
|
+
info /.*/, :to => Logger.new(STDOUT) #3 rule
|
30
32
|
end</code></pre>
|
31
33
|
|
32
|
-
<p>
|
34
|
+
<p>the following will happen:</p>
|
33
35
|
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
<ol>
|
37
|
+
<li>
|
38
|
+
<p>The <em>#logger()</em> method becomes available <strong>everywhere</strong>, so it is completely safe to have a code like:</p>
|
39
|
+
|
40
|
+
<pre><code> class A
|
41
|
+
def foo
|
42
|
+
logger.info("Something interesting happened in A#foo") #goes to STDOUT and to 'log_for_A_class.log' file
|
43
|
+
logger.debug("I want to see some details.") #goes nowhere
|
44
|
+
end
|
45
|
+
end
|
46
|
+
logger.error("#logger is available everywhere") #goes to STDERR
|
47
|
+
class B
|
48
|
+
logger.warn("#logger is available everywhere") #goes to STDOUT
|
49
|
+
end </code></pre>
|
50
|
+
</li>
|
51
|
+
|
52
|
+
<li>
|
53
|
+
<p>The A’s <em>logger.info()</em> output will show up in two destinations:</p>
|
54
|
+
|
55
|
+
<ul>
|
56
|
+
<li>
|
57
|
+
<p>in STDOUT, as defined by rule #3</p>
|
58
|
+
</li>
|
59
|
+
|
60
|
+
<li>
|
61
|
+
<p>in ‘log_for_A_class.log’ file, as defined by rule #1</p>
|
62
|
+
</li>
|
63
|
+
</ul>
|
64
|
+
</li>
|
39
65
|
|
40
|
-
<
|
66
|
+
<li>
|
67
|
+
<p>From <strong>wherever</strong> it gets called from:</p>
|
41
68
|
|
42
|
-
<pre><code>
|
69
|
+
<pre><code> logger.error("ERROR") #will print 'ERROR' in standard error
|
70
|
+
logger.info("INFO") #will print 'INFO' in standard output
|
71
|
+
logger.debug("DEBUG") #will not print anything, since there is no 'debug' rule</code></pre>
|
72
|
+
</li>
|
73
|
+
</ol>
|
43
74
|
|
44
|
-
<p>
|
75
|
+
<p>The <em>#logger()</em> returns some object having methods: <em>#debug(), #info(), #warn(), #error() and #fatal()</em>. These method have generated on first <em>#logger()</em> call and contain only necessary code to meet rules. It means, for example, that if no rules defined all these methods do nothing. It is done for performance reasons, I like to log a lot and I do not want calls like <em>#logger.debug()</em> slowing down production code.</p>
|
45
76
|
|
46
|
-
<
|
77
|
+
<p>The simplest way to have a <em>#logger()</em> available everywhere without specifying any rules is:</p>
|
78
|
+
|
79
|
+
<pre><code>TaggedLogger.init</code></pre>
|
80
|
+
|
81
|
+
<p>No rules specified, therefore whenever you call <em>logger.debug()</em> (or alike) you actually paying for just an empty method execution. You may specify rules later, now you may stay focused on code you are writing.</p>
|
47
82
|
|
48
83
|
<p>You may define your own formatting:</p>
|
49
84
|
|
50
85
|
<pre><code>TaggedLogger.rules do
|
51
|
-
|
52
|
-
puts "#{level}-#{tag}: #{msg}"
|
53
|
-
end
|
86
|
+
format {|level, tag, message| "#{level}-#{tag}: #{msg}"}
|
54
87
|
end</code></pre>
|
55
88
|
|
56
|
-
<p>
|
89
|
+
<p>Each <em>#format()</em> call overrides previous format. If you are wondering what the heck the ‘tag’ is - the answer is simple. The tag is a class name whose method calls <em>#logger()</em>. This is what allows to specify rules for classes or namespaces and this is what the <em>tagged_logger</em> plugin is named after.</p>
|
57
90
|
|
58
|
-
<p>
|
91
|
+
<p>Lets see how you may use it. For example you want to have separate log files for classes <em>Network</em> and <em>Database</em>:</p>
|
59
92
|
|
60
93
|
<pre><code>TaggedLogger.rules do
|
61
|
-
|
62
|
-
|
94
|
+
debug Network, :to => Logger.new("network.log")
|
95
|
+
debug Database, :to => Logger.new("database.log")
|
63
96
|
end</code></pre>
|
64
97
|
|
65
98
|
<p>In case you want to define common log for several classes:</p>
|
66
99
|
|
67
100
|
<pre><code>TaggedLogger.rules do
|
68
|
-
|
101
|
+
debug [Ftp, Http, Sockets], :to => Logger.new("network.log")
|
69
102
|
end </code></pre>
|
70
103
|
|
71
104
|
<p>Or if you want to have all these classes showing up under common tag <em>Network</em> in standard output:</p>
|
72
105
|
|
73
106
|
<pre><code>TaggedLogger.rules do
|
74
|
-
|
107
|
+
info /.*/, :to => Logger.new(STDOUT)
|
75
108
|
rename [Ftp, Http, Sockets] => :Network
|
76
109
|
end</code></pre>
|
77
110
|
|
78
111
|
<p>You may also use regular expressions in your rules:</p>
|
79
112
|
|
80
113
|
<pre><code>TaggedLogger.rules do
|
81
|
-
|
114
|
+
info /Active::/, :to => Logger.new("active.log")
|
82
115
|
end</code></pre>
|
83
116
|
|
84
117
|
<h2 id='license'>License</h2>
|
85
118
|
|
86
|
-
<p>TaggedLogger is released under the MIT license.</p>
|
119
|
+
<p><em>TaggedLogger</em> is released under the MIT license.</p>
|
120
|
+
|
121
|
+
<h2 id='shortcomings'>Shortcomings</h2>
|
87
122
|
|
88
|
-
<
|
123
|
+
<p>The <em>#info(), #debug(), #warn(), #error(), #fatal()</em> rules when have form like <em>:to => logger</em>, the <em>logger</em> <strong>has</strong> to be an object of standard library <em>Logger</em> class. If you need to use different sort of logger the more general rules form could is:</p>
|
89
124
|
|
90
|
-
<
|
125
|
+
<pre><code>TaggedLogger.rules do
|
126
|
+
info /Whatever/ do |level, tag, message|
|
127
|
+
#do your special logging here
|
128
|
+
end
|
129
|
+
end</code></pre>
|
91
130
|
</body></html>
|
data/README.markdown
CHANGED
@@ -4,7 +4,7 @@ Detaches **what** is logged from **how** it is logged.
|
|
4
4
|
## What is it for?
|
5
5
|
Every time you want to log something, simply write:
|
6
6
|
|
7
|
-
logger.debug("verbose debug information") #warn, #info, #error, #fatal also
|
7
|
+
logger.debug("verbose debug information") #warn, #info, #error, #fatal also works
|
8
8
|
|
9
9
|
and do not worry about what kind of logger you use and how your code accesses it.
|
10
10
|
You may configure these things later, one day writing to STDOUT works for you, another
|
@@ -16,75 +16,106 @@ different components and for different audience.
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
After specifying some logging rules:
|
20
|
+
|
21
21
|
TaggedLogger.rules do
|
22
|
-
|
22
|
+
info A, :to => Logger.new("log_for_A_class.log") #1 rule
|
23
|
+
error /.*/, :to => Logger.new(ERROR) #2 rule
|
24
|
+
info /.*/, :to => Logger.new(STDOUT) #3 rule
|
23
25
|
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
the following will happen:
|
28
|
+
|
29
|
+
1. The *#logger()* method becomes available **everywhere**, so it is completely safe to have a code like:
|
30
|
+
|
31
|
+
class A
|
32
|
+
def foo
|
33
|
+
logger.info("Something interesting happened in A#foo") #goes to STDOUT and to 'log_for_A_class.log' file
|
34
|
+
logger.debug("I want to see some details.") #goes nowhere
|
35
|
+
end
|
36
|
+
end
|
37
|
+
logger.error("#logger is available everywhere") #goes to STDERR
|
38
|
+
class B
|
39
|
+
logger.warn("#logger is available everywhere") #goes to STDOUT
|
40
|
+
end
|
41
|
+
|
42
|
+
2. The A's *logger.info()* output will show up in two destinations:
|
43
|
+
|
44
|
+
- in STDOUT, as defined by rule #3
|
45
|
+
|
46
|
+
- in 'log_for_A_class.log' file, as defined by rule #1
|
32
47
|
|
33
|
-
|
48
|
+
3. From **wherever** it gets called from:
|
34
49
|
|
35
|
-
|
50
|
+
logger.error("ERROR") #will print 'ERROR' in standard error
|
51
|
+
logger.info("INFO") #will print 'INFO' in standard output
|
52
|
+
logger.debug("DEBUG") #will not print anything, since there is no 'debug' rule
|
36
53
|
|
37
|
-
you will see somewhat like:
|
38
54
|
|
39
|
-
|
55
|
+
The *#logger()* returns some object having methods: *#debug(), #info(), #warn(), #error() and #fatal()*.
|
56
|
+
These methods have generated on first *#logger()* call and contain only necessary code to meet rules.
|
57
|
+
It means, for example, that if no rules defined all these methods do nothing. It is done for performance
|
58
|
+
reasons, I like to log a lot and I do not want calls like *#logger.debug()* slowing down production code.
|
59
|
+
|
60
|
+
|
61
|
+
The simplest way to have a *#logger()* available everywhere without specifying any rules is:
|
62
|
+
|
63
|
+
TaggedLogger.init
|
64
|
+
|
65
|
+
No rules specified, therefore whenever you call *logger.debug()* (or alike) you actually paying for just an empty method
|
66
|
+
execution. You may specify rules later, now you may stay focused on code you are writing.
|
40
67
|
|
41
68
|
|
42
69
|
You may define your own formatting:
|
43
70
|
|
44
71
|
TaggedLogger.rules do
|
45
|
-
|
46
|
-
puts "#{level}-#{tag}: #{msg}"
|
47
|
-
end
|
72
|
+
format {|level, tag, message| "#{level}-#{tag}: #{msg}"}
|
48
73
|
end
|
49
74
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
calls *#logger*. Note the *#logger* does not have *tag* parameter - tags defined automatically
|
55
|
-
and they are always class names.
|
56
|
-
|
75
|
+
Each *#format()* call overrides previous format.
|
76
|
+
If you are wondering what the heck the 'tag' is - the answer is simple. The tag is a class name
|
77
|
+
whose method calls *#logger()*. This is what allows to specify rules for classes or namespaces and this
|
78
|
+
is what the *tagged_logger* plugin is named after.
|
57
79
|
|
58
|
-
|
80
|
+
Lets see how you may use it. For example you want to have separate log files
|
81
|
+
for classes *Network* and *Database*:
|
59
82
|
|
60
83
|
TaggedLogger.rules do
|
61
|
-
|
62
|
-
|
84
|
+
debug Network, :to => Logger.new("network.log")
|
85
|
+
debug Database, :to => Logger.new("database.log")
|
63
86
|
end
|
64
87
|
|
65
88
|
In case you want to define common log for several classes:
|
66
89
|
|
67
90
|
TaggedLogger.rules do
|
68
|
-
|
91
|
+
debug [Ftp, Http, Sockets], :to => Logger.new("network.log")
|
69
92
|
end
|
70
93
|
|
71
94
|
Or if you want to have all these classes showing up under common
|
72
95
|
tag *Network* in standard output:
|
73
96
|
|
74
97
|
TaggedLogger.rules do
|
75
|
-
|
98
|
+
info /.*/, :to => Logger.new(STDOUT)
|
76
99
|
rename [Ftp, Http, Sockets] => :Network
|
77
100
|
end
|
78
101
|
|
79
102
|
You may also use regular expressions in your rules:
|
80
103
|
|
81
104
|
TaggedLogger.rules do
|
82
|
-
|
105
|
+
info /Active::/, :to => Logger.new("active.log")
|
83
106
|
end
|
84
107
|
|
85
108
|
|
86
109
|
## License
|
87
|
-
TaggedLogger is released under the MIT license.
|
110
|
+
*TaggedLogger* is released under the MIT license.
|
88
111
|
|
89
112
|
## Shortcomings
|
90
|
-
|
113
|
+
The *#info(), #debug(), #warn(), #error(), #fatal()* rules when having form like *:to => logger*, the
|
114
|
+
*logger* **has** to be an object of standard library *Logger* class. If you need to use different sort of logger
|
115
|
+
the more general rules form is:
|
116
|
+
|
117
|
+
TaggedLogger.rules do
|
118
|
+
info /Whatever/ do |level, tag, message|
|
119
|
+
#do your special logging here
|
120
|
+
end
|
121
|
+
end
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake/rdoctask'
|
|
4
4
|
|
5
5
|
Rake::TestTask.new do |t|
|
6
6
|
t.libs << "test"
|
7
|
-
t.test_files = FileList['test/test.rb']
|
7
|
+
t.test_files = FileList['test/test.rb', 'test/test_examples.rb']
|
8
8
|
t.verbose = true
|
9
9
|
end
|
10
10
|
|
@@ -16,7 +16,7 @@ begin
|
|
16
16
|
s.email = "fkocherga@gmail.com"
|
17
17
|
s.homepage = "http://github.com/fkocherga/tagged_logger"
|
18
18
|
s.authors = ["Fedor Kocherga"]
|
19
|
-
s.test_files = ['test/test.rb']
|
19
|
+
s.test_files = ['test/test.rb', 'test/test_examples.rb']
|
20
20
|
end
|
21
21
|
Jeweler::GemcutterTasks.new
|
22
22
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'tagged_logger'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
7
|
+
TaggedLogger.rules do
|
8
|
+
format { |level, tag, msg| "#{level}-#{tag}: #{msg}\n"}
|
9
|
+
info /.*/, :to => Logger.new(STDOUT)
|
10
|
+
end
|
11
|
+
|
12
|
+
logger.info("message")
|
@@ -2,18 +2,36 @@ require 'rubygems'
|
|
2
2
|
require 'tagged_logger'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
5
7
|
class LogFoo
|
6
8
|
def foo
|
7
|
-
logger.info("foo")
|
9
|
+
logger.info("#{self.class}#foo")
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
module Network
|
14
|
+
Ftp = Class.new LogFoo
|
15
|
+
Http = Class.new LogFoo
|
16
|
+
Sockets = Class.new LogFoo
|
17
|
+
end
|
18
|
+
include Network
|
19
|
+
|
20
|
+
def run
|
21
|
+
[Network::Ftp, Network::Http, Network::Sockets, LogFoo].each { |c| c.new.foo }
|
22
|
+
end
|
14
23
|
|
15
24
|
TaggedLogger.rules do
|
16
|
-
|
25
|
+
stdout = Logger.new(STDOUT)
|
26
|
+
puts "- Only logging from within classes Ftp, Http and Sockets will be shown in output (no LogFoo):"
|
27
|
+
info [Ftp, Http, Sockets], :to => stdout
|
28
|
+
run
|
29
|
+
puts "\n- Same result, but regex syntax:"
|
30
|
+
info /(Ftp|Http|Sockets)/, :to => stdout
|
31
|
+
run
|
32
|
+
puts "\n- Or even shorter:"
|
33
|
+
info /Network::/, :to => stdout
|
34
|
+
run
|
17
35
|
end
|
18
36
|
|
19
|
-
|
37
|
+
|
@@ -2,20 +2,25 @@ require 'rubygems'
|
|
2
2
|
require 'tagged_logger'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
-
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
7
|
+
class LogFoo
|
6
8
|
def foo
|
7
9
|
logger.info("#{self.class}#foo")
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
Ftp = Class.new
|
12
|
-
Http = Class.new
|
13
|
-
Sockets = Class.new
|
13
|
+
Ftp = Class.new LogFoo
|
14
|
+
Http = Class.new LogFoo
|
15
|
+
Sockets = Class.new LogFoo
|
14
16
|
|
15
17
|
TaggedLogger.rules do
|
18
|
+
format { |level, tag, message| "#{tag}: #{message}\n"}
|
19
|
+
puts "- Only logging from within classes Ftp, Http and Sockets will be shown in output (no LogFoo)"
|
20
|
+
puts " tag is also printed and it is 'Network' after renaming took place:"
|
16
21
|
rename [Ftp, Http, Sockets] => :Network
|
17
|
-
|
22
|
+
info :Network, :to => Logger.new(STDOUT)
|
18
23
|
end
|
19
24
|
|
20
|
-
[Ftp, Http, Sockets].each { |c| c.new.foo }
|
25
|
+
[Ftp, Http, Sockets, LogFoo].each { |c| c.new.foo }
|
21
26
|
|
@@ -2,19 +2,22 @@ require 'rubygems'
|
|
2
2
|
require 'tagged_logger'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
-
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
7
|
+
class Some
|
6
8
|
def foo
|
7
|
-
logger.info("
|
9
|
+
logger.info("Some information")
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
Database = Class.new LogFoo
|
12
|
-
Network = Class.new LogFoo
|
13
13
|
|
14
14
|
TaggedLogger.rules do
|
15
|
-
|
16
|
-
|
15
|
+
format { |level, tag, message| "#{tag}: #{message}\n"}
|
16
|
+
puts "- Only logging for Some class is shown in STDOUT"
|
17
|
+
puts "- Run this script again by adding '2>/dev/null' and see the difference:"
|
18
|
+
info /.*/, :to => Logger.new(STDERR)
|
19
|
+
info Some, :to => Logger.new(STDOUT)
|
17
20
|
end
|
18
21
|
|
19
|
-
|
20
|
-
|
22
|
+
Some.new.foo
|
23
|
+
logger.info "INFO"
|
data/examples/rule_with_regex.rb
CHANGED
@@ -2,6 +2,8 @@ require 'rubygems'
|
|
2
2
|
require 'tagged_logger'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
5
7
|
module Active
|
6
8
|
class Base
|
7
9
|
def foo
|
@@ -11,7 +13,8 @@ module Active
|
|
11
13
|
end
|
12
14
|
|
13
15
|
TaggedLogger.rules do
|
14
|
-
|
16
|
+
puts "- The recommended way to specify logging for all classes within same namespace:"
|
17
|
+
info /Active::/, :to => Logger.new(STDOUT)
|
15
18
|
end
|
16
19
|
|
17
20
|
Active::Base.new.foo
|
data/examples/simplest_usage.rb
CHANGED
@@ -2,17 +2,18 @@ require 'rubygems'
|
|
2
2
|
require 'tagged_logger'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
+
puts "\n<<<#{File.basename(__FILE__, ".rb")}>>> \n".upcase
|
6
|
+
|
5
7
|
TaggedLogger.rules do
|
6
|
-
|
8
|
+
info /.*/, :to => Logger.new(STDOUT)
|
7
9
|
end
|
8
10
|
|
9
11
|
class A
|
10
12
|
def foo
|
11
|
-
logger.warn "
|
13
|
+
logger.warn "WARNING message" #will be printed since treshold is set to 'info'
|
12
14
|
end
|
13
|
-
logger.debug "
|
15
|
+
logger.debug "DEBUG message" #will not be printed since we have only 'info' rule
|
14
16
|
end
|
15
17
|
|
16
|
-
|
17
|
-
logger.info("Hello word!")
|
18
|
+
logger.info("INFO message") #will be printed
|
18
19
|
A.new.foo
|
data/lib/tagged_logger.rb
CHANGED
@@ -10,16 +10,18 @@ class TaggedLogger
|
|
10
10
|
@rename_rules = Dictionary.new
|
11
11
|
@tag_blocks = Dictionary.new
|
12
12
|
ObjectSpace.each_object(ClassSpecificLogger) { |obj| obj.detach }
|
13
|
+
init
|
13
14
|
end
|
14
15
|
|
15
16
|
def rules(&block)
|
17
|
+
add_logger_generator_in_Kernel
|
16
18
|
instance_eval(&block)
|
17
19
|
end
|
18
20
|
|
19
|
-
def blocks_for(tag)
|
21
|
+
def blocks_for(level, tag)
|
20
22
|
blocks = []
|
21
23
|
tag_aliases(tag) do |tag_alias|
|
22
|
-
tag_blocks(tag_alias) do |tag_block|
|
24
|
+
tag_blocks(level, tag_alias) do |tag_block|
|
23
25
|
blocks << [tag_alias, tag_block]
|
24
26
|
end
|
25
27
|
end
|
@@ -27,46 +29,63 @@ class TaggedLogger
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def init
|
30
|
-
|
32
|
+
rules {}
|
31
33
|
end
|
32
34
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
output &block if block
|
39
|
-
end
|
35
|
+
def debug(what, where = {}, &block) output(:debug, what, where, &block) end
|
36
|
+
def info(what, where = {}, &block) output(:info, what, where, &block) end
|
37
|
+
def warn(what, where = {}, &block) output(:wanr, what, where, &block) end
|
38
|
+
def error(what, where = {}, &block) output(:error, what, where, &block) end
|
39
|
+
def fatal(what, where = {}, &block) output(:fatal, what, where, &block) end
|
40
40
|
|
41
|
-
def
|
42
|
-
|
43
|
-
if spec.is_a? Hash
|
44
|
-
spec.each do |what, where|
|
45
|
-
@tag_blocks[tag_matcher(what)] = lambda { |level, tag, msg | where.send(level, "#{tag}: #{msg}\n") }
|
46
|
-
end
|
47
|
-
raise ArgumentError "No block should be specified in this 'output' rule" if block
|
48
|
-
else
|
49
|
-
raise ArgumentError "Block has to be specified in this 'output' rule" unless block
|
50
|
-
@tag_blocks[tag_matcher(spec)] = block
|
51
|
-
end
|
41
|
+
def format(&block)
|
42
|
+
@formatter = block
|
52
43
|
end
|
53
|
-
|
44
|
+
|
45
|
+
def formatter
|
46
|
+
@formatter = lambda { |level, tag, message| "#{message}\n"} unless @formatter
|
47
|
+
@formatter
|
48
|
+
end
|
49
|
+
|
54
50
|
def rename(renames)
|
55
51
|
renames.each { |from, to| @rename_rules[tag_matcher(from)] = to }
|
56
52
|
end
|
57
53
|
|
58
54
|
private
|
55
|
+
def output(level, what, where, &block)
|
56
|
+
logger = where[:to]
|
57
|
+
code = nil
|
58
|
+
if logger
|
59
|
+
#todo: hack - what about other logger classes?
|
60
|
+
logger.formatter = lambda {|severity, datetime, progname, msg| "#{msg}"} if logger.is_a? Logger
|
61
|
+
write = lambda { |level, tag, msg | logger.send(level, formatter.call(level, tag, msg)) }
|
62
|
+
code = block ? lambda { |l,t,m| write.call(l,t,m); block.call(l,t,m) } : write
|
63
|
+
elsif block
|
64
|
+
code = block
|
65
|
+
else
|
66
|
+
raise ArgumentError "Should be called with block or :to => <logger>"
|
67
|
+
end
|
68
|
+
@tag_blocks[tag_matcher(what, level)] = code
|
69
|
+
end
|
70
|
+
|
59
71
|
class TagMatcher
|
60
72
|
attr_reader :match_spec
|
73
|
+
LEVELS = { :debug => 1, :info => 2, :warn => 3, :error => 4, :fatal => 5}
|
61
74
|
|
62
|
-
def initialize(match_spec)
|
75
|
+
def initialize(match_spec, level = nil)
|
76
|
+
@level = level || :debug
|
63
77
|
@match_spec = match_spec
|
64
78
|
end
|
65
79
|
|
66
|
-
def match?(tag)
|
80
|
+
def match?(tag, level = nil)
|
81
|
+
return false if level && !above_treshold(level)
|
67
82
|
self.class.match?(@match_spec, tag)
|
68
83
|
end
|
69
84
|
|
85
|
+
def above_treshold(level)
|
86
|
+
LEVELS[@level] <= LEVELS[level]
|
87
|
+
end
|
88
|
+
|
70
89
|
def self.match?(spec, tag)
|
71
90
|
t = tag.to_s
|
72
91
|
case spec
|
@@ -82,8 +101,8 @@ class TaggedLogger
|
|
82
101
|
end
|
83
102
|
end #TagMatcher
|
84
103
|
|
85
|
-
def tag_matcher(tag)
|
86
|
-
TagMatcher.new(tag)
|
104
|
+
def tag_matcher(tag, level = nil)
|
105
|
+
TagMatcher.new(tag, level)
|
87
106
|
end
|
88
107
|
|
89
108
|
def tag_aliases(tag, &block)
|
@@ -92,9 +111,9 @@ class TaggedLogger
|
|
92
111
|
block.call(current_name)
|
93
112
|
end
|
94
113
|
|
95
|
-
def tag_blocks(tag, &block)
|
114
|
+
def tag_blocks(level, tag, &block)
|
96
115
|
@tag_blocks.each do |matcher, block|
|
97
|
-
yield block if matcher.match?
|
116
|
+
yield block if matcher.match?(tag, level)
|
98
117
|
end
|
99
118
|
end
|
100
119
|
|
@@ -122,10 +141,10 @@ class TaggedLogger
|
|
122
141
|
|
123
142
|
def initialize(klass)
|
124
143
|
@klass = klass
|
125
|
-
|
126
|
-
|
127
|
-
eigenclass.send(:define_method,
|
128
|
-
blocks.each { |(tag_alias, block)| block.call(
|
144
|
+
[:debug, :warn, :info, :error, :fatal].each do |level|
|
145
|
+
blocks = TaggedLogger.blocks_for(level, klass.to_s)
|
146
|
+
eigenclass.send(:define_method, level) do |msg|
|
147
|
+
blocks.each { |(tag_alias, block)| block.call(level, tag_alias, msg) }
|
129
148
|
end
|
130
149
|
end
|
131
150
|
end
|
data/tagged_logger.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tagged_logger}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Fedor Kocherga"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-16}
|
13
13
|
s.email = %q{fkocherga@gmail.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.html",
|
@@ -22,16 +22,18 @@ Gem::Specification.new do |s|
|
|
22
22
|
"README.markdown",
|
23
23
|
"Rakefile",
|
24
24
|
"VERSION",
|
25
|
+
"examples/changing_format.rb",
|
25
26
|
"examples/one_log_per_classes.rb",
|
26
27
|
"examples/one_tag_per_classes.rb",
|
27
28
|
"examples/per_class_customization.rb",
|
28
29
|
"examples/rule_with_regex.rb",
|
29
|
-
"examples/simplest_customization.rb",
|
30
30
|
"examples/simplest_usage.rb",
|
31
31
|
"lib/tagged_logger.rb",
|
32
32
|
"tagged_logger.gemspec",
|
33
33
|
"tagged_logger.rb",
|
34
|
+
"test/expected_examples_output.txt",
|
34
35
|
"test/test.rb",
|
36
|
+
"test/test_examples.rb",
|
35
37
|
"todo.txt"
|
36
38
|
]
|
37
39
|
s.homepage = %q{http://github.com/fkocherga/tagged_logger}
|
@@ -40,7 +42,8 @@ Gem::Specification.new do |s|
|
|
40
42
|
s.rubygems_version = %q{1.3.5}
|
41
43
|
s.summary = %q{Detaches _what_ is logged from _how_ it is logged.}
|
42
44
|
s.test_files = [
|
43
|
-
"test/test.rb"
|
45
|
+
"test/test.rb",
|
46
|
+
"test/test_examples.rb"
|
44
47
|
]
|
45
48
|
|
46
49
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
<<<CHANGING_FORMAT>>>
|
3
|
+
info-Object: message
|
4
|
+
|
5
|
+
<<<ONE_LOG_PER_CLASSES>>>
|
6
|
+
- Only logging from within classes Ftp, Http and Sockets will be shown in output (no LogFoo):
|
7
|
+
Network::Ftp#foo
|
8
|
+
Network::Http#foo
|
9
|
+
Network::Sockets#foo
|
10
|
+
|
11
|
+
- Same result, but regex syntax:
|
12
|
+
Network::Ftp#foo
|
13
|
+
Network::Http#foo
|
14
|
+
Network::Sockets#foo
|
15
|
+
|
16
|
+
- Or even shorter:
|
17
|
+
Network::Ftp#foo
|
18
|
+
Network::Http#foo
|
19
|
+
Network::Sockets#foo
|
20
|
+
|
21
|
+
<<<ONE_TAG_PER_CLASSES>>>
|
22
|
+
- Only logging from within classes Ftp, Http and Sockets will be shown in output (no LogFoo)
|
23
|
+
tag is also printed and it is 'Network' after renaming took place:
|
24
|
+
Network: Ftp#foo
|
25
|
+
Network: Http#foo
|
26
|
+
Network: Sockets#foo
|
27
|
+
|
28
|
+
<<<PER_CLASS_CUSTOMIZATION>>>
|
29
|
+
- Only logging for Some class is shown in STDOUT
|
30
|
+
- Run this script again by adding '2>/dev/null' and see the difference:
|
31
|
+
Some: Some information
|
32
|
+
|
33
|
+
<<<RULE_WITH_REGEX>>>
|
34
|
+
- The recommended way to specify logging for all classes within same namespace:
|
35
|
+
foo
|
36
|
+
|
37
|
+
<<<SIMPLEST_USAGE>>>
|
38
|
+
INFO message
|
39
|
+
WARNING message
|
data/test/test.rb
CHANGED
@@ -18,134 +18,140 @@ end
|
|
18
18
|
class TaggedLoggerTest < Test::Unit::TestCase
|
19
19
|
include RR::Adapters::TestUnit
|
20
20
|
|
21
|
-
|
22
|
-
context "@standard_logger with stub output @out1;" do
|
21
|
+
context "stub output device @@stub_out;" do
|
23
22
|
setup do
|
24
|
-
|
25
|
-
@standard_logger = Logger.new(@out1)
|
26
|
-
@formatter = lambda {|severity, datetime, progname, msg| "#{msg}"}
|
27
|
-
@standard_logger.formatter = @formatter
|
23
|
+
@@stub_out = TestLogDevice.new
|
28
24
|
end
|
29
25
|
|
30
26
|
teardown do
|
31
|
-
Kernel.class_eval
|
32
|
-
remove_method :logger
|
33
|
-
end
|
27
|
+
Kernel.class_eval { remove_method :logger }
|
34
28
|
end
|
35
29
|
|
36
|
-
should "be able to intialize with minimal effort" do
|
30
|
+
should "be able to intialize with minimal effort, without defining any rules" do
|
37
31
|
TaggedLogger.init
|
38
|
-
dont_allow(
|
32
|
+
dont_allow(@@stub_out).write
|
39
33
|
assert Class.new.methods.include? "logger"
|
40
34
|
assert_nothing_raised { Class.new.logger }
|
41
35
|
end
|
42
36
|
|
43
|
-
context "everything gets logged to
|
37
|
+
context "everything gets logged to @@stub_out;" do
|
44
38
|
setup do
|
45
|
-
logger = @standard_logger
|
46
39
|
TaggedLogger.rules do
|
47
40
|
reset
|
48
|
-
|
41
|
+
format {|level, tag, msg| "#{tag}: #{msg}"}
|
42
|
+
debug /.*/, :to => Logger.new(@@stub_out)
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
52
|
-
should "
|
46
|
+
should "write output for every of #debug, #info, #warn, #error, #fatal call" do
|
53
47
|
NewClass = Class.new
|
54
48
|
obj = NewClass.new
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
49
|
+
TaggedLogger.rules { format { |level, tag, msg| "#{msg}" } }
|
50
|
+
|
51
|
+
mock(@@stub_out).write("debug")
|
52
|
+
obj.logger.debug("debug")
|
53
|
+
mock(@@stub_out).write("info")
|
54
|
+
obj.logger.info("info")
|
55
|
+
mock(@@stub_out).write("warn")
|
56
|
+
obj.logger.warn("warn")
|
57
|
+
mock(@@stub_out).write("error")
|
58
|
+
obj.logger.error("error")
|
59
|
+
mock(@@stub_out).write("fatal")
|
60
|
+
obj.logger.fatal("fatal")
|
60
61
|
end
|
61
62
|
|
62
|
-
context "class A and class B with
|
63
|
+
context "class A and class B with logger.info() in their method #foo;" do
|
63
64
|
setup do
|
64
|
-
module Foo
|
65
|
-
def foo
|
66
|
-
logger.info("foo")
|
67
|
-
end
|
68
|
-
end
|
65
|
+
module Foo; def foo; logger.info("foo"); end; end
|
69
66
|
class A;include Foo; end
|
70
67
|
class B;include Foo; end
|
71
68
|
@a = A.new
|
72
69
|
@b = B.new
|
73
70
|
end
|
74
|
-
|
71
|
+
|
75
72
|
should "be possible to replace tags for A, B classes with single tag TEST making rules for A and B obsolete" do
|
76
73
|
TaggedLogger.rules do
|
77
74
|
rename [A,B] => :TEST
|
78
75
|
end
|
79
|
-
|
76
|
+
mock(@@stub_out).write("TEST: foo")
|
80
77
|
@a.foo
|
81
|
-
|
82
|
-
@out1.clear
|
83
|
-
|
78
|
+
mock(@@stub_out).write("TEST: foo")
|
84
79
|
@b.foo
|
85
|
-
assert_equal "TEST: foo\n", @out1.to_s
|
86
80
|
end
|
87
81
|
|
88
|
-
|
89
|
-
setup
|
90
|
-
|
91
|
-
|
92
|
-
|
82
|
+
context "@logger2 with stub output @@stub_out_aux;" do
|
83
|
+
setup { @@stub_out_aux = TestLogDevice.new }
|
84
|
+
|
85
|
+
should "be possible to add logging to @@stub_out_aux for A" do
|
86
|
+
TaggedLogger.rules { debug A, :to => Logger.new(@@stub_out_aux) }
|
87
|
+
mock(@@stub_out).write("#{self.class}::A: foo")
|
88
|
+
mock(@@stub_out_aux).write("#{self.class}::A: foo")
|
89
|
+
@a.foo
|
90
|
+
mock(@@stub_out).write("#{self.class}::B: foo")
|
91
|
+
dont_allow(@@stub_out_aux).write
|
92
|
+
@b.foo
|
93
93
|
end
|
94
94
|
|
95
|
-
should "be possible to speialize logging for tag A by
|
96
|
-
logger2 = @logger2
|
95
|
+
should "be possible to speialize logging for tag A by providing block" do
|
97
96
|
TaggedLogger.rules do
|
98
|
-
|
97
|
+
debug A do |level, tag, msg|
|
98
|
+
@@stub_out_aux.write("#{level} #{tag} #{msg}")
|
99
|
+
end
|
99
100
|
end
|
101
|
+
mock(@@stub_out_aux).write("info #{self.class}::A foo")
|
102
|
+
mock(@@stub_out).write("#{self.class}::A: foo")
|
100
103
|
@a.foo
|
101
|
-
assert_equal "#{self.class}::A: foo\n", @out1.to_s
|
102
|
-
assert_equal "#{self.class}::A: foo\n", @out2.to_s
|
103
|
-
@out2.clear
|
104
|
-
@b.foo
|
105
|
-
assert_equal "#{self.class}::B: foo\n", @out1.to_s
|
106
|
-
assert_equal "", @out2.to_s
|
107
104
|
end
|
108
|
-
|
109
|
-
should "be possible to
|
110
|
-
logger2 = @logger2
|
105
|
+
|
106
|
+
should "be possible to provide block and logger together, and do actual writing by yielding" do
|
111
107
|
TaggedLogger.rules do
|
112
|
-
|
113
|
-
|
108
|
+
debug A, :to => Logger.new(@@stub_out_aux) do |level, tag, message|
|
109
|
+
@@stub_out_aux.write "post write callback"
|
114
110
|
end
|
115
111
|
end
|
112
|
+
mock(@@stub_out_aux).write("#{self.class}::A: foo")
|
113
|
+
mock(@@stub_out_aux).write("post write callback")
|
114
|
+
mock(@@stub_out).write("#{self.class}::A: foo")
|
116
115
|
@a.foo
|
117
|
-
assert_equal "#{self.class}::A: foo\n", @out1.to_s
|
118
|
-
assert_equal "foo", @out2.to_s
|
119
|
-
@out2.clear
|
120
|
-
@b.foo
|
121
|
-
assert_equal "#{self.class}::B: foo\n", @out1.to_s
|
122
|
-
assert_equal "", @out2.to_s
|
123
116
|
end
|
124
117
|
|
125
118
|
should "be possible to replace tags for A, B classes with single tag TEST and specialize logging for it" do
|
126
|
-
logger2 = @logger2
|
127
119
|
TaggedLogger.rules do
|
128
120
|
rename [A, B] => :TEST
|
129
|
-
|
121
|
+
debug :TEST, :to => Logger.new(@@stub_out_aux)
|
130
122
|
end
|
123
|
+
mock(@@stub_out).write("TEST: foo")
|
124
|
+
mock(@@stub_out_aux).write("TEST: foo")
|
131
125
|
@a.foo
|
132
|
-
|
133
|
-
|
134
|
-
@out1.clear
|
135
|
-
@out2.clear
|
126
|
+
mock(@@stub_out).write("TEST: foo")
|
127
|
+
mock(@@stub_out_aux).write("TEST: foo")
|
136
128
|
@b.foo
|
137
|
-
assert_equal "TEST: foo\n", @out1.to_s
|
138
|
-
assert_equal "TEST: foo\n", @out2.to_s
|
139
129
|
end
|
140
130
|
|
141
131
|
should "use default tag equal to class name for class methods" do
|
142
132
|
def A.bar
|
143
133
|
logger.info "bar"
|
144
134
|
end
|
135
|
+
mock(@@stub_out).write("#{self.class}::A: bar")
|
145
136
|
A.bar
|
146
|
-
assert_equal "#{self.class}::A: bar\n", @out1.to_s
|
147
137
|
end
|
148
|
-
|
138
|
+
|
139
|
+
context "class A and class B with logger.debug() in their method #bar;" do
|
140
|
+
setup do
|
141
|
+
module Bar; def bar; logger.debug("bar"); end; end
|
142
|
+
class A;include Bar; end
|
143
|
+
class B;include Bar; end
|
144
|
+
end
|
145
|
+
|
146
|
+
should "not print debug messages if info level specified" do
|
147
|
+
TaggedLogger.rules do
|
148
|
+
info /A/, :to => Logger.new(@@stub_out_aux)
|
149
|
+
end
|
150
|
+
dont_allow(@@stub_out_aux).write
|
151
|
+
@a.bar
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
149
155
|
|
150
156
|
end
|
151
157
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
root_dir = File.dirname(File.expand_path(__FILE__)) + '/../'
|
2
|
+
examples_output = `find -s #{root_dir}examples -iname '*.rb' -exec ruby {} \\;`
|
3
|
+
expected_output = File.read("#{root_dir}test/expected_examples_output.txt")
|
4
|
+
if expected_output != examples_output
|
5
|
+
puts "FAILED: Examples do not produce same output as expected.\n"
|
6
|
+
raise StandardError, "FAILED"
|
7
|
+
end
|
8
|
+
puts "SUCCEEDED.\n"
|
data/todo.txt
CHANGED
@@ -1,21 +1,7 @@
|
|
1
|
-
-
|
2
|
-
run only them afterwards rather than going via all rules each time. It will
|
3
|
-
gain almost 300% in parsing speed on my app.
|
4
|
-
|
5
|
-
- Replace output ... => ... with
|
6
|
-
format ...
|
7
|
-
output ... => do
|
8
|
-
format ....
|
9
|
-
end
|
10
|
-
|
11
|
-
- output ... => ... - may be:
|
12
|
-
debug ... => ...
|
13
|
-
info ... => ...
|
14
|
-
|
15
|
-
- Simplest configuration with warning
|
16
|
-
|
17
|
-
- Switch tests on rr expectations
|
18
|
-
|
1
|
+
- logger.debug method (and alike) should accept block for performance reason
|
19
2
|
- logger called within Base does not log when Derived is instantiated
|
20
|
-
|
21
3
|
- writing messages in any encoding
|
4
|
+
- test against 'logging' framework
|
5
|
+
- test agains 1.8.6 and 1.9.1
|
6
|
+
- test with Rails
|
7
|
+
- when logger specified in :to => ... then lib must complain unless formatting and logging code to that specific logger class was not defined
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tagged_logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fedor Kocherga
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-16 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -29,16 +29,18 @@ files:
|
|
29
29
|
- README.markdown
|
30
30
|
- Rakefile
|
31
31
|
- VERSION
|
32
|
+
- examples/changing_format.rb
|
32
33
|
- examples/one_log_per_classes.rb
|
33
34
|
- examples/one_tag_per_classes.rb
|
34
35
|
- examples/per_class_customization.rb
|
35
36
|
- examples/rule_with_regex.rb
|
36
|
-
- examples/simplest_customization.rb
|
37
37
|
- examples/simplest_usage.rb
|
38
38
|
- lib/tagged_logger.rb
|
39
39
|
- tagged_logger.gemspec
|
40
40
|
- tagged_logger.rb
|
41
|
+
- test/expected_examples_output.txt
|
41
42
|
- test/test.rb
|
43
|
+
- test/test_examples.rb
|
42
44
|
- todo.txt
|
43
45
|
- README.html
|
44
46
|
has_rdoc: true
|
@@ -71,3 +73,4 @@ specification_version: 3
|
|
71
73
|
summary: Detaches _what_ is logged from _how_ it is logged.
|
72
74
|
test_files:
|
73
75
|
- test/test.rb
|
76
|
+
- test/test_examples.rb
|