logging 0.1.0

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.
@@ -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