path-log4r 1.1.10

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.
Files changed (104) hide show
  1. data/INSTALL +11 -0
  2. data/LICENSE +90 -0
  3. data/LICENSE.LGPLv3 +165 -0
  4. data/README +95 -0
  5. data/Rakefile +74 -0
  6. data/TODO +2 -0
  7. data/doc/content/contact.html +22 -0
  8. data/doc/content/contribute.html +21 -0
  9. data/doc/content/index.html +90 -0
  10. data/doc/content/license.html +56 -0
  11. data/doc/content/manual.html +449 -0
  12. data/doc/dev/README.developers +55 -0
  13. data/doc/dev/checklist +23 -0
  14. data/doc/dev/things-to-do +5 -0
  15. data/doc/images/log4r-logo.png +0 -0
  16. data/doc/images/logo2.png +0 -0
  17. data/doc/log4r.css +111 -0
  18. data/doc/rdoc-log4r.css +696 -0
  19. data/doc/templates/main.html +147 -0
  20. data/examples/README +19 -0
  21. data/examples/ancestors.rb +53 -0
  22. data/examples/chainsaw_settings.xml +7 -0
  23. data/examples/customlevels.rb +34 -0
  24. data/examples/filelog.rb +25 -0
  25. data/examples/fileroll.rb +40 -0
  26. data/examples/gmail.rb +30 -0
  27. data/examples/gmail.yaml +95 -0
  28. data/examples/log4r_yaml.yaml +0 -0
  29. data/examples/logclient.rb +25 -0
  30. data/examples/logserver.rb +18 -0
  31. data/examples/moderate.xml +29 -0
  32. data/examples/moderateconfig.rb +66 -0
  33. data/examples/myformatter.rb +23 -0
  34. data/examples/outofthebox.rb +21 -0
  35. data/examples/rdoc-gen +2 -0
  36. data/examples/rrconfig.xml +63 -0
  37. data/examples/rrsetup.rb +42 -0
  38. data/examples/simpleconfig.rb +39 -0
  39. data/examples/syslogcustom.rb +52 -0
  40. data/examples/xmlconfig.rb +25 -0
  41. data/examples/yaml.rb +30 -0
  42. data/lib/log4r.rb +20 -0
  43. data/lib/log4r/GDC.rb +41 -0
  44. data/lib/log4r/MDC.rb +59 -0
  45. data/lib/log4r/NDC.rb +86 -0
  46. data/lib/log4r/base.rb +74 -0
  47. data/lib/log4r/config.rb +9 -0
  48. data/lib/log4r/configurator.rb +224 -0
  49. data/lib/log4r/formatter/formatter.rb +105 -0
  50. data/lib/log4r/formatter/log4jxmlformatter.rb +61 -0
  51. data/lib/log4r/formatter/patternformatter.rb +145 -0
  52. data/lib/log4r/lib/drbloader.rb +52 -0
  53. data/lib/log4r/lib/xmlloader.rb +24 -0
  54. data/lib/log4r/logevent.rb +28 -0
  55. data/lib/log4r/logger.rb +199 -0
  56. data/lib/log4r/loggerfactory.rb +89 -0
  57. data/lib/log4r/logserver.rb +28 -0
  58. data/lib/log4r/outputter/consoleoutputters.rb +18 -0
  59. data/lib/log4r/outputter/datefileoutputter.rb +117 -0
  60. data/lib/log4r/outputter/emailoutputter.rb +143 -0
  61. data/lib/log4r/outputter/fileoutputter.rb +56 -0
  62. data/lib/log4r/outputter/iooutputter.rb +55 -0
  63. data/lib/log4r/outputter/outputter.rb +134 -0
  64. data/lib/log4r/outputter/outputterfactory.rb +61 -0
  65. data/lib/log4r/outputter/remoteoutputter.rb +40 -0
  66. data/lib/log4r/outputter/rollingfileoutputter.rb +234 -0
  67. data/lib/log4r/outputter/scribeoutputter.rb +37 -0
  68. data/lib/log4r/outputter/staticoutputter.rb +30 -0
  69. data/lib/log4r/outputter/syslogoutputter.rb +130 -0
  70. data/lib/log4r/outputter/udpoutputter.rb +53 -0
  71. data/lib/log4r/rdoc/GDC +14 -0
  72. data/lib/log4r/rdoc/MDC +16 -0
  73. data/lib/log4r/rdoc/NDC +41 -0
  74. data/lib/log4r/rdoc/configurator +243 -0
  75. data/lib/log4r/rdoc/emailoutputter +103 -0
  76. data/lib/log4r/rdoc/formatter +39 -0
  77. data/lib/log4r/rdoc/log4r +89 -0
  78. data/lib/log4r/rdoc/logger +175 -0
  79. data/lib/log4r/rdoc/logserver +85 -0
  80. data/lib/log4r/rdoc/outputter +108 -0
  81. data/lib/log4r/rdoc/patternformatter +128 -0
  82. data/lib/log4r/rdoc/scribeoutputter +16 -0
  83. data/lib/log4r/rdoc/syslogoutputter +29 -0
  84. data/lib/log4r/rdoc/win32eventoutputter +7 -0
  85. data/lib/log4r/rdoc/yamlconfigurator +20 -0
  86. data/lib/log4r/repository.rb +88 -0
  87. data/lib/log4r/staticlogger.rb +49 -0
  88. data/lib/log4r/yamlconfigurator.rb +196 -0
  89. data/tests/README +10 -0
  90. data/tests/testGDC.rb +26 -0
  91. data/tests/testMDC.rb +42 -0
  92. data/tests/testNDC.rb +27 -0
  93. data/tests/testall.rb +6 -0
  94. data/tests/testbase.rb +49 -0
  95. data/tests/testchainsaw.rb +48 -0
  96. data/tests/testconf.xml +37 -0
  97. data/tests/testcustom.rb +27 -0
  98. data/tests/testformatter.rb +27 -0
  99. data/tests/testlogger.rb +196 -0
  100. data/tests/testoutputter.rb +132 -0
  101. data/tests/testpatternformatter.rb +78 -0
  102. data/tests/testthreads.rb +35 -0
  103. data/tests/testxmlconf.rb +45 -0
  104. metadata +184 -0
@@ -0,0 +1,105 @@
1
+ # :include: ../rdoc/formatter
2
+ #
3
+ # Version:: $Id$
4
+
5
+ require "singleton"
6
+
7
+ require "log4r/base"
8
+
9
+ module Log4r
10
+
11
+ # Formatter is an abstract class and a null object
12
+ class Formatter
13
+ def initialize(hash={})
14
+ end
15
+ # Define this method in a subclass to format data.
16
+ def format(logevent)
17
+ end
18
+ end
19
+
20
+ # SimpleFormatter produces output like this:
21
+ #
22
+ # WARN loggername> Danger, Will Robinson, danger!
23
+ #
24
+ # Does not write traces and does not inspect objects.
25
+
26
+ class SimpleFormatter < Formatter
27
+ def format(event)
28
+ sprintf("%*s %s> %s\n", MaxLevelLength, LNAMES[event.level],
29
+ event.name, event.data)
30
+ end
31
+ end
32
+
33
+ # BasicFormatter produces output like this:
34
+ #
35
+ # WARN loggername: I dropped my Wookie!
36
+ #
37
+ # Or like this if trace is on:
38
+ #
39
+ # WARN loggername(file.rb at 12): Hot potato!
40
+ #
41
+ # Also, it will pretty-print any Exception it gets and
42
+ # +inspect+ everything else.
43
+ #
44
+ # Hash arguments include:
45
+ #
46
+ # +depth+:: How many lines of the stacktrace to display.
47
+
48
+ class BasicFormatter < SimpleFormatter
49
+ @@basicformat = "%*s %s"
50
+
51
+ def initialize(hash={})
52
+ @depth = (hash[:depth] or hash['depth'] or 7).to_i
53
+ end
54
+
55
+ def format(event)
56
+ buff = sprintf(@@basicformat, MaxLevelLength, LNAMES[event.level],
57
+ event.name)
58
+ buff << (event.tracer.nil? ? "" : "(#{event.tracer[0]})") + ": "
59
+ buff << format_object(event.data) + "\n"
60
+ buff
61
+ end
62
+
63
+ # Formats data according to its class:
64
+ #
65
+ # String:: Prints it out as normal.
66
+ # Exception:: Produces output similar to command-line exceptions.
67
+ # Object:: Prints the type of object, then the output of
68
+ # +inspect+. An example -- Array: [1, 2, 3]
69
+
70
+ def format_object(obj)
71
+ if obj.kind_of? Exception
72
+ return "Caught #{obj.class}: #{obj.message}\n\t" +\
73
+ obj.backtrace[0...@depth].join("\n\t")
74
+ elsif obj.kind_of? String
75
+ return obj
76
+ else # inspect the object
77
+ return "#{obj.class}: #{obj.inspect}"
78
+ end
79
+ end
80
+ end
81
+
82
+ # Formats objects the same way irb does:
83
+ #
84
+ # loggername:foo.rb in 12>
85
+ # [1, 3, 4]
86
+ # loggername:foo.rb in 13>
87
+ # {1=>"1"}
88
+ #
89
+ # Strings don't get inspected. just printed. The trace is optional.
90
+
91
+ class ObjectFormatter < Formatter
92
+ def format(event)
93
+ buff = event.logger.name
94
+ buff << (event.tracer.nil? ? "" : ":#{event.tracer[0]}") + ">\n"
95
+ buff << (event.data.kind_of?(String) ? event.data : event.data.inspect)
96
+ buff << "\n"
97
+ end
98
+ end
99
+
100
+ # Outputters that don't define a Formatter will get this, which
101
+ # is currently BasicFormatter
102
+ class DefaultFormatter < BasicFormatter
103
+ end
104
+
105
+ end
@@ -0,0 +1,61 @@
1
+ # :include: ../rdoc/log4jxmlformatter
2
+ #
3
+ # == Other Info
4
+ #
5
+ # Version:: $Id$
6
+
7
+ require "log4r/formatter/formatter"
8
+
9
+ require "rubygems"
10
+ require "builder"
11
+
12
+ module Log4r
13
+
14
+ class Log4jXmlFormatter < BasicFormatter
15
+
16
+ def format(logevent)
17
+ logger = logevent.fullname.gsub('::', '.')
18
+ timestamp = (Time.now.to_f * 1000).to_i
19
+ level = LNAMES[logevent.level]
20
+ message = format_object(logevent.data)
21
+ exception = message if logevent.data.kind_of? Exception
22
+ file, line, method = parse_caller(logevent.tracer[0]) if logevent.tracer
23
+
24
+ builder = Builder::XmlMarkup.new
25
+ xml = builder.log4j :event, :logger => logger,
26
+ :timestamp => timestamp,
27
+ :level => level,
28
+ :thread => '' do |e|
29
+ e.log4j :NDC, NDC.get
30
+ e.log4j :message, message
31
+ e.log4j :throwable, exception if exception
32
+ e.log4j :locationInfo, :class => '',
33
+ :method => method,
34
+ :file => file,
35
+ :line => line
36
+ e.log4j :properties do |p|
37
+ MDC.get_context.each do |key, value|
38
+ p.log4j :data, :name => key, :value => value
39
+ end
40
+ end
41
+ end
42
+ xml
43
+ end
44
+
45
+ #######
46
+ private
47
+ #######
48
+
49
+ def parse_caller(line)
50
+ if /^(.+?):(\d+)(?::in `(.*)')?/ =~ line
51
+ file = Regexp.last_match[1]
52
+ line = Regexp.last_match[2].to_i
53
+ method = Regexp.last_match[3]
54
+ [file, line, method]
55
+ else
56
+ []
57
+ end
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,145 @@
1
+ # :include: ../rdoc/patternformatter
2
+ #
3
+ # == Other Info
4
+ #
5
+ # Version:: $Id$
6
+
7
+ require "log4r/formatter/formatter"
8
+ require "log4r/GDC"
9
+ require "log4r/MDC"
10
+ require "log4r/NDC"
11
+
12
+ module Log4r
13
+ # See log4r/formatter/patternformatter.rb
14
+ class PatternFormatter < BasicFormatter
15
+
16
+ # Arguments to sprintf keyed to directive letters<br>
17
+ # %c - event short name<br>
18
+ # %C - event fullname<br>
19
+ # %d - date<br>
20
+ # %g - Global Diagnostic Context (GDC)<br>
21
+ # %t - trace<br>
22
+ # %m - message<br>
23
+ # %h - thread name<br>
24
+ # %p - process ID aka PID<br>
25
+ # %M - formatted message<br>
26
+ # %l - Level in string form<br>
27
+ # %x - Nested Diagnostic Context (NDC)<br>
28
+ # %X - Mapped Diagnostic Context (MDC), syntax is "%X{key}"<br>
29
+ # %% - Insert a %<br>
30
+ DirectiveTable = {
31
+ "c" => 'event.name',
32
+ "C" => 'event.fullname',
33
+ "d" => 'format_date',
34
+ "g" => 'Log4r::GDC.get()',
35
+ "t" => '(event.tracer.nil? ? "no trace" : event.tracer[0])',
36
+ "T" => '(event.tracer.nil? ? "no trace" : event.tracer[0].split(File::SEPARATOR)[-1])',
37
+ "m" => 'event.data',
38
+ "h" => '(Thread.current[:name] or Thread.current.to_s)',
39
+ "p" => 'Process.pid.to_s',
40
+ "M" => 'format_object(event.data)',
41
+ "l" => 'LNAMES[event.level]',
42
+ "x" => 'Log4r::NDC.get()',
43
+ "X" => 'Log4r::MDC.get("DTR_REPLACE")',
44
+ "%" => '"%"'
45
+ }
46
+
47
+ # Matches the first directive encountered and the stuff around it.
48
+ #
49
+ # * $1 is the stuff before directive or "" if not applicable
50
+ # * $2 is the directive group or nil if there's none
51
+ # * $3 is the %#.# match within directive group
52
+ # * $4 is the .# match which we don't use (it's there to match properly)
53
+ # * $5 is the directive letter
54
+ # * $6 is the stuff after the directive or "" if not applicable
55
+ # * $7 is the remainder
56
+
57
+ DirectiveRegexp = /([^%]*)((%-?\d*(\.\d+)?)([cCdgtTmhpMlxX%]))?(\{.+?\})?(.*)/
58
+
59
+ # default date format
60
+ ISO8601 = "%Y-%m-%d %H:%M:%S"
61
+
62
+ attr_reader :pattern, :date_pattern, :date_method
63
+
64
+ # Accepts the following hash arguments (either a string or a symbol):
65
+ #
66
+ # [<tt>pattern</tt>] A pattern format string.
67
+ # [<tt>date_pattern</tt>] A Time#strftime format string. See the
68
+ # Ruby Time class for details.
69
+ # [+date_method+]
70
+ # As an option to date_pattern, specify which
71
+ # Time.now method to call. For
72
+ # example, +usec+ or +to_s+.
73
+ # Specify it as a String or Symbol.
74
+ #
75
+ # The default date format is ISO8601, which looks like this:
76
+ #
77
+ # yyyy-mm-dd hh:mm:ss => 2001-01-12 13:15:50
78
+
79
+ def initialize(hash={})
80
+ super(hash)
81
+ @pattern = (hash['pattern'] or hash[:pattern] or nil)
82
+ @date_pattern = (hash['date_pattern'] or hash[:date_pattern] or nil)
83
+ @date_method = (hash['date_method'] or hash[:date_method] or nil)
84
+ @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
85
+ PatternFormatter.create_format_methods(self)
86
+ end
87
+
88
+ # PatternFormatter works by dynamically defining a <tt>format</tt> method
89
+ # based on the supplied pattern format. This method contains a call to
90
+ # Kernel#sptrintf with arguments containing the data requested in
91
+ # the pattern format.
92
+ #
93
+ # How is this magic accomplished? First, we visit each directive
94
+ # and change the %#.# component to %#.#s. The directive letter is then
95
+ # used to cull an appropriate entry from the DirectiveTable for the
96
+ # sprintf argument list. After assembling the method definition, we
97
+ # run module_eval on it, and voila.
98
+
99
+ def PatternFormatter.create_format_methods(pf) #:nodoc:
100
+ # first, define the format_date method
101
+ if pf.date_method
102
+ module_eval "def pf.format_date; Time.now.#{pf.date_method}; end"
103
+ else
104
+ module_eval <<-EOS
105
+ def pf.format_date
106
+ Time.now.strftime "#{pf.date_pattern}"
107
+ end
108
+ EOS
109
+ end
110
+ # and now the main format method
111
+ ebuff = "def pf.format(event)\n sprintf(\""
112
+ _pattern = pf.pattern.dup
113
+ args = [] # the args to sprintf which we'll append to ebuff lastly
114
+ while true # work on each match in turn
115
+ match = DirectiveRegexp.match _pattern
116
+ ebuff << match[1] unless match[1].empty?
117
+ break if match[2].nil?
118
+ # deal with the directive by inserting a %#.#s where %#.# is copied
119
+ # directy from the match
120
+ ebuff << match[3] + "s"
121
+
122
+ if ( match[5] == 'X' && match[6] != nil ) then
123
+
124
+ # MDC matches, need to be able to handle String, Symbol or Number
125
+ match6sub = /[\{\}\"]/
126
+ mdcmatches = match[6].match /\{(:?)(\d*)(.*)\}/
127
+
128
+ if ( mdcmatches[1] == "" && mdcmatches[2] == "" )
129
+ match6sub = /[\{\}]/ # don't remove surrounding "'s if String
130
+ end
131
+
132
+ args <<
133
+ DirectiveTable[match[5]].gsub("DTR_REPLACE", match[6]).gsub(match6sub,'')
134
+ else
135
+ args << DirectiveTable[match[5]] # cull the data for our argument list
136
+ end
137
+ break if match[7].empty?
138
+ _pattern = match[7]
139
+ end
140
+ ebuff << '\n", ' + args.join(', ') + ")\n"
141
+ ebuff << "end\n"
142
+ module_eval ebuff
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,52 @@
1
+ #:nodoc:
2
+ module Log4r
3
+ begin
4
+ require 'romp'
5
+ HAVE_ROMP = true
6
+ rescue LoadError
7
+ HAVE_ROMP = false
8
+ end
9
+
10
+ if HAVE_ROMP
11
+
12
+ module ROMPServer #:nodoc:
13
+ private
14
+ def start_server(_uri, accept)
15
+ @server = ROMP::Server.new(_uri, accept) # what if accept is nil?
16
+ @server.bind(self, "Log4r::LogServer")
17
+ end
18
+ end
19
+
20
+ module ROMPClient #:nodoc:
21
+ private
22
+ def connect
23
+ begin
24
+ @client = ROMP::Client.new(@uri, false)
25
+ @remote_logger = @client.resolve("Log4r::LogServer")
26
+ rescue Exception => e
27
+ Logger.log_internal(-2) {
28
+ "RemoteOutputter '#{@name}' failed to connect to #{@uri}!"
29
+ }
30
+ Logger.log_internal {e}
31
+ self.level = OFF
32
+ end
33
+ end
34
+ # we use propagated = true
35
+ def send_buffer
36
+ begin
37
+ @buff.each {|levent|
38
+ lname = LNAMES[levent.level].downcase
39
+ @remote_logger.oneway(lname, levent, true)
40
+ }
41
+ rescue Exception => e
42
+ Logger.log_internal(-2) {"RemoteOutputter '#{@name}' can't log!"}
43
+ Logger.log_internal {e}
44
+ self.level = OFF
45
+ ensure @buff.clear
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,24 @@
1
+ #:nodoc:
2
+ module Log4r
3
+ begin
4
+ require 'rexml/document'
5
+ HAVE_REXML = true
6
+ rescue LoadError
7
+ HAVE_REXML = false
8
+ end
9
+ end
10
+
11
+ if Log4r::HAVE_REXML
12
+ module REXML #:nodoc: all
13
+ class Element
14
+ def value_of(elmt)
15
+ val = attributes[elmt]
16
+ if val.nil?
17
+ sub = elements[elmt]
18
+ val = sub.text unless sub.nil?
19
+ end
20
+ val
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # :nodoc:
2
+ module Log4r
3
+
4
+ ##
5
+ # LogEvent wraps up all the miscellaneous data associated with a logging
6
+ # statement. It gets passed around to the varied components of Log4r and
7
+ # should be of interest to those creating extensions.
8
+ #
9
+ # Data contained:
10
+ #
11
+ # [level] The integer level of the log event. Use LNAMES[level]
12
+ # to get the actual level name.
13
+ # [tracer] The execution stack returned by <tt>caller</tt> at the
14
+ # log event. It is nil if the invoked Logger's trace is false.
15
+ # [data] The object that was passed into the logging method.
16
+ # [name] The name of the logger that was invoked.
17
+ # [fullname] The fully qualified name of the logger that was invoked.
18
+ #
19
+ # Note that creating timestamps is a task left to formatters.
20
+
21
+ class LogEvent
22
+ attr_reader :level, :tracer, :data, :name, :fullname
23
+ def initialize(level, logger, tracer, data)
24
+ @level, @tracer, @data = level, tracer, data
25
+ @name, @fullname = logger.name, logger.fullname
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,199 @@
1
+ # :include: rdoc/logger
2
+ #
3
+ # == Other Info
4
+ #
5
+ # Version:: $Id$
6
+ # Author:: Leon Torres <leon(at)ugcs.caltech.edu>
7
+
8
+ require "log4r/outputter/outputter"
9
+ require "log4r/repository"
10
+ require "log4r/loggerfactory"
11
+ require "log4r/staticlogger"
12
+
13
+ module Log4r
14
+
15
+ # See log4r/logger.rb
16
+ class Logger
17
+ attr_reader :name, :fullname, :path, :level, :parent
18
+ attr_reader :additive, :trace, :outputters
19
+
20
+ # Logger requires a name. The last 3 parameters are:
21
+ #
22
+ # level:: Do I have a level? (Otherwise, I'll inherit my parent's)
23
+ # additive:: Am I additive?
24
+ # trace:: Do I record the execution trace? (slows things a wee bit)
25
+
26
+ def initialize(_fullname, _level=nil, _additive=true, _trace=false)
27
+ # validation
28
+ raise ArgumentError, "Logger must have a name", caller if _fullname.nil?
29
+ Log4rTools.validate_level(_level) unless _level.nil?
30
+ validate_name(_fullname)
31
+
32
+ # create the logger
33
+ @fullname = _fullname
34
+ @outputters = []
35
+ @additive = _additive
36
+ deal_with_inheritance(_level)
37
+ LoggerFactory.define_methods(self)
38
+ self.trace = _trace
39
+ Repository[@fullname] = self
40
+ end
41
+
42
+ def validate_name(_fullname)
43
+ parts = _fullname.split Log4rConfig::LoggerPathDelimiter
44
+ for part in parts
45
+ raise ArgumentError, "Malformed path", caller[1..-1] if part.empty?
46
+ end
47
+ end
48
+ private :validate_name
49
+
50
+ # Parses name for location in heiarchy, sets the parent, and
51
+ # deals with level inheritance
52
+
53
+ def deal_with_inheritance(_level)
54
+ mypath = @fullname.split Log4rConfig::LoggerPathDelimiter
55
+ @name = mypath.pop
56
+ if mypath.empty? # then root is my daddy
57
+ @path = ""
58
+ # This is one of the guarantees that RootLogger gets created
59
+ @parent = Logger.root
60
+ else
61
+ @path = mypath.join(Log4rConfig::LoggerPathDelimiter)
62
+ @parent = Repository.find_ancestor(@path)
63
+ @parent = Logger.root if @parent.nil?
64
+ end
65
+ # inherit the level if no level defined
66
+ if _level.nil? then @level = @parent.level
67
+ else @level = _level end
68
+ Repository.reassign_any_children(self)
69
+ end
70
+ private :deal_with_inheritance
71
+
72
+ # Set the logger level dynamically. Does not affect children.
73
+ def level=(_level)
74
+ Log4rTools.validate_level(_level)
75
+ @level = _level
76
+ LoggerFactory.define_methods(self)
77
+ Logger.log_internal {"Logger '#{@fullname}' set to #{LNAMES[@level]}"}
78
+ @level
79
+ end
80
+
81
+ # Return array of defined levels.
82
+ def levels
83
+ LNAMES
84
+ end
85
+
86
+ # Set the additivity of the logger dynamically. True or false.
87
+ def additive=(_additive)
88
+ @additive = _additive
89
+ LoggerFactory.define_methods(self)
90
+ Logger.log_internal {"Logger '#{@fullname}' is additive"}
91
+ @additive
92
+ end
93
+
94
+ # Set whether the logger traces. Can be set dynamically. Defaults
95
+ # to false and understands the strings 'true' and 'false'.
96
+ def trace=(_trace)
97
+ @trace =
98
+ case _trace
99
+ when "true", true then true
100
+ else false end
101
+ LoggerFactory.define_methods(self)
102
+ Logger.log_internal {"Logger '#{@fullname}' is tracing"} if @trace
103
+ @trace
104
+ end
105
+
106
+ # Please don't reset the parent
107
+ def parent=(parent)
108
+ @parent = parent
109
+ end
110
+
111
+ # Set the Outputters dynamically by name or reference. Can be done any
112
+ # time.
113
+ def outputters=(_outputters)
114
+ @outputters.clear
115
+ add(*_outputters)
116
+ end
117
+
118
+ # Add outputters by name or by reference. Can be done any time.
119
+ def add(*_outputters)
120
+ for thing in _outputters
121
+ o = (thing.kind_of?(Outputter) ? thing : Outputter[thing])
122
+ # some basic validation
123
+ if not o.kind_of?(Outputter)
124
+ raise TypeError, "Expected kind of Outputter, got #{o.class}", caller
125
+ elsif o.nil?
126
+ raise TypeError, "Couldn't find Outputter '#{thing}'", caller
127
+ end
128
+ @outputters.push o
129
+ Logger.log_internal {"Added outputter '#{o.name}' to '#{@fullname}'"}
130
+ end
131
+ @outputters
132
+ end
133
+
134
+ # Remove outputters from this logger by name only. Can be done any time.
135
+ def remove(*_outputters)
136
+ for name in _outputters
137
+ o = Outputter[name]
138
+ @outputters.delete o
139
+ Logger.log_internal {"Removed outputter '#{o.name}' from '#{@fullname}'"}
140
+ end
141
+ end
142
+
143
+ def is_root?; false end
144
+
145
+ def ==(other)
146
+ return true if self.object_id == other.object_id
147
+ end
148
+ end
149
+
150
+
151
+ # RootLogger should be retrieved with Logger.root or Logger.global.
152
+ # It's supposed to be transparent.
153
+ #--
154
+ # We must guarantee the creation of RootLogger before any other Logger
155
+ # or Outputter gets their logging methods defined. There are two
156
+ # guarantees in the code:
157
+ #
158
+ # * Logger#deal_with_inheritance - calls RootLogger.instance when
159
+ # a new Logger is created without a parent. Parents must exist, therefore
160
+ # RootLogger is forced to be created.
161
+ #
162
+ # * OutputterFactory.create_methods - Calls Logger.root first. So if
163
+ # an Outputter is created, RootLogger is also created.
164
+ #
165
+ # When RootLogger is created, it calls
166
+ # Log4r.define_levels(*Log4rConfig::LogLevels). This ensures that the
167
+ # default levels are loaded if no custom ones are.
168
+
169
+ class RootLogger < Logger
170
+ include Singleton
171
+
172
+ def initialize
173
+ Log4r.define_levels(*Log4rConfig::LogLevels) # ensure levels are loaded
174
+ @level = ALL
175
+ @outputters = []
176
+ Repository['root'] = self
177
+ Repository['global'] = self
178
+ LoggerFactory.undefine_methods(self)
179
+ end
180
+
181
+ def is_root?; true end
182
+
183
+ # Set the global level. Any loggers defined thereafter will
184
+ # not log below the global level regardless of their levels.
185
+
186
+ def level=(alevel); @level = alevel end
187
+
188
+ # Does nothing
189
+ def outputters=(foo); end
190
+ # Does nothing
191
+ def trace=(foo); end
192
+ # Does nothing
193
+ def additive=(foo); end
194
+ # Does nothing
195
+ def add(*foo); end
196
+ # Does nothing
197
+ def remove(*foo); end
198
+ end
199
+ end