filterfish-logging 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/History.txt +176 -0
  2. data/Manifest.txt +54 -0
  3. data/README.txt +93 -0
  4. data/Rakefile +28 -0
  5. data/data/logging.yaml +63 -0
  6. data/lib/logging.rb +288 -0
  7. data/lib/logging/appender.rb +257 -0
  8. data/lib/logging/appenders/console.rb +43 -0
  9. data/lib/logging/appenders/email.rb +131 -0
  10. data/lib/logging/appenders/file.rb +55 -0
  11. data/lib/logging/appenders/growl.rb +182 -0
  12. data/lib/logging/appenders/io.rb +81 -0
  13. data/lib/logging/appenders/rolling_file.rb +293 -0
  14. data/lib/logging/appenders/syslog.rb +202 -0
  15. data/lib/logging/config/yaml_configurator.rb +197 -0
  16. data/lib/logging/layout.rb +103 -0
  17. data/lib/logging/layouts/basic.rb +35 -0
  18. data/lib/logging/layouts/pattern.rb +292 -0
  19. data/lib/logging/log_event.rb +50 -0
  20. data/lib/logging/logger.rb +388 -0
  21. data/lib/logging/repository.rb +151 -0
  22. data/lib/logging/root_logger.rb +60 -0
  23. data/lib/logging/utils.rb +44 -0
  24. data/tasks/ann.rake +78 -0
  25. data/tasks/bones.rake +21 -0
  26. data/tasks/gem.rake +106 -0
  27. data/tasks/manifest.rake +49 -0
  28. data/tasks/notes.rake +22 -0
  29. data/tasks/post_load.rake +37 -0
  30. data/tasks/rdoc.rake +49 -0
  31. data/tasks/rubyforge.rake +57 -0
  32. data/tasks/setup.rb +253 -0
  33. data/tasks/svn.rake +45 -0
  34. data/tasks/test.rake +38 -0
  35. data/test/appenders/test_console.rb +40 -0
  36. data/test/appenders/test_email.rb +167 -0
  37. data/test/appenders/test_file.rb +94 -0
  38. data/test/appenders/test_growl.rb +115 -0
  39. data/test/appenders/test_io.rb +113 -0
  40. data/test/appenders/test_rolling_file.rb +187 -0
  41. data/test/appenders/test_syslog.rb +192 -0
  42. data/test/benchmark.rb +88 -0
  43. data/test/config/test_yaml_configurator.rb +41 -0
  44. data/test/layouts/test_basic.rb +44 -0
  45. data/test/layouts/test_pattern.rb +173 -0
  46. data/test/setup.rb +66 -0
  47. data/test/test_appender.rb +162 -0
  48. data/test/test_layout.rb +85 -0
  49. data/test/test_log_event.rb +81 -0
  50. data/test/test_logger.rb +589 -0
  51. data/test/test_logging.rb +250 -0
  52. data/test/test_repository.rb +123 -0
  53. data/test/test_root_logger.rb +82 -0
  54. data/test/test_utils.rb +48 -0
  55. metadata +126 -0
@@ -0,0 +1,35 @@
1
+ # $Id$
2
+
3
+ module Logging
4
+ module Layouts
5
+
6
+ # The +Basic+ layout class provides methods for simple formatting of log
7
+ # events. The resulting string follows the format below.
8
+ #
9
+ # LEVEL LoggerName : log message
10
+ #
11
+ # _LEVEL_ is the log level of the event. _LoggerName_ is the name of the
12
+ # logger that generated the event. <em>log message</em> is the message
13
+ # or object that was passed to the logger. If multiple message or objects
14
+ # were passed to the logger then each will be printed on its own line with
15
+ # the format show above.
16
+ #
17
+ class Basic < ::Logging::Layout
18
+
19
+ # call-seq:
20
+ # format( event )
21
+ #
22
+ # Returns a string representation of the given loggging _event_. See the
23
+ # class documentation for details about the formatting used.
24
+ #
25
+ def format( event )
26
+ obj = format_obj(event.data)
27
+ sprintf("%*s %s : %s\n", ::Logging::MAX_LEVEL_LENGTH,
28
+ ::Logging::LNAMES[event.level], event.logger, obj)
29
+ end
30
+
31
+ end # class Basic
32
+ end # module Layouts
33
+ end # module Logging
34
+
35
+ # EOF
@@ -0,0 +1,292 @@
1
+ # $Id$
2
+
3
+ module Logging
4
+ module Layouts
5
+
6
+ # A flexible layout configurable with pattern string.
7
+ #
8
+ # The goal of this class is to format a LogEvent and return the results as
9
+ # a String. The results depend on the conversion pattern.
10
+ #
11
+ # The conversion pattern is closely related to the conversion pattern of
12
+ # the sprintf function. A conversion pattern is composed of literal text
13
+ # and format control expressions called conversion specifiers.
14
+ #
15
+ # You are free to insert any literal text within the conversion pattern.
16
+ #
17
+ # Each conversion specifier starts with a percent sign (%) and is followed
18
+ # by optional format modifiers and a conversion character. The conversion
19
+ # character specifies the type of data, e.g. logger, level, date, thread
20
+ # ID. The format modifiers control such things as field width, padding,
21
+ # left and right justification. The following is a simple example.
22
+ #
23
+ # Let the conversion pattern be "%-5l [%c]: %m\n" and assume that the
24
+ # logging environment was set to use a Pattern layout. Then the statements
25
+ #
26
+ # root = Logging::Logger[:root]
27
+ # root.debug("Message 1")
28
+ # root.warn("Message 2")
29
+ #
30
+ # would yield the output
31
+ #
32
+ # DEBUG [root]: Message 1
33
+ # WARN [root]: Message 2
34
+ #
35
+ # Note that there is no explicit separator between text and conversion
36
+ # specifiers. The pattern parser knows when it has reached the end of a
37
+ # conversion specifier when it reads a conversion character. In the example
38
+ # above the conversion specifier %-5l means the level of the logging event
39
+ # should be left justified to a width of five characters. The recognized
40
+ # conversion characters are
41
+ #
42
+ # [c] Used to output the name of the logger that generated the log
43
+ # event.
44
+ # [d] Used to output the date of the log event. The format of the
45
+ # date is specified using the :date_pattern option when the Layout
46
+ # is created. ISO8601 format is assumed if not date pattern is given.
47
+ # [F] Used to output the file name where the logging request was issued.
48
+ # [l] Used to output the level of the log event.
49
+ # [L] Used to output the line number where the logging request was
50
+ # issued.
51
+ # [m] Used to output the application supplied message associated with
52
+ # the log event.
53
+ # [M] Used to output the method name where the logging request was
54
+ # issued.
55
+ # [p] Used to output the process ID of the currently running program.
56
+ # [r] Used to output the number of milliseconds elapsed from the
57
+ # construction of the Layout until creation of the log event.
58
+ # [t] Used to output the object ID of the thread that generated the
59
+ # log event.
60
+ # [%] The sequence '%%' outputs a single percent sign.
61
+ #
62
+ # The directives F, L, and M will only work if the Logger generating the
63
+ # events is configured to generate tracing information. If this is not
64
+ # the case these fields will always be empty.
65
+ #
66
+ # By default the relevant information is output as is. However, with the
67
+ # aid of format modifiers it is possible to change the minimum field width,
68
+ # the maximum field width and justification.
69
+ #
70
+ # The optional format modifier is placed between the percent sign and the
71
+ # conversion character.
72
+ #
73
+ # The first optional format modifier is the left justification flag which
74
+ # is just the minus (-) character. Then comes the optional minimum field
75
+ # width modifier. This is a decimal constant that represents the minimum
76
+ # number of characters to output. If the data item requires fewer
77
+ # characters, it is padded on either the left or the right until the
78
+ # minimum width is reached. The default is to pad on the left (right
79
+ # justify) but you can specify right padding with the left justification
80
+ # flag. The padding character is space. If the data item is larger than the
81
+ # minimum field width, the field is expanded to accommodate the data. The
82
+ # value is never truncated.
83
+ #
84
+ # This behavior can be changed using the maximum field width modifier which
85
+ # is designated by a period followed by a decimal constant. If the data
86
+ # item is longer than the maximum field, then the extra characters are
87
+ # removed from the end of the data item.
88
+ #
89
+ # Below are various format modifier examples for the category conversion
90
+ # specifier.
91
+ #
92
+ # [%20c] Left pad with spaces if the logger name is less than 20
93
+ # characters long
94
+ # [%-20c] Right pad with spaces if the logger name is less than 20
95
+ # characters long
96
+ # [%.30c] Truncates the logger name if it is longer than 30 characters
97
+ # [%20.30c] Left pad with spaces if the logger name is shorter than
98
+ # 20 characters. However, if the logger name is longer than
99
+ # 30 characters, then truncate the name.
100
+ # [%-20.30c] Right pad with spaces if the logger name is shorter than
101
+ # 20 characters. However, if the logger name is longer than
102
+ # 30 characters, then truncate the name.
103
+ #
104
+ # Below are examples of some conversion patterns.
105
+ #
106
+ # %.1l, [%d] %5l -- %c: %m\n
107
+ #
108
+ # This is how the Logger class in the Ruby standard library formats
109
+ # messages. The main difference will be in the date format (the Pattern
110
+ # Layout uses the ISO8601 date format). Set the :date_method on the
111
+ # Pattern Layout to be 'to_s' and then the date formats will agree.
112
+ #
113
+ class Pattern < ::Logging::Layout
114
+
115
+ # :stopdoc:
116
+
117
+ # Arguments to sprintf keyed to directive letters
118
+ DIRECTIVE_TABLE = {
119
+ 'c' => 'event.logger',
120
+ 'd' => 'format_date',
121
+ 'F' => 'event.file',
122
+ 'l' => '::Logging::LNAMES[event.level]',
123
+ 'L' => 'event.line',
124
+ 'm' => 'format_obj(event.data)',
125
+ 'M' => 'event.method',
126
+ 'p' => 'Process.pid',
127
+ 'r' => 'Integer((Time.now-@created_at)*1000).to_s',
128
+ 't' => 'Thread.current.object_id.to_s',
129
+ '%' => :placeholder
130
+ }
131
+
132
+ # Matches the first directive encountered and the stuff around it.
133
+ #
134
+ # * $1 is the stuff before directive or "" if not applicable
135
+ # * $2 is the %#.# match within directive group
136
+ # * $3 is the directive letter
137
+ # * $4 is the stuff after the directive or "" if not applicable
138
+ DIRECTIVE_RGXP = %r/([^%]*)(?:(%-?\d*(?:\.\d+)?)([a-zA-Z%]))?(.*)/m
139
+
140
+ # default date format
141
+ ISO8601 = "%Y-%m-%d %H:%M:%S"
142
+
143
+ # call-seq:
144
+ # Pattern.create_date_format_methods( pf )
145
+ #
146
+ # This method will create the +date_format+ method in the given Pattern
147
+ # Layout _pf_ based on the configured date patten and/or date method
148
+ # specified by the user.
149
+ #
150
+ def self.create_date_format_methods( pf )
151
+ code = "undef :format_date if method_defined? :format_date\n"
152
+ code << "def format_date\n"
153
+ if pf.date_method.nil?
154
+ if pf.date_pattern =~ %r/%s/
155
+ code << <<-CODE
156
+ now = Time.now
157
+ dp = '#{pf.date_pattern}'.gsub('%s','%06d' % now.usec)
158
+ now.strftime dp
159
+ CODE
160
+ else
161
+ code << "Time.now.strftime '#{pf.date_pattern}'\n"
162
+ end
163
+ else
164
+ code << "Time.now.#{pf.date_method}\n"
165
+ end
166
+ code << "end\n"
167
+
168
+ pf.meta_eval code
169
+ end
170
+
171
+ # call-seq:
172
+ # Pattern.create_format_method( pf )
173
+ #
174
+ # This method will create the +format+ method in the given Pattern
175
+ # Layout _pf_ based on the configured format pattern specified by the
176
+ # user.
177
+ #
178
+ def self.create_format_method( pf )
179
+ # Create the format(event) method
180
+ code = "undef :format if method_defined? :format\n"
181
+ code << "def format( event )\nsprintf(\""
182
+ pattern = pf.pattern.dup
183
+ args = []
184
+
185
+ while true
186
+ m = DIRECTIVE_RGXP.match(pattern)
187
+ code << m[1] unless m[1].empty?
188
+
189
+ case m[3]
190
+ when '%'; code << '%%'
191
+ when *DIRECTIVE_TABLE.keys
192
+ code << m[2] + 's'
193
+ args << DIRECTIVE_TABLE[m[3]]
194
+ when nil; break
195
+ else
196
+ raise ArgumentError, "illegal format character - '#{m[3]}'"
197
+ end
198
+
199
+ break if m[4].empty?
200
+ pattern = m[4]
201
+ end
202
+
203
+ code << '"'
204
+ code << ', ' + args.join(', ') unless args.empty?
205
+ code << ")\n"
206
+ code << "end\n"
207
+
208
+ pf.meta_eval code
209
+ end
210
+ # :startdoc:
211
+
212
+ # call-seq:
213
+ # Pattern.new( opts )
214
+ #
215
+ # Creates a new Pattern layout using the following options.
216
+ #
217
+ # :pattern => "[%d] %-5l -- %c : %m\n"
218
+ # :date_pattern => "%Y-%m-%d %H:%M:%S"
219
+ # :date_method => 'usec' or 'to_s'
220
+ #
221
+ # If used, :date_method will supersede :date_pattern.
222
+ #
223
+ def initialize( opts = {} )
224
+ super
225
+ @created_at = Time.now
226
+
227
+ @date_pattern = opts.getopt(:date_pattern)
228
+ @date_method = opts.getopt(:date_method)
229
+ @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
230
+
231
+ @pattern = opts.getopt(:pattern,
232
+ "[%d] %-#{::Logging::MAX_LEVEL_LENGTH}l -- %c : %m\n")
233
+
234
+ Pattern.create_date_format_methods(self)
235
+ Pattern.create_format_method(self)
236
+ end
237
+
238
+ attr_reader :pattern, :date_pattern, :date_method
239
+
240
+ # call-seq:
241
+ # appender.pattern = "[%d] %-5l -- %c : %m\n"
242
+ #
243
+ # Set the message formatting pattern to be used by the layout.
244
+ #
245
+ def pattern=( var )
246
+ @pattern = var
247
+ Pattern.create_format_method(self)
248
+ end
249
+
250
+ # call-seq:
251
+ # appender.date_pattern = "%Y-%m-%d %H:%M:%S"
252
+ #
253
+ # Set the date formatting pattern to be used when outputting timestamps
254
+ # in the log messages.
255
+ #
256
+ def date_pattern=( var )
257
+ @date_pattern = var
258
+ Pattern.create_date_format_methods(self)
259
+ end
260
+
261
+ # call-seq:
262
+ # appender.date_method = 'to_s'
263
+ # appender.date_method = :usec
264
+ #
265
+ # Set the date method to be used when outputting timestamps in the log
266
+ # messages. If a date method is configured, the output of that method
267
+ # will be used in leu of the date pattern.
268
+ #
269
+ def date_method=( var )
270
+ @date_method = var
271
+ Pattern.create_date_format_methods(self)
272
+ end
273
+
274
+ # :stopdoc:
275
+
276
+ # call-seq:
277
+ # meta_eval( code )
278
+ #
279
+ # Evaluates the given string of _code_ if the singleton class of this
280
+ # Pattern Layout object.
281
+ #
282
+ def meta_eval( code )
283
+ meta = class << self; self end
284
+ meta.class_eval code
285
+ end
286
+ # :startdoc:
287
+
288
+ end # class Pattern
289
+ end # module Layouts
290
+ end # module Logging
291
+
292
+ # EOF
@@ -0,0 +1,50 @@
1
+ # $Id$
2
+
3
+ module Logging
4
+
5
+ # This class defines a logging event.
6
+ #
7
+ class LogEvent
8
+
9
+ # :stopdoc:
10
+
11
+ # Regular expression used to parse out caller information
12
+ #
13
+ # * $1 == filename
14
+ # * $2 == line number
15
+ # * $3 == method name (might be nil)
16
+ CALLER_RGXP = %r/([\.\/\(\)\w]+):(\d+)(?::in `(\w+)')?/o
17
+ # :startdoc:
18
+
19
+ # call-seq:
20
+ # LogEvent.new( logger, level, [data], trace )
21
+ #
22
+ # Creates a new log event with the given _logger_ name, numeric _level_,
23
+ # array of _data_ from the user to be logged, and boolean _trace_ flag.
24
+ # If the _trace_ flag is set to +true+ then Kernel::caller will be
25
+ # invoked to get the execution trace of the logging method.
26
+ #
27
+ def initialize( logger, level, data, trace )
28
+ @logger = logger
29
+ @level = level
30
+ @data = data
31
+ @file = @line = @method = ''
32
+
33
+ if trace
34
+ t = Kernel.caller[2]
35
+ return if t.nil?
36
+
37
+ m = CALLER_RGXP.match(t)
38
+ @file = m[1]
39
+ @line = m[2]
40
+ @method = m[3] unless m[3].nil?
41
+ end
42
+ end
43
+
44
+ attr_accessor :logger, :level, :data
45
+ attr_reader :file, :line, :method
46
+
47
+ end # class LogEvent
48
+ end # module Logging
49
+
50
+ # EOF
@@ -0,0 +1,388 @@
1
+ # $Id$
2
+
3
+ require 'thread'
4
+
5
+ module Logging
6
+
7
+ # The +Logger+ class is the primary interface to the +Logging+ framework.
8
+ # It provides the logging methods that will be called from user methods,
9
+ # and it generates logging events that are sent to the appenders (the
10
+ # appenders take care of sending the log events to the logging
11
+ # destinations -- files, sockets, etc).
12
+ #
13
+ # +Logger+ instances are obtained from the +Repository+ and should
14
+ # not be directly created by users.
15
+ #
16
+ # Example:
17
+ #
18
+ # log = Logging::Logger['my logger']
19
+ # log.add_appenders( Logging::Appender.stdout ) # append to STDOUT
20
+ # log.level = :info # log 'info' and above
21
+ #
22
+ # log.info 'starting foo operation'
23
+ # ...
24
+ # log.info 'finishing foo operation'
25
+ # ...
26
+ # log.fatal 'unknown exception', exception
27
+ #
28
+ class Logger
29
+
30
+ @mutex = Mutex.new # :nodoc:
31
+
32
+ class << self
33
+
34
+ # call-seq:
35
+ # Logger.root
36
+ #
37
+ # Returns the root logger.
38
+ #
39
+ def root
40
+ ::Logging::Repository.instance[:root]
41
+ end
42
+
43
+ # :stopdoc:
44
+
45
+ # Overrides the new method such that only one Logger will be created
46
+ # for any given logger name.
47
+ #
48
+ def new( *args )
49
+ return super if args.empty?
50
+
51
+ repo = ::Logging::Repository.instance
52
+ name = repo.to_key(args.shift)
53
+
54
+ @mutex.synchronize do
55
+ logger = repo[name]
56
+ if logger.nil?
57
+ logger = super(name, *args)
58
+ repo[name] = logger
59
+ end
60
+ logger
61
+ end
62
+ end
63
+ alias :[] :new
64
+
65
+ # This is where the actual logging methods are defined. Two methods
66
+ # are created for each log level. The first is a query method used to
67
+ # determine if that perticular logging level is enabled. The second is
68
+ # the actual logging method that accepts a list of objects to be
69
+ # logged or a block. If a block is given, then the object returned
70
+ # from the block will be logged.
71
+ #
72
+ # Example
73
+ #
74
+ # log = Logging::Logger['my logger']
75
+ # log.level = :warn
76
+ #
77
+ # log.info? # => false
78
+ # log.warn? # => true
79
+ # log.warn 'this is your last warning'
80
+ # log.fatal 'I die!', exception
81
+ #
82
+ # log.debug do
83
+ # # expensive method to construct log message
84
+ # msg
85
+ # end
86
+ #
87
+ def define_log_methods( logger )
88
+ ::Logging::LEVELS.each do |name,num|
89
+ code = "undef :#{name} if method_defined? :#{name}\n"
90
+ code << "undef :#{name}? if method_defined? :#{name}?\n"
91
+
92
+ if logger.level > num
93
+ code << <<-CODE
94
+ def #{name}?( ) false end
95
+ def #{name}( data = nil ) false end
96
+ CODE
97
+ else
98
+ code << <<-CODE
99
+ def #{name}?( ) true end
100
+ def #{name}( data = nil )
101
+ data = yield if block_given?
102
+ log_event(::Logging::LogEvent.new(@name, #{num}, data, @trace))
103
+ true
104
+ end
105
+ CODE
106
+ end
107
+
108
+ logger.meta_eval code
109
+ end
110
+ end
111
+ # :startdoc:
112
+
113
+ end # class << self
114
+
115
+ attr_reader :level, :name, :parent, :additive, :trace
116
+
117
+ # call-seq:
118
+ # Logger.new( name )
119
+ # Logger[name]
120
+ #
121
+ # Returns the logger identified by _name_.
122
+ #
123
+ # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
124
+ # retrieve the logger. When _name_ is a +Class+ the class name will be
125
+ # used to retrieve the logger. When _name_ is an object the name of the
126
+ # object's class will be used to retrieve the logger.
127
+ #
128
+ # Example:
129
+ #
130
+ # obj = MyClass.new
131
+ #
132
+ # log1 = Logger.new(obj)
133
+ # log2 = Logger.new(MyClass)
134
+ # log3 = Logger['MyClass']
135
+ #
136
+ # log1.object_id == log2.object_id # => true
137
+ # log2.object_id == log3.object_id # => true
138
+ #
139
+ def initialize( name )
140
+ case name
141
+ when String
142
+ raise(ArgumentError, "logger must have a name") if name.empty?
143
+ else raise(ArgumentError, "logger name must be a String") end
144
+
145
+ repo = ::Logging::Repository.instance
146
+ @name = name
147
+ @parent = repo.parent(name)
148
+ @appenders = []
149
+ @additive = true
150
+ @trace = false
151
+ self.level = @parent.level
152
+
153
+ repo.children(name).each {|c| c.parent = self}
154
+ end
155
+
156
+ # call-seq:
157
+ # log <=> other
158
+ #
159
+ # Compares this logger by name to another logger. The normal return codes
160
+ # for +String+ objects apply.
161
+ #
162
+ def <=>( other )
163
+ case other
164
+ when self; 0
165
+ when ::Logging::RootLogger; 1
166
+ when ::Logging::Logger; @name <=> other.name
167
+ else raise ArgumentError, 'expecting a Logger instance' end
168
+ end
169
+
170
+ # call-seq:
171
+ # log << "message"
172
+ #
173
+ # Log the given message without any formatting and without performing any
174
+ # level checks. The message is logged to all appenders. The message is
175
+ # passed up the logger tree if this logger's additivity is +true+.
176
+ #
177
+ def <<( msg )
178
+ @appenders.each {|a| a << msg}
179
+ @parent << msg if @additive
180
+ end
181
+
182
+ # call-seq:
183
+ # add( severity, message = nil ) {block}
184
+ #
185
+ # Log a message if the given severity is high enough. This is the generic
186
+ # logging method. Users will be more inclined to use #debug, #info, #warn,
187
+ # #error, and #fatal.
188
+ #
189
+ # <b>Message format</b>: +message+ can be any object, but it has to be
190
+ # converted to a String in order to log it. The Logging::format_as
191
+ # method is used to determine how objects chould be converted to
192
+ # strings. Generally, +inspect+ is used.
193
+ #
194
+ # A special case is an +Exception+ object, which will be printed in
195
+ # detail, including message, class, and backtrace.
196
+ #
197
+ # If a _message_ is not given, then the return value from the block is
198
+ # used as the message to log. This is useful when creating the actual
199
+ # message is an expensive operation. This allows the logger to check the
200
+ # severity against the configured level before actually constructing the
201
+ # message.
202
+ #
203
+ # This method returns +true+ if the message was logged, and +false+ is
204
+ # returned if the message was not logged.
205
+ #
206
+ def add( lvl, data = nil )
207
+ lvl = Integer(lvl)
208
+ return false if lvl < level
209
+
210
+ data = yield if block_given?
211
+ log_event(::Logging::LogEvent.new(@name, lvl, data, @trace))
212
+ true
213
+ end
214
+
215
+ # call-seq:
216
+ # additive = true
217
+ #
218
+ # Sets the additivity of the logger. Acceptable values are +true+,
219
+ # 'true', +false+, 'false', or +nil+. In this case +nil+ does not
220
+ # change the additivity
221
+ #
222
+ def additive=( val )
223
+ @additive = case val
224
+ when true, 'true'; true
225
+ when false, 'false'; false
226
+ when nil; @additive
227
+ else raise ArgumentError, 'expecting a boolean' end
228
+ end
229
+
230
+ # call-seq:
231
+ # trace = true
232
+ #
233
+ # Sets the tracing of the logger. Acceptable values are +true+,
234
+ # 'true', +false+, 'false', or +nil+. In this case +nil+ does not
235
+ # change the tracing.
236
+ #
237
+ def trace=( val )
238
+ @trace = case val
239
+ when true, 'true'; true
240
+ when false, 'false'; false
241
+ when nil; @trace
242
+ else raise ArgumentError, 'expecting a boolean' end
243
+ end
244
+
245
+ # call-seq:
246
+ # level = :all
247
+ #
248
+ # Set the level for this logger. The level can be either a +String+, a
249
+ # +Symbol+, or a +Fixnum+. An +ArgumentError+ is raised if this is not
250
+ # the case.
251
+ #
252
+ # There are two special levels -- "all" and "off". The former will
253
+ # enable log messages from this logger. The latter will disable all log
254
+ # messages from this logger.
255
+ #
256
+ # Setting the logger level to +nil+ will cause the parent's logger level
257
+ # to be used.
258
+ #
259
+ # Example:
260
+ #
261
+ # log.level = :debug
262
+ # log.level = "INFO"
263
+ # log.level = 4
264
+ # log.level = 'off'
265
+ # log.level = :all
266
+ #
267
+ # These prodcue an +ArgumentError+
268
+ #
269
+ # log.level = Object
270
+ # log.level = -1
271
+ # log.level = 1_000_000_000_000
272
+ #
273
+ def level=( level )
274
+ lvl = case level
275
+ when String, Symbol; ::Logging::level_num(level)
276
+ when Fixnum; level
277
+ when nil; @parent.level
278
+ else
279
+ raise ArgumentError,
280
+ "level must be a String, Symbol, or Integer"
281
+ end
282
+ if lvl.nil? or lvl < 0 or lvl > ::Logging::LEVELS.length
283
+ raise ArgumentError, "unknown level was given '#{level}'"
284
+ end
285
+
286
+ @level = lvl
287
+ ::Logging::Logger.define_log_methods(self)
288
+ @level
289
+ end
290
+
291
+ # call-seq:
292
+ # appenders = app
293
+ #
294
+ # Clears the current list of appenders and replaces them with _app_,
295
+ # where _app_ can be either a single appender or an array of appenders.
296
+ #
297
+ def appenders=( args )
298
+ @appenders.clear
299
+ add_appenders(*args) unless args.nil?
300
+ end
301
+
302
+ # call-seq:
303
+ # add_appenders( appenders )
304
+ #
305
+ # Add the given _appenders_ to the list of appenders, where _appenders_
306
+ # can be either a single appender or an array of appenders.
307
+ #
308
+ def add_appenders( *args )
309
+ args.flatten.each do |arg|
310
+ o = arg.kind_of?(::Logging::Appender) ? arg : ::Logging::Appender[arg]
311
+ raise ArgumentError, "unknown appender '#{arg}'" if o.nil?
312
+ @appenders << o unless @appenders.include?(o)
313
+ end
314
+ self
315
+ end
316
+
317
+ # call-seq:
318
+ # remove_appenders( appenders )
319
+ #
320
+ # Remove the given _appenders_ from the list of appenders. The appenders
321
+ # to remove can be identified either by name using a +String+ or by
322
+ # passing the appender instance. _appenders_ can be a single appender or
323
+ # an array of appenders.
324
+ #
325
+ def remove_appenders( *args )
326
+ args.flatten.each do |arg|
327
+ @appenders.delete_if do |a|
328
+ case arg
329
+ when String; arg == a.name
330
+ when ::Logging::Appender; arg.object_id == a.object_id
331
+ else
332
+ raise ArgumentError, "#{arg.inspect} is not a 'Logging::Appender'"
333
+ end
334
+ end
335
+ end
336
+ self
337
+ end
338
+
339
+ # call-seq:
340
+ # clear_appenders
341
+ #
342
+ # Remove all appenders from this logger.
343
+ #
344
+ def clear_appenders( ) @appenders.clear end
345
+
346
+
347
+ protected
348
+
349
+ # call-seq:
350
+ # parent = ParentLogger
351
+ #
352
+ # Set the parent logger for this logger. This method will be invoked by
353
+ # the +Repository+ class when a parent or child is added to the
354
+ # hierarchy.
355
+ #
356
+ def parent=( parent ) @parent = parent end
357
+
358
+ # call-seq:
359
+ # log_event( event )
360
+ #
361
+ # Send the given _event_ to the appenders for logging, and pass the
362
+ # _event_ up to the parent if additive mode is enabled. The log level has
363
+ # already been checked before this method is called.
364
+ #
365
+ def log_event( event )
366
+ @appenders.each {|a| a.append(event)}
367
+ @parent.log_event(event) if @additive
368
+ end
369
+
370
+ # :stopdoc:
371
+
372
+ # call-seq:
373
+ # meta_eval( code )
374
+ #
375
+ # Evaluates the given string of _code_ if the singleton class of this
376
+ # Logger object.
377
+ #
378
+ def meta_eval( code )
379
+ meta = class << self; self end
380
+ meta.class_eval code
381
+ end
382
+ public :meta_eval
383
+ # :startdoc:
384
+
385
+ end # class Logger
386
+ end # module Logging
387
+
388
+ # EOF