logging 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt ADDED
@@ -0,0 +1,11 @@
1
+ --
2
+ $Id: README.txt 12 2007-01-14 20:03:40Z tim_pease $
3
+ ++
4
+
5
+ = Logging
6
+
7
+ obtaining a logger
8
+ where to log
9
+ log statements
10
+ changing the log level
11
+
data/lib/logging.rb ADDED
@@ -0,0 +1,129 @@
1
+ # $Id: logging.rb 12 2007-01-14 20:03:40Z tim_pease $
2
+
3
+ require 'logging/repository'
4
+
5
+ # require all appenders
6
+ require 'logging/appenders/console'
7
+ require 'logging/appenders/file'
8
+ require 'logging/appenders/static_appender'
9
+
10
+ # require all layouts
11
+ require 'logging/layouts/basic'
12
+ require 'logging/layouts/pattern'
13
+
14
+
15
+ #
16
+ #
17
+ #
18
+ module Logging
19
+
20
+ LEVELS = {} # :nodoc:
21
+ LNAMES = {} # :nodoc:
22
+
23
+ class << self
24
+ #
25
+ # call-seq:
26
+ # define_levels( levels )
27
+ #
28
+ # Defines the levels available to the loggers. The _levels_ is an array
29
+ # of strings and symbols. Each element in the array is downcased and
30
+ # converted to a symbol; these symbols are used to create the logging
31
+ # methods in the loggers.
32
+ #
33
+ # The first element in the array is the lowest logging level. Setting the
34
+ # logging level to this value will enable all log messages. The last
35
+ # element in the array is the highest logging level. Setting the logging
36
+ # level to this value will disable all log messages except this highest
37
+ # level.
38
+ #
39
+ # This method should only be invoked once to configure the logging
40
+ # levels. It is automatically invoked with the default logging levels
41
+ # when the first logger is created.
42
+ #
43
+ # The levels "all" and "off" are reserved and will be ignored if passed
44
+ # to this method.
45
+ #
46
+ # Example:
47
+ #
48
+ # Logging.define_levels :debug, :info, :warn, :error, :fatal
49
+ # log = Logging::Logger['my logger']
50
+ # log.level = :warn
51
+ # log.warn 'Danger! Danger! Will Robinson'
52
+ # log.info 'Just FYI' # => not logged
53
+ #
54
+ # or
55
+ #
56
+ # Logging.define_levels %w(DEBUG INFO NOTICE WARNING ERR CRIT ALERT EMERG)
57
+ # log = Logging::Logger['syslog']
58
+ # log.level = :notice
59
+ # log.warning 'This is your first warning'
60
+ # log.info 'Just FYI' # => not logged
61
+ #
62
+ def define_levels( *args )
63
+ return nil if args.empty?
64
+
65
+ args.flatten!
66
+ levels = ::Logging::LEVELS.clear
67
+ names = ::Logging::LNAMES.clear
68
+
69
+ id = 0
70
+ args.each do |lvl|
71
+ lvl = levelify lvl
72
+ unless levels.has_key?(lvl) or lvl == 'all' or lvl == 'off'
73
+ levels[lvl] = id
74
+ names[id] = lvl.upcase
75
+ id += 1
76
+ end
77
+ end
78
+
79
+ longest = names.values.inject {|x,y| (x.length > y.length) ? x : y}
80
+ module_eval "MAX_LEVEL_LENGTH = #{longest.length}"
81
+
82
+ levels.keys
83
+ end
84
+
85
+ #
86
+ # call-seq:
87
+ # format_as( obj_format )
88
+ #
89
+ # Defines the default _obj_format_ method to use when converting objects
90
+ # into string representations for logging. _obj_format_ can be one of
91
+ # <tt>:string</tt>, <tt>:inspect</tt>, or <tt>:yaml</tt>. These
92
+ # formatting commands map to the following object methods
93
+ #
94
+ # * :string => to_s
95
+ # * :inspect => inspect
96
+ # * :yaml => to_yaml
97
+ #
98
+ # An +ArgumentError+ is raised if anything other than +:string+,
99
+ # +:inspect+, +:yaml+ is passed to this method.
100
+ #
101
+ def format_as( f )
102
+ unless [:string, :inspect, :yaml].include? f
103
+ raise ArgumentError, "unknown object format '#{f}'"
104
+ end
105
+
106
+ module_eval "OBJ_FORMAT = :#{f}"
107
+ end
108
+
109
+ # :stopdoc:
110
+ def levelify( level )
111
+ case level
112
+ when String: level.downcase
113
+ when Symbol: level.to_s.downcase
114
+ else raise ArgumentError, "levels must be a String or Symbol" end
115
+ end
116
+
117
+ def level_num( level )
118
+ l = levelify level
119
+ case l
120
+ when 'all': 0
121
+ when 'off': LEVELS.length
122
+ else LEVELS[l] end
123
+ end
124
+ # :startdoc:
125
+ end
126
+
127
+ end # module Logging
128
+
129
+ # EOF
@@ -0,0 +1,205 @@
1
+ # $Id: appender.rb 12 2007-01-14 20:03:40Z tim_pease $
2
+
3
+ require 'sync'
4
+ require 'logging'
5
+ require 'logging/logger'
6
+ require 'logging/layout'
7
+ require 'logging/layouts/basic'
8
+
9
+ module Logging
10
+
11
+ #
12
+ # The +Appender+ class is provides methods for appending log events to a
13
+ # logging destination. The log events are formatted into strings using a
14
+ # Layout.
15
+ #
16
+ # All other Appenders inherit from this class which provides stub methods.
17
+ # Each subclass should provide a +write+ method that will write log
18
+ # messages to the logging destination.
19
+ #
20
+ # A private +sync+ method is provided for use by subclasses. It is used to
21
+ # synchronize writes to the logging destination, and can be used by
22
+ # subclasses to synchronize the closing or flushing of the logging
23
+ # destination.
24
+ #
25
+ class Appender
26
+
27
+ attr_reader :name, :layout, :level
28
+
29
+ #
30
+ # call-seq:
31
+ # Appender.new( name )
32
+ # Appender.new( name, :layout => layout )
33
+ #
34
+ # Creates a new appender using the given name. If no Layout is specified,
35
+ # then a Basic layout will be used. Any logging header supplied by the
36
+ # layout will be written to the logging destination when the Appender is
37
+ # created.
38
+ #
39
+ def initialize( name, opts = {} )
40
+ @name = name.to_s
41
+ @closed = false
42
+ @level = 0
43
+ self.layout = opts[:layout] if opts.include? :layout
44
+ @layout ||= ::Logging::Layouts::Basic.new
45
+
46
+ @sync = Sync.new
47
+ sync {write(@layout.header)}
48
+
49
+ ::Logging::Appender[@name] = self
50
+ end
51
+
52
+ #
53
+ # call-seq:
54
+ # append( event )
55
+ #
56
+ # Write the given _event_ to the logging destination. The log event will
57
+ # be processed through the Layout associated with the Appender.
58
+ #
59
+ def append( event )
60
+ if @closed
61
+ raise RuntimeError,
62
+ "appender '<#{self.class.name}: #{@name}>' is closed"
63
+ end
64
+
65
+ sync {write(@layout.format(event))} unless @level > event.level
66
+ self
67
+ end
68
+
69
+ #
70
+ # call-seq:
71
+ # appender << string
72
+ #
73
+ # Write the given _string_ to the logging destination "as is" -- no
74
+ # layout formatting will be performed.
75
+ #
76
+ def <<( str )
77
+ if @closed
78
+ raise RuntimeError,
79
+ "appender '<#{self.class.name}: #{@name}>' is closed"
80
+ end
81
+
82
+ sync {write(str)}
83
+ self
84
+ end
85
+
86
+ #
87
+ # call-seq:
88
+ # level = :all
89
+ #
90
+ # Set the level for this appender; log events below this level will be
91
+ # ignored by this appender. The level can be either a +String+, a
92
+ # +Symbol+, or a +Fixnum+. An +ArgumentError+ is raised if this is not
93
+ # the case.
94
+ #
95
+ # There are two special levels -- "all" and "off". The former will
96
+ # enable recording of all log events. The latter will disable the
97
+ # recording of all events.
98
+ #
99
+ # Example:
100
+ #
101
+ # appender.level = :debug
102
+ # appender.level = "INFO"
103
+ # appender.level = 4
104
+ # appender.level = 'off'
105
+ # appender.level = :all
106
+ #
107
+ # These prodcue an +ArgumentError+
108
+ #
109
+ # appender.level = Object
110
+ # appender.level = -1
111
+ # appender.level = 1_000_000_000_000
112
+ #
113
+ def level=( level )
114
+ lvl = case level
115
+ when String, Symbol: ::Logging::level_num(level)
116
+ when Fixnum: level
117
+ when nil: 0
118
+ else
119
+ raise ArgumentError,
120
+ "level must be a String, Symbol, or Integer"
121
+ end
122
+ if lvl.nil? or lvl < 0 or lvl > ::Logging::LEVELS.length
123
+ raise ArgumentError, "unknown level was given '#{level}'"
124
+ end
125
+
126
+ @level = lvl
127
+ end
128
+
129
+ #
130
+ # call-seq
131
+ # appender.layout = Logging::Layouts::Basic.new
132
+ #
133
+ # Sets the layout to be used by this appender.
134
+ #
135
+ def layout=( layout )
136
+ unless layout.kind_of? ::Logging::Layout
137
+ raise TypeError,
138
+ "#{layout.inspect} is not a kind of 'Logging::Layout'"
139
+ end
140
+ @layout = layout
141
+ end
142
+
143
+ #
144
+ # call-seq:
145
+ # close( footer = true )
146
+ #
147
+ # Close the appender and writes the layout footer to the logging
148
+ # destination if the _footer_ flag is set to +true+. Log events will
149
+ # no longer be written to the logging destination after the appender
150
+ # is closed.
151
+ #
152
+ def close( footer = true )
153
+ return self if @closed
154
+ @closed = true
155
+ sync {write(@layout.footer)} if footer
156
+ self
157
+ end
158
+
159
+ #
160
+ # call-seq:
161
+ # closed?
162
+ #
163
+ # Returns +true+ if the appender has been closed; returns +false+
164
+ # otherwise. When an appender is closed, no more log events can be
165
+ # written to the logging destination.
166
+ #
167
+ def closed?( ) @closed end
168
+
169
+ #
170
+ # call-seq:
171
+ # flush
172
+ #
173
+ # Call +flush+ to force an appender to write out any buffered log events.
174
+ # Similar to IO#flush, so use in a similar fashion.
175
+ #
176
+ def flush( ) self end
177
+
178
+
179
+ private
180
+ #
181
+ # call-seq:
182
+ # write( str )
183
+ #
184
+ # Writes the given string to the logging destination. Subclasses should
185
+ # provide an implementation of this method.
186
+ #
187
+ def write( str ) nil end
188
+
189
+ #
190
+ # call-seq:
191
+ # sync { block }
192
+ #
193
+ # Obtains an exclusive lock, runs the block, and releases the lock when
194
+ # the block completes. This method is re-entrant so that a single thread
195
+ # can call +sync+ multiple times without hanging the thread.
196
+ #
197
+ def sync
198
+ if Thread.current == @sync.sync_ex_locker then yield
199
+ else @sync.synchronize(:EX) {yield} end
200
+ end
201
+
202
+ end # class Appender
203
+ end # module Logging
204
+
205
+ # EOF
@@ -0,0 +1,47 @@
1
+ # $Id: console.rb 2 2007-01-09 18:10:50Z tim_pease $
2
+
3
+ require 'logging/appenders/io'
4
+
5
+ module Logging
6
+ module Appenders
7
+
8
+ #
9
+ # This class provides an Appender that can write to STDOUT.
10
+ #
11
+ class StdOut< ::Logging::Appenders::IO
12
+
13
+ #
14
+ # call-seq:
15
+ # StdOut.new
16
+ # StdOut.new( :layout => layout )
17
+ #
18
+ # Creates a new StdOut Appender. The name 'stdout' will always be used for
19
+ # this appender.
20
+ #
21
+ def initialize( opts = {} )
22
+ super('stdout', STDOUT, opts)
23
+ end
24
+ end # class StdOut
25
+
26
+ #
27
+ # This class provides an Appender that can write to STDERR.
28
+ #
29
+ class StdErr< ::Logging::Appenders::IO
30
+
31
+ #
32
+ # call-seq:
33
+ # StdErr.new
34
+ # StdErr.new( :layout => layout )
35
+ #
36
+ # Creates a new StdErr Appender. The name 'stderr' will always be used for
37
+ # this appender.
38
+ #
39
+ def initialize( opts = {} )
40
+ super('stderr', STDERR, opts)
41
+ end
42
+ end # class StdErr
43
+
44
+ end # module Appenders
45
+ end # module Logging
46
+
47
+ # EOF
@@ -0,0 +1,45 @@
1
+ # $Id: file.rb 2 2007-01-09 18:10:50Z tim_pease $
2
+
3
+ require 'logging/appenders/io'
4
+
5
+ module Logging
6
+ module Appenders
7
+
8
+ #
9
+ # This class provides an Appender that can write to a File.
10
+ #
11
+ class File < ::Logging::Appenders::IO
12
+
13
+ #
14
+ # call-seq:
15
+ # File.new( filename )
16
+ # File.new( filename, :truncate => true )
17
+ # File.new( filename, :layout => layout )
18
+ #
19
+ # Creates a new File Appender that will use the given _filename_ as the
20
+ # logging destination. If the file does not already exist it will be
21
+ # created. If the :truncate option is set to +true+ then the file will be
22
+ # truncated before writing begins; otherwise, log messages will be appened
23
+ # to the file.
24
+ #
25
+ def initialize( filename, opts = {} )
26
+ mode = opts.delete(:truncate) ? 'w' : 'a'
27
+
28
+ if ::File.exist?(filename)
29
+ if not ::File.file?(filename)
30
+ raise StandardError, "#{filename} is not a regular file"
31
+ elsif not ::File.writable?(filename)
32
+ raise StandardError, "#{filename} is not writeable"
33
+ end
34
+ elsif not ::File.writable?(::File.dirname(filename))
35
+ raise StandardError, "#{::File.dirname(filename)} is not writable"
36
+ end
37
+
38
+ super(filename, ::File.new(filename, mode), opts)
39
+ end
40
+
41
+ end # class FileAppender
42
+ end # module Appenders
43
+ end # module Logging
44
+
45
+ # EOF
@@ -0,0 +1,87 @@
1
+ # $Id: io.rb 10 2007-01-12 18:57:07Z tim_pease $
2
+
3
+ require 'logging/appender'
4
+
5
+ module Logging
6
+ module Appenders
7
+
8
+ #
9
+ # This class provides an Appender that can write to any IO stream
10
+ # configured for writing.
11
+ #
12
+ class IO < ::Logging::Appender
13
+
14
+ #
15
+ # call-seq:
16
+ # IO.new( name, io )
17
+ # IO.new( name, io, :layout => layout )
18
+ #
19
+ # Creates a new IO Appender using the given name that will use the _io_
20
+ # stream as the logging destination.
21
+ #
22
+ def initialize( name, io, opts = {} )
23
+ unless io.respond_to? :print
24
+ raise TypeError, "expecting an IO object but got '#{io.class.name}'"
25
+ end
26
+
27
+ @io = io
28
+ @io.sync = true
29
+
30
+ super(name, opts)
31
+ end
32
+
33
+ #
34
+ # call-seq:
35
+ # close( footer = true )
36
+ #
37
+ # Close the appender and writes the layout footer to the logging
38
+ # destination if the _footer_ flag is set to +true+. Log events will
39
+ # no longer be written to the logging destination after the appender
40
+ # is closed.
41
+ #
42
+ def close( *args )
43
+ return self if @io.nil?
44
+ sync do
45
+ super(*args)
46
+ @io.close unless [STDIN, STDERR, STDOUT].include?(@io)
47
+ @io = nil
48
+ end
49
+ self
50
+ end
51
+
52
+ #
53
+ # call-seq:
54
+ # flush
55
+ #
56
+ # Call +flush+ to force an appender to write out any buffered log events.
57
+ # Similar to IO#flush, so use in a similar fashion.
58
+ #
59
+ def flush
60
+ return self if @io.nil?
61
+ @io.flush
62
+ self
63
+ end
64
+
65
+
66
+ private
67
+ #
68
+ # call-seq:
69
+ # write( str )
70
+ #
71
+ # Writes the given string to the IO stream. If an +IOError+ is detected,
72
+ # than this appender will be closed and the error reported.
73
+ #
74
+ def write( str )
75
+ begin
76
+ @io.print str
77
+ rescue IOError
78
+ close false
79
+ raise
80
+ end
81
+ end
82
+
83
+ end # class IO
84
+ end # module Appenders
85
+ end # module Logging
86
+
87
+ # EOF