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,202 @@
1
+ # $Id$
2
+
3
+ begin
4
+ require 'syslog'
5
+ HAVE_SYSLOG = true
6
+ rescue LoadError
7
+ HAVE_SYSLOG = false
8
+ end
9
+
10
+ # only load this class if we have the syslog library
11
+ # Windows does not have syslog
12
+ #
13
+ if HAVE_SYSLOG
14
+
15
+ module Logging::Appenders
16
+
17
+ # This class provides an Appender that can write to the UNIX syslog
18
+ # daemon.
19
+ #
20
+ class Syslog < ::Logging::Appender
21
+ include ::Syslog::Constants
22
+
23
+ # call-seq:
24
+ # Syslog.new( name, opts = {} )
25
+ #
26
+ # Create an appender that will log messages to the system message
27
+ # logger. The message is then written to the system console, log files,
28
+ # logged-in users, or forwarded to other machines as appropriate. The
29
+ # options that can be used to configure the appender are as follows:
30
+ #
31
+ # :ident => identifier string (name is used by default)
32
+ # :logopt => options used when opening the connection
33
+ # :facility => the syslog facility to use
34
+ #
35
+ # The parameter :ident is a string that will be prepended to every
36
+ # message. The :logopt argument is a bit field specifying logging
37
+ # options, which is formed by OR'ing one or more of the following
38
+ # values:
39
+ #
40
+ # LOG_CONS If syslog() cannot pass the message to syslogd(8) it
41
+ # wil attempt to write the message to the console
42
+ # ('/dev/console').
43
+ #
44
+ # LOG_NDELAY Open the connection to syslogd(8) immediately. Normally
45
+ # the open is delayed until the first message is logged.
46
+ # Useful for programs that need to manage the order in
47
+ # which file descriptors are allocated.
48
+ #
49
+ # LOG_PERROR Write the message to standard error output as well to
50
+ # the system log.
51
+ #
52
+ # LOG_PID Log the process id with each message: useful for
53
+ # identifying instantiations of daemons.
54
+ #
55
+ # The :facility parameter encodes a default facility to be assigned to
56
+ # all messages that do not have an explicit facility encoded:
57
+ #
58
+ # LOG_AUTH The authorization system: login(1), su(1), getty(8),
59
+ # etc.
60
+ #
61
+ # LOG_AUTHPRIV The same as LOG_AUTH, but logged to a file readable
62
+ # only by selected individuals.
63
+ #
64
+ # LOG_CONSOLE Messages written to /dev/console by the kernel console
65
+ # output driver.
66
+ #
67
+ # LOG_CRON The cron daemon: cron(8).
68
+ #
69
+ # LOG_DAEMON System daemons, such as routed(8), that are not
70
+ # provided for explicitly by other facilities.
71
+ #
72
+ # LOG_FTP The file transfer protocol daemons: ftpd(8), tftpd(8).
73
+ #
74
+ # LOG_KERN Messages generated by the kernel. These cannot be
75
+ # generated by any user processes.
76
+ #
77
+ # LOG_LPR The line printer spooling system: lpr(1), lpc(8),
78
+ # lpd(8), etc.
79
+ #
80
+ # LOG_MAIL The mail system.
81
+ #
82
+ # LOG_NEWS The network news system.
83
+ #
84
+ # LOG_SECURITY Security subsystems, such as ipfw(4).
85
+ #
86
+ # LOG_SYSLOG Messages generated internally by syslogd(8).
87
+ #
88
+ # LOG_USER Messages generated by random user processes. This is
89
+ # the default facility identifier if none is specified.
90
+ #
91
+ # LOG_UUCP The uucp system.
92
+ #
93
+ # LOG_LOCAL0 Reserved for local use. Similarly for LOG_LOCAL1
94
+ # through LOG_LOCAL7.
95
+ #
96
+ def initialize( name, opts = {} )
97
+ ident = opts.getopt(:ident, name)
98
+ logopt = opts.getopt(:logopt, (LOG_PID | LOG_CONS), :as => Integer)
99
+ facility = opts.getopt(:facility, LOG_USER, :as => Integer)
100
+ @syslog = ::Syslog.open(ident, logopt, facility)
101
+
102
+ # provides a mapping from the default Logging levels
103
+ # to the syslog levels
104
+ @map = [LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT]
105
+
106
+ map = opts.getopt(:map)
107
+ self.map = map unless map.nil?
108
+
109
+ super
110
+ end
111
+
112
+ # call-seq:
113
+ # map = { logging_levels => syslog_levels }
114
+ #
115
+ # Configure the mapping from the Logging levels to the syslog levels.
116
+ # This is needed in order to log events at the proper syslog level.
117
+ #
118
+ # Without any configuration, the following maping will be used:
119
+ #
120
+ # :debug => LOG_DEBUG
121
+ # :info => LOG_INFO
122
+ # :warn => LOG_WARNING
123
+ # :error => LOG_ERR
124
+ # :fatal => LOG_CRIT
125
+ #
126
+ def map=( levels )
127
+ map = []
128
+ levels.keys.each do |lvl|
129
+ num = ::Logging.level_num(lvl)
130
+ map[num] = syslog_level_num(levels[lvl])
131
+ end
132
+ @map = map
133
+ end
134
+
135
+ # call-seq:
136
+ # close
137
+ #
138
+ # Closes the connetion to the syslog facility.
139
+ #
140
+ def close( footer = true )
141
+ super
142
+ @syslog.close
143
+ self
144
+ end
145
+
146
+ # call-seq:
147
+ # closed? => true or false
148
+ #
149
+ # Queries the connection to the syslog facility and returns +true+ if
150
+ # the connection is closed.
151
+ #
152
+ def closed?
153
+ !@syslog.opened?
154
+ end
155
+
156
+
157
+ private
158
+
159
+ # call-seq:
160
+ # write( event )
161
+ #
162
+ # Write the given _event_ to the syslog facility. The log event will be
163
+ # processed through the Layout assciated with this appender. The message
164
+ # will be logged at the level specified by the event.
165
+ #
166
+ def write( event )
167
+ pri = LOG_DEBUG
168
+ message = if event.instance_of?(::Logging::LogEvent)
169
+ pri = @map[event.level]
170
+ @layout.format(event)
171
+ else
172
+ event.to_s
173
+ end
174
+ return if message.empty?
175
+
176
+ @syslog.log(pri, '%s', message)
177
+ self
178
+ end
179
+
180
+ # call-seq:
181
+ # syslog_level_num( level ) => integer
182
+ #
183
+ # Takes the given _level_ as a string, symbol, or integer and returns
184
+ # the corresponding syslog level number.
185
+ #
186
+ def syslog_level_num( level )
187
+ case level
188
+ when Integer; level
189
+ when String, Symbol
190
+ level = level.to_s.upcase
191
+ self.class.const_get level
192
+ else
193
+ raise ArgumentError, "unkonwn level '#{level}'"
194
+ end
195
+ end
196
+
197
+ end # class Syslog
198
+
199
+ end # module Logging::Appenders
200
+ end # HAVE_SYSLOG
201
+
202
+ # EOF
@@ -0,0 +1,197 @@
1
+ # $Id$
2
+
3
+ require 'yaml'
4
+
5
+ module Logging
6
+ module Config
7
+
8
+ # The YamlConfigurator class is used to configure the Logging framework
9
+ # using information found in a YAML file.
10
+ #
11
+ class YamlConfigurator
12
+
13
+ class Error < StandardError; end # :nodoc:
14
+
15
+ class << self
16
+
17
+ # call-seq:
18
+ # YamlConfigurator.load( file, key = 'logging_config' )
19
+ #
20
+ # Load the given YAML _file_ and use it to configure the Logging
21
+ # framework. The file can be either a filename, and open File, or an
22
+ # IO object. If it is the latter two, the File / IO object will not be
23
+ # closed by this method.
24
+ #
25
+ # The configuration will be loaded from the given _key_ in the YAML
26
+ # stream.
27
+ #
28
+ def load( file, key = 'logging_config' )
29
+ io, close = nil, false
30
+ case file
31
+ when String
32
+ ext = File.extname(file)
33
+ if ext == 'yml' || ext == 'yaml'
34
+ io = File.open(file, 'r')
35
+ close = true
36
+ else
37
+ io = StringIO.new(file)
38
+ close = true
39
+ end
40
+ when IO
41
+ io = file
42
+ else
43
+ raise Error, 'expecting a filename or a File'
44
+ end
45
+
46
+ begin
47
+ new(io, key).load
48
+ ensure
49
+ io.close if close
50
+ end
51
+ nil
52
+ end
53
+ end # class << self
54
+
55
+ # call-seq:
56
+ # YamlConfigurator.new( io, key )
57
+ #
58
+ # Creates a new YAML configurator that will load the Logging
59
+ # configuration from the given _io_ stream. The configuration will be
60
+ # loaded from the given _key_ in the YAML stream.
61
+ #
62
+ def initialize( io, key )
63
+ YAML.load_documents(io) do |doc|
64
+ @config = doc[key]
65
+ break if @config.instance_of?(Hash)
66
+ end
67
+
68
+ unless @config.instance_of?(Hash)
69
+ raise Error, "Key '#{key}' not defined in YAML configuration"
70
+ end
71
+ end
72
+
73
+ # call-seq:
74
+ # load
75
+ #
76
+ # Loads the Logging configuration from the data loaded from the YAML
77
+ # file.
78
+ #
79
+ def load
80
+ pre_config @config['pre_config']
81
+ appenders @config['appenders']
82
+ loggers @config['loggers']
83
+ end
84
+
85
+ # call-seq:
86
+ # pre_config( config )
87
+ #
88
+ # Configures the logging levels, object format style, and root logging
89
+ # level.
90
+ #
91
+ def pre_config( config )
92
+ # if no pre_config section was given, just create an empty hash
93
+ # we do this to ensure that some logging levels are always defined
94
+ config ||= Hash.new
95
+
96
+ # define levels
97
+ levels = config['define_levels']
98
+ ::Logging.init(levels) unless levels.nil?
99
+
100
+ # format as
101
+ format = config['format_as']
102
+ ::Logging.format_as(format) unless format.nil?
103
+
104
+ # grab the root logger and set the logging level
105
+ root = ::Logging::Logger.root
106
+ if config.has_key?('root')
107
+ root.level = config['root']['level']
108
+ end
109
+ end
110
+
111
+ # call-seq:
112
+ # appenders( ary )
113
+ #
114
+ # Given an array of Appender configurations, this method will iterate
115
+ # over each and create the Appender(s).
116
+ #
117
+ def appenders( ary )
118
+ return if ary.nil?
119
+
120
+ ary.each {|h| appender(h)}
121
+ end
122
+
123
+ # call-seq:
124
+ # loggers( ary )
125
+ #
126
+ # Given an array of Logger configurations, this method will iterate over
127
+ # each and create the Logger(s).
128
+ #
129
+ def loggers( ary )
130
+ return if ary.nil?
131
+
132
+ ary.each do |config|
133
+ name = config['name']
134
+ raise Error, 'Logger name not given' if name.nil?
135
+
136
+ l = Logging::Logger.new name
137
+ l.level = config['level'] if config.has_key?('level')
138
+ l.additive = config['additive'] if l.respond_to? :additive=
139
+ l.trace = config['trace'] if l.respond_to? :trace=
140
+
141
+ if config.has_key?('appenders')
142
+ l.appenders = config['appenders'].map {|n| ::Logging::Appender[n]}
143
+ end
144
+ end
145
+ end
146
+
147
+ # call-seq:
148
+ # appender( config )
149
+ #
150
+ # Creates a new Appender based on the given _config_ options (a hash).
151
+ # The type of Appender created is determined by the 'type' option in the
152
+ # config. The remaining config options are passed to the Appender
153
+ # initializer.
154
+ #
155
+ # The config options can also contain a 'layout' option. This should be
156
+ # another set of options used to create a Layout for this Appender.
157
+ #
158
+ def appender( config )
159
+ return if config.nil?
160
+ config = config.dup
161
+
162
+ type = config.delete('type')
163
+ raise Error, 'Appender type not given' if type.nil?
164
+
165
+ name = config.delete('name')
166
+ raise Error, 'Appender name not given' if type.nil?
167
+
168
+ config['layout'] = layout(config.delete('layout'))
169
+
170
+ clazz = ::Logging::Appenders.const_get type
171
+ clazz.new(name, config)
172
+ end
173
+
174
+ # call-seq:
175
+ # layout( config )
176
+ #
177
+ # Creates a new Layout based on the given _config_ options (a hash).
178
+ # The type of Layout created is determined by the 'type' option in the
179
+ # config. The remaining config options are passed to the Layout
180
+ # initializer.
181
+ #
182
+ def layout( config )
183
+ return if config.nil?
184
+ config = config.dup
185
+
186
+ type = config.delete('type')
187
+ raise Error, 'Layout type not given' if type.nil?
188
+
189
+ clazz = ::Logging::Layouts.const_get type
190
+ clazz.new config
191
+ end
192
+
193
+ end # class YamlConfigurator
194
+ end # module Config
195
+ end # module Logging
196
+
197
+ # EOF
@@ -0,0 +1,103 @@
1
+ # $Id$
2
+
3
+ require 'yaml'
4
+
5
+ module Logging
6
+
7
+ # The +Layout+ class provides methods for formatting log events into a
8
+ # string representation. Layouts are used by Appenders to format log
9
+ # events before writing them to the logging destination.
10
+ #
11
+ # All other Layouts inherit from this class which provides stub methods.
12
+ # Each subclass should provide a +format+ method. A layout can be used by
13
+ # more than one +Appender+ so all the methods need to be thread safe.
14
+ #
15
+ class Layout
16
+
17
+ # call-seq:
18
+ # Layout.new( :format_as => :string )
19
+ #
20
+ # Creates a new layout that will format objecs as strings using the
21
+ # given <tt>:format_as</tt> style. This can be one of <tt>:string</tt>,
22
+ # <tt>:inspect</tt>, or <tt>:yaml</tt>. These formatting commands map to
23
+ # the following object methods:
24
+ #
25
+ # * :string => to_s
26
+ # * :inspect => inspect
27
+ # * :yaml => to_yaml
28
+ #
29
+ # If the format is not specified then the global object format is used
30
+ # (see Logging#format_as). If the global object format is not specified
31
+ # then <tt>:string</tt> is used.
32
+ #
33
+ def initialize( opts = {} )
34
+ default = ::Logging.const_defined?('OBJ_FORMAT') ?
35
+ ::Logging::OBJ_FORMAT : nil
36
+
37
+ f = opts.getopt(:format_as, default)
38
+ f = f.intern if f.instance_of? String
39
+
40
+ @obj_format = case f
41
+ when :inspect, :yaml; f
42
+ else :string end
43
+ end
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
+ # call-seq:
54
+ # header
55
+ #
56
+ # Returns a header string to be used at the beginning of a logging
57
+ # appender.
58
+ #
59
+ def header( ) '' end
60
+
61
+ # call-seq:
62
+ # footer
63
+ #
64
+ # Returns a footer string to be used at the end of a logging appender.
65
+ #
66
+ def footer( ) '' end
67
+
68
+
69
+ protected
70
+
71
+ # call-seq:
72
+ # format_obj( obj )
73
+ #
74
+ # Return a string representation of the given object. Depending upon
75
+ # the configuration of the logger system the format will be an +inspect+
76
+ # based represenation or a +yaml+ based representation.
77
+ #
78
+ def format_obj( obj )
79
+ case obj
80
+ when String; obj
81
+ when Exception
82
+ str = "<#{obj.class.name}> #{obj.message}"
83
+ unless obj.backtrace.nil?
84
+ str << "\n\t" << obj.backtrace.join("\n\t")
85
+ end
86
+ str
87
+ when nil; "<#{obj.class.name}> nil"
88
+ else
89
+ str = "<#{obj.class.name}> "
90
+ str << case @obj_format
91
+ when :inspect; obj.inspect
92
+ when :yaml; "\n#{obj.to_yaml}"
93
+ else obj.to_s end
94
+ str
95
+ end
96
+ end
97
+
98
+ end # class Layout
99
+ end # module Logging
100
+
101
+ Logging.require_all_libs_relative_to(__FILE__, 'layouts')
102
+
103
+ # EOF