sml-log4r 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/doc/content/contact.html +22 -0
  2. data/doc/content/contribute.html +21 -0
  3. data/doc/content/index.html +90 -0
  4. data/doc/content/license.html +56 -0
  5. data/doc/content/manual.html +449 -0
  6. data/doc/dev/README.developers +40 -0
  7. data/doc/dev/checklist +14 -0
  8. data/doc/dev/things-to-do +2 -0
  9. data/doc/images/crush/logo2.png +0 -0
  10. data/doc/images/log4r-logo.png +0 -0
  11. data/doc/images/logo2.png +0 -0
  12. data/doc/log4r.css +111 -0
  13. data/doc/old/manual.html +348 -0
  14. data/doc/templates/main.html +147 -0
  15. data/examples/README +19 -0
  16. data/examples/customlevels.rb +34 -0
  17. data/examples/fileroll.rb +40 -0
  18. data/examples/log4r_yaml.yaml +0 -0
  19. data/examples/logclient.rb +25 -0
  20. data/examples/logserver.rb +18 -0
  21. data/examples/moderate.xml +29 -0
  22. data/examples/moderateconfig.rb +66 -0
  23. data/examples/myformatter.rb +23 -0
  24. data/examples/outofthebox.rb +21 -0
  25. data/examples/rrconfig.xml +63 -0
  26. data/examples/rrsetup.rb +42 -0
  27. data/examples/simpleconfig.rb +39 -0
  28. data/examples/xmlconfig.rb +25 -0
  29. data/examples/yaml.rb +30 -0
  30. data/src/log4r.rb +17 -0
  31. data/src/log4r/base.rb +74 -0
  32. data/src/log4r/config.rb +9 -0
  33. data/src/log4r/configurator.rb +224 -0
  34. data/src/log4r/formatter/formatter.rb +105 -0
  35. data/src/log4r/formatter/patternformatter.rb +108 -0
  36. data/src/log4r/lib/drbloader.rb +52 -0
  37. data/src/log4r/lib/xmlloader.rb +24 -0
  38. data/src/log4r/logevent.rb +28 -0
  39. data/src/log4r/logger.rb +194 -0
  40. data/src/log4r/loggerfactory.rb +89 -0
  41. data/src/log4r/logserver.rb +28 -0
  42. data/src/log4r/outputter/consoleoutputters.rb +18 -0
  43. data/src/log4r/outputter/datefileoutputter.rb +110 -0
  44. data/src/log4r/outputter/emailoutputter.rb +115 -0
  45. data/src/log4r/outputter/fileoutputter.rb +49 -0
  46. data/src/log4r/outputter/iooutputter.rb +55 -0
  47. data/src/log4r/outputter/outputter.rb +132 -0
  48. data/src/log4r/outputter/outputterfactory.rb +59 -0
  49. data/src/log4r/outputter/remoteoutputter.rb +40 -0
  50. data/src/log4r/outputter/rollingfileoutputter.rb +126 -0
  51. data/src/log4r/outputter/staticoutputter.rb +30 -0
  52. data/src/log4r/outputter/syslogoutputter.rb +75 -0
  53. data/src/log4r/rdoc/configurator +243 -0
  54. data/src/log4r/rdoc/emailoutputter +103 -0
  55. data/src/log4r/rdoc/formatter +39 -0
  56. data/src/log4r/rdoc/log4r +89 -0
  57. data/src/log4r/rdoc/logger +175 -0
  58. data/src/log4r/rdoc/logserver +85 -0
  59. data/src/log4r/rdoc/outputter +108 -0
  60. data/src/log4r/rdoc/patternformatter +128 -0
  61. data/src/log4r/rdoc/syslogoutputter +29 -0
  62. data/src/log4r/rdoc/yamlconfigurator +20 -0
  63. data/src/log4r/repository.rb +65 -0
  64. data/src/log4r/staticlogger.rb +49 -0
  65. data/src/log4r/yamlconfigurator.rb +0 -0
  66. data/tests/include.rb +7 -0
  67. data/tests/runtest.rb +6 -0
  68. data/tests/testbase.rb +45 -0
  69. data/tests/testcustom.rb +33 -0
  70. data/tests/testdefault.rb +25 -0
  71. data/tests/testformatter.rb +29 -0
  72. data/tests/testlogger.rb +198 -0
  73. data/tests/testoutputter.rb +112 -0
  74. data/tests/testpatternformatter.rb +26 -0
  75. data/tests/testxmlconf.rb +51 -0
  76. data/tests/xml/testconf.xml +37 -0
  77. metadata +140 -0
@@ -0,0 +1,29 @@
1
+ = SyslogOutputter
2
+
3
+ A SyslogOutputter transforms a Log4r::LogEvent into a call to syslog().
4
+ Since syslog has its own formatting system, log4r formatters are ignored.
5
+
6
+ == Usage
7
+
8
+ To use,
9
+
10
+ <tt>require 'log4r/outputter/syslogoutputter'</tt>
11
+
12
+ An example,
13
+
14
+ require 'log4r'
15
+ require 'log4r/outputter/syslogoutputter'
16
+
17
+ syslog = Log4r::SyslogOutputter.new("name", 'logopt'=>#, 'facility'=>#)
18
+ syslog.err("this is an ERR message")
19
+
20
+ The output in <tt>/var/logs/syslog</tt> (Debian) is,
21
+
22
+ Sep 3 11:43:06 tiphares sys[1603]: this is an ERR message
23
+
24
+ The hash arguments +logoptions+ and +facility+ are passed to
25
+ <tt>Syslog.open</tt>. The
26
+ defaults are <tt>LOG_PID | LOG_CONS</tt> and <tt>LOG_USER</tt> respectively.
27
+
28
+ This is a first try implementation. It works well. Please report
29
+ any bugs and fixes.
@@ -0,0 +1,20 @@
1
+ = Configuring Log4r with Log4r::YamlConfigurator
2
+
3
+ The YamlConfigurator class allows one to set up Log4r via YAML.
4
+ It is used almost exactly as Log4r::Configurator and has the same features,
5
+
6
+ ycfg = YamlConfigurator # handy shorthand
7
+ ycfg['foo'] = bar # replaces instances of #{foo} in the YAML with bar
8
+ ycfg.load_yaml_file('foo.yaml')
9
+
10
+ Ruby 1.7 and 1.8 comes with a YAML parser. Hence, YAML can be used
11
+ to configure Log4r out of the box.
12
+
13
+ A comprehensive example of a Log4r YAML configuration is provided in the
14
+ examples directory.
15
+
16
+ To use this class:
17
+
18
+ require 'log4r/yamlconfigurator'
19
+
20
+ Thanks to Andreas Hund for making this possible.
@@ -0,0 +1,65 @@
1
+ # :nodoc:
2
+ # Version:: $Id: repository.rb,v 1.10 2002/08/20 07:40:26 cepheus Exp $
3
+
4
+ require "singleton"
5
+
6
+ module Log4r
7
+ class Logger
8
+
9
+ # The repository stores a Hash of loggers keyed to their fullnames and
10
+ # provides a few functions to reduce the code bloat in log4r/logger.rb.
11
+ # This class is supposed to be transparent to end users, hence it is
12
+ # a class within Logger. If anyone knows how to make this private,
13
+ # let me know.
14
+
15
+ class Repository # :nodoc:
16
+ include Singleton
17
+ attr_reader :loggers
18
+
19
+ def initialize
20
+ @loggers = Hash.new
21
+ end
22
+
23
+ def self.[](fullname)
24
+ instance.loggers[fullname]
25
+ end
26
+
27
+ def self.[]=(fullname, logger)
28
+ instance.loggers[fullname] = logger
29
+ end
30
+
31
+ # Retrieves all children of a parent
32
+ def self.all_children(parent)
33
+ # children have the parent name + delimiter in their fullname
34
+ daddy = parent.name + Private::Config::LoggerPathDelimiter
35
+ for fullname, logger in instance.loggers
36
+ yield logger if parent.is_root? || fullname =~ /#{daddy}/
37
+ end
38
+ end
39
+
40
+ # when new loggers are introduced, they may get inserted into
41
+ # an existing inheritance tree. this method
42
+ # updates the children of a logger to link their new parent
43
+ def self.reassign_any_children(parent)
44
+ for fullname, logger in instance.loggers
45
+ next if logger.is_root?
46
+ logger.parent = parent if logger.path =~ /^#{parent.fullname}$/
47
+ end
48
+ end
49
+
50
+ # looks for the first defined logger in a child's path
51
+ # or nil if none found (which will then be rootlogger)
52
+ def self.find_ancestor(path)
53
+ arr = path.split Log4rConfig::LoggerPathDelimiter
54
+ logger = nil
55
+ while arr.size > 0 do
56
+ logger = Repository[arr.join(Log4rConfig::LoggerPathDelimiter)]
57
+ break unless logger.nil?
58
+ arr.pop
59
+ end
60
+ logger
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ # :nodoc:
2
+ module Log4r
3
+ class Logger
4
+ # Returns the root logger. Identical to Logger.global
5
+ def self.root; return RootLogger.instance end
6
+ # Returns the root logger. Identical to Logger.root
7
+ def self.global; return root end
8
+
9
+ # Get a logger with a fullname from the repository or nil if logger
10
+ # wasn't found.
11
+
12
+ def self.[](_fullname)
13
+ # forces creation of RootLogger if it doesn't exist yet.
14
+ return RootLogger.instance if _fullname=='root' or _fullname=='global'
15
+ Repository[_fullname]
16
+ end
17
+
18
+ # Like Logger[] except that it raises NameError if Logger wasn't found.
19
+
20
+ def self.get(_fullname)
21
+ logger = self[_fullname]
22
+ if logger.nil?
23
+ raise NameError, "Logger '#{_fullname}' not found.", caller
24
+ end
25
+ logger
26
+ end
27
+
28
+ # Yields fullname and logger for every logger in the system.
29
+ def self.each
30
+ for fullname, logger in Repository.instance.loggers
31
+ yield fullname, logger
32
+ end
33
+ end
34
+
35
+ def self.each_logger
36
+ Repository.instance.loggers.each_value {|logger| yield logger}
37
+ end
38
+
39
+ # Internal logging for Log4r components. Accepts only blocks.
40
+ # To see such log events, create a logger named 'log4r' and give
41
+ # it an outputter.
42
+
43
+ def self.log_internal(level=1)
44
+ internal = Logger['log4r']
45
+ return if internal.nil?
46
+ internal.send(LNAMES[level].downcase, yield)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ $:.push("../src")
2
+ require 'runit/testcase'
3
+ require "log4r"
4
+ require "log4r/configurator"
5
+
6
+ include Log4r
7
+ include RUNIT
@@ -0,0 +1,6 @@
1
+ system "ruby testcustom.rb"
2
+ system "ruby testbase.rb"
3
+ system "ruby testdefault.rb"
4
+ for i in 1..4
5
+ system "ruby testxmlconf.rb #{i}"
6
+ end
@@ -0,0 +1,45 @@
1
+ require "include"
2
+ require "runit/cui/testrunner"
3
+
4
+ # must be run independently
5
+ class TestBase < TestCase
6
+ def test_default_const
7
+ Logger.root # create the default levels
8
+ assert_equal(ALL,0)
9
+ assert_equal(DEBUG,1)
10
+ assert_equal(INFO,2)
11
+ assert_equal(WARN,3)
12
+ assert_equal(ERROR,4)
13
+ assert_equal(FATAL,5)
14
+ assert_equal(OFF,6)
15
+ assert_equal(LEVELS, 7)
16
+ assert_equal(LNAMES.size, 7)
17
+ end
18
+ def test_validate
19
+ 7.times{|i| assert_no_exception {Log4rTools.validate_level(i)} }
20
+ assert_exception(ArgumentError) {Log4rTools.validate_level(-1)}
21
+ assert_exception(ArgumentError) {Log4rTools.validate_level(LEVELS)}
22
+ assert_exception(ArgumentError) {Log4rTools.validate_level(String)}
23
+ assert_exception(ArgumentError) {Log4rTools.validate_level("bogus")}
24
+ end
25
+ def test_decode_bool
26
+ assert(Log4rTools.decode_bool({:data=>'true'},:data,false) == true)
27
+ assert(Log4rTools.decode_bool({:data=>true},:data,false) == true)
28
+ assert(Log4rTools.decode_bool({:data=>'false'},:data,true) == false)
29
+ assert(Log4rTools.decode_bool({:data=>false},:data,true) == false)
30
+ assert(Log4rTools.decode_bool({:data=>nil},:data,true) == true)
31
+ assert(Log4rTools.decode_bool({:data=>nil},:data,false) == false)
32
+ assert(Log4rTools.decode_bool({:data=>String},:data,true) == true)
33
+ assert(Log4rTools.decode_bool({:data=>String},:data,false) == false)
34
+ assert(Log4rTools.decode_bool({'data'=>'true'},:data,false) == true)
35
+ assert(Log4rTools.decode_bool({'data'=>true},:data,false) == true)
36
+ assert(Log4rTools.decode_bool({'data'=>'false'},:data,true) == false)
37
+ assert(Log4rTools.decode_bool({'data'=>false},:data,true) == false)
38
+ assert(Log4rTools.decode_bool({'data'=>nil},:data,true) == true)
39
+ assert(Log4rTools.decode_bool({'data'=>nil},:data,false) == false)
40
+ assert(Log4rTools.decode_bool({'data'=>String},:data,true) == true)
41
+ assert(Log4rTools.decode_bool({'data'=>String},:data,false) == false)
42
+ end
43
+ end
44
+
45
+ CUI::TestRunner.run(TestBase.suite)
@@ -0,0 +1,33 @@
1
+ require "include"
2
+ require "runit/cui/testrunner"
3
+
4
+ # tests the customization of Log4r levels
5
+ class TestCustom < TestCase
6
+ def test_validation
7
+ assert_exception(TypeError) { Configurator.custom_levels "lowercase" }
8
+ assert_exception(TypeError) { Configurator.custom_levels "With space" }
9
+ end
10
+
11
+ def test_create
12
+ assert_no_exception { Configurator.custom_levels "Foo", "Bar", "Baz" }
13
+ assert_no_exception { Configurator.custom_levels }
14
+ assert_no_exception { Configurator.custom_levels "Bogus", "Levels" }
15
+ end
16
+ def test_methods
17
+ l = Logger.new 'custom1'
18
+ assert_respond_to(:foo, l)
19
+ assert_respond_to(:foo?, l)
20
+ assert_respond_to(:bar, l)
21
+ assert_respond_to(:bar?, l)
22
+ assert_respond_to(:baz, l)
23
+ assert_respond_to(:baz?, l)
24
+ assert_no_exception(NameError) { Bar }
25
+ assert_no_exception(NameError) { Baz }
26
+ assert_no_exception(NameError) { Foo }
27
+ end
28
+
29
+ end
30
+
31
+ CUI::TestRunner.run(TestCustom.new("test_validation"))
32
+ CUI::TestRunner.run(TestCustom.new("test_create"))
33
+ CUI::TestRunner.run(TestCustom.new("test_methods"))
@@ -0,0 +1,25 @@
1
+ # actually, tests only the following:
2
+ require "testlogger"
3
+ require "testoutputter"
4
+ require "testformatter"
5
+ require "testpatternformatter"
6
+
7
+ require "runit/testsuite"
8
+ require "runit/cui/testrunner"
9
+
10
+ class TestDefault
11
+ def TestDefault.suite
12
+ suite = TestSuite.new
13
+ for k in Object.constants.sort
14
+ next if /^Test/ !~ k
15
+ const = Object.const_get(k)
16
+ if const.kind_of?(Class) && const.superclass == RUNIT::TestCase
17
+ suite.add(const.suite)
18
+ end
19
+ end
20
+ suite
21
+ end
22
+ end
23
+
24
+ CUI::TestRunner.run(TestDefault.suite)
25
+
@@ -0,0 +1,29 @@
1
+ require "include"
2
+
3
+ class TestFormatter < TestCase
4
+ def test_creation
5
+ assert_no_exception { Formatter.new.format(3) }
6
+ assert_no_exception { DefaultFormatter.new }
7
+ assert_kind_of(Formatter, DefaultFormatter.new)
8
+ end
9
+ def test_simple_formatter
10
+ sf = SimpleFormatter.new
11
+ f = Logger.new('simple formatter')
12
+ event = LogEvent.new(0, f, nil, "some data")
13
+ assert_match(sf.format(event), /simple formatter/)
14
+ end
15
+ def test_basic_formatter
16
+ b = BasicFormatter.new
17
+ f = Logger.new('fake formatter')
18
+ event = LogEvent.new(0, f, caller, "fake formatter")
19
+ event2 = LogEvent.new(0, f, nil, "fake formatter")
20
+ # this checks for tracing
21
+ assert_match(b.format(event), /in/)
22
+ assert_not_match(b.format(event2), /in/)
23
+ e = ArgumentError.new("argerror")
24
+ e.set_backtrace ['backtrace']
25
+ event3 = LogEvent.new(0, f, nil, e)
26
+ assert_match(b.format(event3), /ArgumentError/)
27
+ assert_match(b.format(LogEvent.new(0,f,nil,[1,2,3])), /Array/)
28
+ end
29
+ end
@@ -0,0 +1,198 @@
1
+ require "include"
2
+
3
+ class MyFormatter1 < Formatter
4
+ def format(event)
5
+ return "MyFormatter1\n"
6
+ end
7
+ end
8
+
9
+ class MyFormatter2 < Formatter
10
+ def format(event)
11
+ return "MyFormatter2\n"
12
+ end
13
+ end
14
+
15
+ class TestLogger < TestCase
16
+ def test_root
17
+ l1 = Logger.root
18
+ l2 = Logger['root']
19
+ l3 = Logger.global
20
+ assert(l1 == l2, "RootLogger wasn't singleton!")
21
+ assert(l1 == l3)
22
+ assert(l1.is_root? == true, "is_root? not working")
23
+ assert(l1.parent == nil, "Root's parent wasn't nil!")
24
+ end
25
+ def test_validation
26
+ assert_exception(ArgumentError) { Logger.new }
27
+ assert_no_exception { Logger.new('validate', nil) }
28
+ end
29
+ def test_all_off
30
+ l = Logger.new("create_method")
31
+ l.level = WARN
32
+ assert(l.debug? == false)
33
+ assert(l.info? == false)
34
+ assert(l.warn? == true)
35
+ assert(l.error? == true)
36
+ assert(l.fatal? == true)
37
+ assert(l.off? == false)
38
+ assert(l.all? == false)
39
+ l.level = OFF
40
+ assert(l.off? == true)
41
+ assert(l.all? == false)
42
+ l.level = ALL
43
+ assert(l.off? == false)
44
+ assert(l.all? == true)
45
+ end
46
+ def test_add_outputters
47
+ StdoutOutputter.new('fake1')
48
+ StdoutOutputter.new('fake2')
49
+ a = Logger.new("add")
50
+ assert_exception(TypeError) { a.add 'bogus' }
51
+ assert_exception(TypeError) { a.add Class }
52
+ assert_exception(TypeError) { a.add 'fake1', Class }
53
+ assert_no_exception { a.add 'fake1', 'fake2' }
54
+ end
55
+ def test_repository
56
+ assert_exception(NameError) { Logger.get('bogusbogus') }
57
+ assert_no_exception { Logger['bogusbogus'] }
58
+ end
59
+ def test_heiarchy
60
+ a = Logger.new("a")
61
+ a.additive = true
62
+ assert(a.name == "a", "name wasn't set properly")
63
+ assert(a.path == "", "path wasn't set properly")
64
+ assert(a.level == Logger.root.level, "didn't inherit root's level")
65
+ assert(a.parent == Logger.root)
66
+ a.level = WARN
67
+ b = Logger.new("a::b")
68
+ assert(b.name == "b", "name wasn't set properly")
69
+ assert(b.path == "a", "path wasn't set properly")
70
+ assert(b.level == a.level, "didn't inherit parent's level")
71
+ assert(b.parent == a, "parent wasn't what is expected")
72
+ c = Logger.new("a::b::c")
73
+ assert(Logger["a::b::c"] == c)
74
+ assert(c.name == "c", "name wasn't set properly")
75
+ assert(c.path == "a::b", "path wasn't set properly")
76
+ assert(c.level == b.level, "didn't inherit parent's level")
77
+ assert(c.parent == b, "parent wasn't what is expected")
78
+ d = Logger.new("a::d")
79
+ assert(Logger["a::d"] == d)
80
+ assert(d.name == "d", "name wasn't set properly")
81
+ assert(d.path == "a", "path wasn't set properly")
82
+ assert(d.level == a.level, "didn't inherit parent's level")
83
+ assert(d.parent == a, "parent wasn't what is expected")
84
+ assert_exception(ArgumentError) { Logger.new("::a") }
85
+ end
86
+ def test_undefined_parents
87
+ a = Logger.new 'has::no::real::parents::me'
88
+ assert(a.parent == Logger.root)
89
+ b = Logger.new 'has::no::real::parents::me::child'
90
+ assert(b.parent == a)
91
+ c = Logger.new 'has::no::real::parents::metoo'
92
+ assert(c.parent == Logger.root)
93
+ p = Logger.new 'has::no::real::parents'
94
+ assert(p.parent == Logger.root)
95
+ assert(a.parent == p)
96
+ assert(b.parent == a)
97
+ assert(c.parent == p)
98
+ Logger.each{|fullname, logger|
99
+ if logger != a and logger != c
100
+ assert(logger.parent != p)
101
+ end
102
+ }
103
+ end
104
+ def test_levels
105
+ l = Logger.new("levels", WARN)
106
+ assert(l.level == WARN, "level wasn't changed")
107
+ assert(l.fatal? == true)
108
+ assert(l.error? == true)
109
+ assert(l.warn? == true)
110
+ assert(l.info? == false)
111
+ assert(l.debug? == false)
112
+ l.debug "debug message should NOT show up"
113
+ l.info "info message should NOT show up"
114
+ l.warn "warn messge should show up. 3 total"
115
+ l.error "error messge should show up. 3 total"
116
+ l.fatal "fatal messge should show up. 3 total"
117
+ l.level = ERROR
118
+ assert(l.level == ERROR, "level wasn't changed")
119
+ assert(l.fatal? == true)
120
+ assert(l.error? == true)
121
+ assert(l.warn? == false)
122
+ assert(l.info? == false)
123
+ assert(l.debug? == false)
124
+ l.debug "debug message should NOT show up"
125
+ l.info "info message should NOT show up"
126
+ l.warn "warn messge should NOT show up."
127
+ l.error "error messge should show up. 2 total"
128
+ l.fatal "fatal messge should show up. 2 total"
129
+ l.level = WARN
130
+ end
131
+ def test_log_blocks
132
+ l = Logger.new 'logblocks'
133
+ l.level = WARN
134
+ l.add(Outputter.stdout)
135
+ assert_no_exception {
136
+ l.debug { puts "should not show up"; "LOGBLOCKS" }
137
+ l.fatal { puts "should show up"; "LOGBLOCKS" }
138
+ l.fatal { nil }
139
+ l.fatal {}
140
+ }
141
+ end
142
+ def test_heiarchial_logging
143
+ a = Logger.new("one")
144
+ a.add(StdoutOutputter.new 'so1')
145
+ b = Logger.new("one::two")
146
+ b.add(StdoutOutputter.new 'so2')
147
+ c = Logger.new("one::two::three")
148
+ c.add(StdoutOutputter.new 'so3')
149
+ d = Logger.new("one::two::three::four")
150
+ d.add(StdoutOutputter.new 'so4')
151
+ d.additive = false
152
+ e = Logger.new("one::two::three::four::five")
153
+ e.add(StdoutOutputter.new 'so5')
154
+
155
+ a.fatal "statement from a should show up once"
156
+ b.fatal "statement from b should show up twice"
157
+ c.fatal "statement from c should show up thrice"
158
+ d.fatal "statement from d should show up once"
159
+ e.fatal "statement from e should show up twice"
160
+ end
161
+ def test_multi_outs
162
+ f1 = FileOutputter.new('f1', :filename => "./junk/tmp1.log", :level=>ALL)
163
+ f2 = FileOutputter.new('f2', :filename => "./junk/tmp2.log", :level=>DEBUG)
164
+ f3 = FileOutputter.new('f3', :filename => "./junk/tmp3.log", :level=>ERROR)
165
+ f4 = FileOutputter.new('f4', :filename => "./junk/tmp4.log", :level=>FATAL)
166
+
167
+ l = Logger.new("multi")
168
+ l.add(f1, f3, f4)
169
+
170
+ a = Logger.new("multi::multi2")
171
+ a.level = ERROR
172
+ a.add(f2, f4)
173
+
174
+ l.debug "debug test_multi_outputters"
175
+ l.info "info test_multi_outputters"
176
+ l.warn "warn test_multi_outputters"
177
+ l.error "error test_multi_outputters"
178
+ l.fatal "fatal test_multi_outputters"
179
+
180
+ a.debug "debug test_multi_outputters"
181
+ a.info "info test_multi_outputters"
182
+ a.warn "warn test_multi_outputters"
183
+ a.error "error test_multi_outputters"
184
+ a.fatal "fatal test_multi_outputters"
185
+
186
+ f1.close; f2.close; f3.close; f4.close
187
+ end
188
+ def test_custom_formatter
189
+ l = Logger.new('custom_formatter')
190
+ o = StdoutOutputter.new('formatter'=>MyFormatter1.new)
191
+ l.add o
192
+ l.error "try myformatter1"
193
+ l.fatal "try myformatter1"
194
+ o.formatter = MyFormatter2.new
195
+ l.error "try formatter2"
196
+ l.fatal "try formatter2"
197
+ end
198
+ end