logging 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ # $Id: static_appender.rb 12 2007-01-14 20:03:40Z tim_pease $
2
+
3
+ require 'logging/appenders/console'
4
+
5
+ module Logging
6
+ class Appender
7
+
8
+ @appenders = Hash.new
9
+
10
+ class << self
11
+
12
+ #
13
+ # call-seq:
14
+ # Appender[name]
15
+ #
16
+ # Returns the appender instance stroed in the Appender hash under the
17
+ # key _name_, or +nil+ if no appender has been created using that name.
18
+ #
19
+ def []( name ) @appenders[name] end
20
+
21
+ #
22
+ # call-seq:
23
+ # Appender[name] = appender
24
+ #
25
+ # Stores the given _appender_ instance in the Appender hash under the
26
+ # key _name_.
27
+ #
28
+ def []=( name, val ) @appenders[name] = val end
29
+
30
+ #
31
+ # call-seq:
32
+ # Appender.stdout
33
+ #
34
+ # Returns an instance of the StdOut Appender. Unless the user explicitly
35
+ # creates a new StdOut Appender, the instance returned by this method
36
+ # will always be the same:
37
+ #
38
+ # Appender.stdout.object_id == Appender.stdout.object_id #=> true
39
+ #
40
+ def stdout( ) self['stdout'] || ::Logging::Appenders::StdOut.new end
41
+
42
+ #
43
+ # call-seq:
44
+ # Appender.stderr
45
+ #
46
+ # Returns an instance of the StdErr Appender. Unless the user explicitly
47
+ # creates a new StdErr Appender, the instance returned by this method
48
+ # will always be the same:
49
+ #
50
+ # Appender.stderr.object_id == Appender.stderr.object_id #=> true
51
+ #
52
+ def stderr( ) self['stderr'] || ::Logging::Appenders::StdErr.new end
53
+
54
+ end # class << self
55
+ end # class Appender
56
+ end # module Logging
57
+
58
+ # EOF
@@ -0,0 +1,102 @@
1
+ # $Id: layout.rb 9 2007-01-11 23:51:41Z tim_pease $
2
+
3
+ require 'yaml'
4
+ require 'logging'
5
+
6
+ module Logging
7
+
8
+ #
9
+ # The +Layout+ class provides methods for formatting log events into a
10
+ # string representation. Layouts are used by Appenders to format log
11
+ # events before writing them to the logging destination.
12
+ #
13
+ # All other Layouts inherit from this class which provides stub methods.
14
+ # Each subclass should provide a +format+ method. A layout can be used by
15
+ # more than one +Appender+ so all the methods need to be thread safe.
16
+ #
17
+ class Layout
18
+
19
+ #
20
+ # call-seq:
21
+ # Layout.new
22
+ # Layout.new( obj_format )
23
+ #
24
+ # Creates a new layout that uses the given _obj_format_ when converting
25
+ # objects to strings. _obj_format_ can be one of <tt>:string</tt>,
26
+ # <tt>:inspect</tt>, or <tt>:yaml</tt>. These formatting commands map to
27
+ # the following object methods:
28
+ #
29
+ # * :string => to_s
30
+ # * :inspect => inspect
31
+ # * :yaml => to_yaml
32
+ #
33
+ # If _obj_format_ is not given then the global object format is used
34
+ # (see Logging#format_as). If the global object format is not specified
35
+ # then +:string+ is used.
36
+ #
37
+ def initialize( f = nil )
38
+ f ||= ::Logging::OBJ_FORMAT if ::Logging.const_defined? 'OBJ_FORMAT'
39
+ @obj_format = case f
40
+ when :inspect, :yaml: f
41
+ else :string end
42
+ end
43
+
44
+ #
45
+ # call-seq:
46
+ # format( event )
47
+ #
48
+ # Returns a string representation of the given loggging _event_. It is
49
+ # up to subclasses to implement this method.
50
+ #
51
+ def format( event ) nil end
52
+
53
+ #
54
+ # call-seq:
55
+ # header
56
+ #
57
+ # Returns a header string to be used at the beginning of a logging
58
+ # appender.
59
+ #
60
+ def header( ) '' end
61
+
62
+ #
63
+ # call-seq:
64
+ # footer
65
+ #
66
+ # Returns a footer string to be used at the end of a logging appender.
67
+ #
68
+ def footer( ) '' end
69
+
70
+
71
+ protected
72
+ #
73
+ # call-seq:
74
+ # format_obj( obj )
75
+ #
76
+ # Return a string representation of the given object. Depending upon
77
+ # the configuration of the logger system the format will be an +inspect+
78
+ # based represenation or a +yaml+ based representation.
79
+ #
80
+ def format_obj( obj )
81
+ case obj
82
+ when String: obj
83
+ when Exception:
84
+ str = "<#{obj.class.name}> #{obj.message}"
85
+ unless obj.backtrace.nil?
86
+ str << "\n\t" << obj.backtrace.join("\n\t")
87
+ end
88
+ str
89
+ else
90
+ str = "<#{obj.class.name}> "
91
+ str << case @obj_format
92
+ when :inspect: obj.inspect
93
+ when :yaml: "\n#{obj.to_yaml}"
94
+ else obj.to_s end
95
+ str
96
+ end
97
+ end
98
+
99
+ end # class Layout
100
+ end # module Logging
101
+
102
+ # EOF
@@ -0,0 +1,48 @@
1
+ # $Id: basic.rb 15 2007-01-15 19:03:45Z tim_pease $
2
+
3
+ require 'logging'
4
+ require 'logging/layout'
5
+
6
+
7
+ module Logging
8
+ module Layouts
9
+
10
+ #
11
+ # The +Basic+ layout class provides methods for simple formatting of log
12
+ # events. The resulting string follows the format below.
13
+ #
14
+ # LEVEL LoggerName : log message
15
+ #
16
+ # _LEVEL_ is the log level of the event. _LoggerName_ is the name of the
17
+ # logger that generated the event. <em>log message</em> is the message
18
+ # or object that was passed to the logger. If multiple message or objects
19
+ # were passed to the logger then each will be printed on its own line with
20
+ # the format show above.
21
+ #
22
+ class Basic < ::Logging::Layout
23
+
24
+ #
25
+ # call-seq:
26
+ # format( event )
27
+ #
28
+ # Returns a string representation of the given loggging _event_. See the
29
+ # class documentation for details about the formatting used.
30
+ #
31
+ def format( event )
32
+ start = sprintf("%*s %s : ", ::Logging::MAX_LEVEL_LENGTH,
33
+ ::Logging::LNAMES[event.level], event.logger)
34
+ buf = ''
35
+ event.data.each do |obj|
36
+ buf << start
37
+ buf << format_obj(obj)
38
+ buf << "\n"
39
+ end
40
+
41
+ return buf
42
+ end
43
+
44
+ end # class Basic
45
+ end # module Layouts
46
+ end # module Logging
47
+
48
+ # EOF
@@ -0,0 +1,320 @@
1
+ # $Id: pattern.rb 13 2007-01-15 17:19:37Z tim_pease $
2
+
3
+ require 'logging'
4
+ require 'logging/layout'
5
+
6
+ module Logging
7
+ module Layouts
8
+
9
+ #
10
+ # A flexible layout configurable with pattern string.
11
+ #
12
+ # The goal of this class is to format a LogEvent and return the results as
13
+ # a String. The results depend on the conversion pattern.
14
+ #
15
+ # The conversion pattern is closely related to the conversion pattern of
16
+ # the sprintf function. A conversion pattern is composed of literal text
17
+ # and format control expressions called conversion specifiers.
18
+ #
19
+ # You are free to insert any literal text within the conversion pattern.
20
+ #
21
+ # Each conversion specifier starts with a percent sign (%) and is followed
22
+ # by optional format modifiers and a conversion character. The conversion
23
+ # character specifies the type of data, e.g. logger, level, date, thread
24
+ # ID. The format modifiers control such things as field width, padding,
25
+ # left and right justification. The following is a simple example.
26
+ #
27
+ # Let the conversion pattern be "%-5l [%c]: %m\n" and assume that the
28
+ # logging environment was set to use a Pattern layout. Then the statements
29
+ #
30
+ # root = Logging::Logger[:root]
31
+ # root.debug("Message 1")
32
+ # root.warn("Message 2")
33
+ #
34
+ # would yield the output
35
+ #
36
+ # DEBUG [root]: Message 1
37
+ # WARN [root]: Message 2
38
+ #
39
+ # Note that there is no explicit separator between text and conversion
40
+ # specifiers. The pattern parser knows when it has reached the end of a
41
+ # conversion specifier when it reads a conversion character. In the example
42
+ # above the conversion specifier %-5l means the level of the logging event
43
+ # should be left justified to a width of five characters. The recognized
44
+ # conversion characters are
45
+ #
46
+ # [c] Used to output the name of the logger that generated the log
47
+ # event.
48
+ # [d] Used to output the date of the log event. The format of the
49
+ # date is specified using the :date_pattern option when the Layout
50
+ # is created. ISO8601 format is assumed if not date pattern is given.
51
+ # [F] Used to output the file name where the logging request was issued.
52
+ # [l] Used to output the level of the log event.
53
+ # [L] Used to output the line number where the logging request was
54
+ # issued.
55
+ # [m] Used to output the application supplied message associated with
56
+ # the log event.
57
+ # [M] Used to output the method name where the logging request was
58
+ # issued.
59
+ # [p] Used to output the process ID of the currently running program.
60
+ # [r] Used to output the number of milliseconds elapsed from the
61
+ # construction of the Layout until creation of the log event.
62
+ # [t] Used to output the object ID of the thread that generated the
63
+ # log event.
64
+ # [%] The sequence '%%' outputs a single percent sign.
65
+ #
66
+ # The directives F, L, and M will only work if the Logger generating the
67
+ # events is configured to generate tracing information. If this is not
68
+ # the case these fields will always be empty.
69
+ #
70
+ # By default the relevant information is output as is. However, with the
71
+ # aid of format modifiers it is possible to change the minimum field width,
72
+ # the maximum field width and justification.
73
+ #
74
+ # The optional format modifier is placed between the percent sign and the
75
+ # conversion character.
76
+ #
77
+ # The first optional format modifier is the left justification flag which
78
+ # is just the minus (-) character. Then comes the optional minimum field
79
+ # width modifier. This is a decimal constant that represents the minimum
80
+ # number of characters to output. If the data item requires fewer
81
+ # characters, it is padded on either the left or the right until the
82
+ # minimum width is reached. The default is to pad on the left (right
83
+ # justify) but you can specify right padding with the left justification
84
+ # flag. The padding character is space. If the data item is larger than the
85
+ # minimum field width, the field is expanded to accommodate the data. The
86
+ # value is never truncated.
87
+ #
88
+ # This behavior can be changed using the maximum field width modifier which
89
+ # is designated by a period followed by a decimal constant. If the data
90
+ # item is longer than the maximum field, then the extra characters are
91
+ # removed from the end of the data item.
92
+ #
93
+ # Below are various format modifier examples for the category conversion
94
+ # specifier.
95
+ #
96
+ # [%20c] Left pad with spaces if the logger name is less than 20
97
+ # characters long
98
+ # [%-20c] Right pad with spaces if the logger name is less than 20
99
+ # characters long
100
+ # [%.30c] Truncates the logger name if it is longer than 30 characters
101
+ # [%20.30c] Left pad with spaces if the logger name is shorter than
102
+ # 20 characters. However, if the logger name is longer than
103
+ # 30 characters, then truncate the name.
104
+ # [%-20.30c] Right pad with spaces if the logger name is shorter than
105
+ # 20 characters. However, if the logger name is longer than
106
+ # 30 characters, then truncate the name.
107
+ #
108
+ # Below are examples of some conversion patterns.
109
+ #
110
+ # %.1l, [%d] %5l -- %c: %m\n
111
+ #
112
+ # This is how the Logger class in the Ruby standard library formats
113
+ # messages. The main difference will be in the date format (the Pattern
114
+ # Layout uses the ISO8601 date format). Set the :date_method on the
115
+ # Pattern Layout to be 'to_s' and then the date formats will agree.
116
+ #
117
+ class Pattern < ::Logging::Layout
118
+
119
+ # :stopdoc:
120
+
121
+ # Arguments to sprintf keyed to directive letters
122
+ DIRECTIVE_TABLE = {
123
+ 'c' => 'event.logger',
124
+ 'd' => 'format_date',
125
+ 'F' => 'event.file',
126
+ 'l' => '::Logging::LNAMES[event.level]',
127
+ 'L' => 'event.line',
128
+ 'm' => :placeholder,
129
+ 'M' => 'event.method',
130
+ 'p' => 'Process.pid',
131
+ 'r' => 'Integer((Time.now-@created_at)*1000).to_s',
132
+ 't' => 'Thread.current.object_id.to_s',
133
+ '%' => :placeholder
134
+ }
135
+
136
+ # Matches the first directive encountered and the stuff around it.
137
+ #
138
+ # * $1 is the stuff before directive or "" if not applicable
139
+ # * $2 is the %#.# match within directive group
140
+ # * $3 is the directive letter
141
+ # * $4 is the stuff after the directive or "" if not applicable
142
+ DIRECTIVE_RGXP = %r/([^%]*)(?:(%-?\d*(?:\.\d+)?)([a-zA-Z%]))?(.*)/m
143
+
144
+ # default date format
145
+ ISO8601 = "%Y-%m-%d %H:%M:%S"
146
+
147
+ #
148
+ # call-seq:
149
+ # Pattern.create_date_format_methods( pf )
150
+ #
151
+ # This method will create the +date_format+ method in the given Pattern
152
+ # Layout _pf_ based on the configured date patten and/or date method
153
+ # specified by the user.
154
+ #
155
+ def self.create_date_format_methods( pf )
156
+ code = "undef :format_date if method_defined? :format_date\n"
157
+ code << "def format_date\nTime.now."
158
+ code << if pf.date_method.nil? then "strftime '#{pf.date_pattern}'\n"
159
+ else "#{pf.date_method}\n" end
160
+ code << "end\n"
161
+
162
+ pf.meta_eval code
163
+ end
164
+
165
+ #
166
+ # call-seq:
167
+ # Pattern.create_format_methods( pf )
168
+ #
169
+ # This method will create the +format+ and +format_str+ methods in the
170
+ # given Pattern Layout _pf_ based on the configured format pattern
171
+ # specified by the user.
172
+ #
173
+ def self.create_format_methods( pf )
174
+ # Create the format_str(event) method. This method will return format
175
+ # string that can be used with +sprintf+ to format the data objects in
176
+ # the given _event_.
177
+ code = "undef :format_str if method_defined? :format_str\n"
178
+ code << "def format_str( event )\nsprintf(\""
179
+ pattern = pf.pattern.dup
180
+ have_m_directive = false
181
+ have_percent = false
182
+ args = []
183
+
184
+ while true
185
+ m = DIRECTIVE_RGXP.match(pattern)
186
+ code << m[1] unless m[1].empty?
187
+
188
+ case m[3]
189
+ when '%'
190
+ code << '%%%%' # this results in a %% in the format string
191
+ have_percent = true
192
+ when 'm'
193
+ code << '%' + m[2] + 's'
194
+ have_m_directive = true
195
+ when *DIRECTIVE_TABLE.keys
196
+ code << m[2] + 's'
197
+ args << DIRECTIVE_TABLE[m[3]]
198
+ when nil: break
199
+ else
200
+ raise ArgumentError, "illegal format character - '#{m[3]}'"
201
+ end
202
+
203
+ break if m[4].empty?
204
+ pattern = m[4]
205
+ end
206
+
207
+ code << '"'
208
+ code << ', ' + args.join(', ') unless args.empty?
209
+ code << ")\n"
210
+ code << "end\n"
211
+
212
+ code.gsub!('%%', '%') if have_percent and not have_m_directive
213
+ pf.meta_eval code
214
+
215
+ # Create the format(event) method
216
+ code = "undef :format if method_defined? :format\n"
217
+ if have_m_directive
218
+ code << <<-CODE
219
+ def format( event )
220
+ fmt = format_str(event)
221
+ buf = ''
222
+ event.data.each {|obj| buf << sprintf(fmt, format_obj(obj))}
223
+ buf
224
+ end
225
+ CODE
226
+ else
227
+ code << "alias :format :format_str\n"
228
+ end
229
+ pf.meta_eval code
230
+ end
231
+ # :startdoc:
232
+
233
+ #
234
+ # call-seq:
235
+ # Pattern.new( opts )
236
+ #
237
+ # Creates a new Pattern layout using the following options.
238
+ #
239
+ # :pattern => "[%d] %-5l -- %c : %m\n"
240
+ # :date_pattern => "%Y-%m-%d %H:%M:%S"
241
+ # :date_method => 'usec' or 'to_s'
242
+ #
243
+ # If used, :date_method will supersede :date_pattern.
244
+ #
245
+ def initialize( opts = {} )
246
+ f = opts.delete(:obj_format)
247
+ super(f)
248
+
249
+ @created_at = Time.now
250
+
251
+ @pattern = opts[:pattern]
252
+ @date_pattern = opts[:date_pattern]
253
+ @date_method = opts[:date_method]
254
+
255
+ @pattern ||= "[%d] %-#{::Logging::MAX_LEVEL_LENGTH}l -- %c : %m\n"
256
+ @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
257
+
258
+ Pattern.create_date_format_methods(self)
259
+ Pattern.create_format_methods(self)
260
+ end
261
+
262
+ attr_reader :pattern, :date_pattern, :date_method
263
+
264
+ #
265
+ # call-seq:
266
+ # appender.pattern = "[%d] %-5l -- %c : %m\n"
267
+ #
268
+ # Set the message formatting pattern to be used by the layout.
269
+ #
270
+ def pattern=( var )
271
+ @pattern = var.to_s
272
+ Pattern.create_format_methods(self)
273
+ end
274
+
275
+ #
276
+ # call-seq:
277
+ # appender.date_pattern = "%Y-%m-%d %H:%M:%S"
278
+ #
279
+ # Set the date formatting pattern to be used when outputting timestamps
280
+ # in the log messages.
281
+ #
282
+ def date_pattern=( var )
283
+ @date_pattern = var.to_s
284
+ Pattern.create_date_format_methods(self)
285
+ end
286
+
287
+ #
288
+ # call-seq:
289
+ # appender.date_method = 'to_s'
290
+ # appender.date_method = :usec
291
+ #
292
+ # Set the date method to be used when outputting timestamps in the log
293
+ # messages. If a date method is configured, the output of that method
294
+ # will be used in leu of the date pattern.
295
+ #
296
+ def date_method=( var )
297
+ @date_method = var
298
+ Pattern.create_date_format_methods(self)
299
+ end
300
+
301
+ # :stopdoc:
302
+
303
+ #
304
+ # call-seq:
305
+ # meta_eval( code )
306
+ #
307
+ # Evaluates the given string of _code_ if the singleton class of this
308
+ # Pattern Layout object.
309
+ #
310
+ def meta_eval( code )
311
+ meta = class << self; self end
312
+ meta.class_eval code
313
+ end
314
+ # :startdoc:
315
+
316
+ end # class Pattern
317
+ end # module Layouts
318
+ end # module Logging
319
+
320
+ # EOF