TwP-logging 0.9.7

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.
Files changed (54) hide show
  1. data/History.txt +169 -0
  2. data/README.rdoc +102 -0
  3. data/Rakefile +42 -0
  4. data/data/bad_logging_1.rb +13 -0
  5. data/data/bad_logging_2.rb +21 -0
  6. data/data/logging.rb +42 -0
  7. data/data/logging.yaml +63 -0
  8. data/data/simple_logging.rb +13 -0
  9. data/lib/logging.rb +408 -0
  10. data/lib/logging/appender.rb +303 -0
  11. data/lib/logging/appenders/buffering.rb +167 -0
  12. data/lib/logging/appenders/console.rb +62 -0
  13. data/lib/logging/appenders/email.rb +75 -0
  14. data/lib/logging/appenders/file.rb +54 -0
  15. data/lib/logging/appenders/growl.rb +197 -0
  16. data/lib/logging/appenders/io.rb +69 -0
  17. data/lib/logging/appenders/rolling_file.rb +291 -0
  18. data/lib/logging/appenders/syslog.rb +201 -0
  19. data/lib/logging/config/configurator.rb +190 -0
  20. data/lib/logging/config/yaml_configurator.rb +195 -0
  21. data/lib/logging/layout.rb +119 -0
  22. data/lib/logging/layouts/basic.rb +34 -0
  23. data/lib/logging/layouts/pattern.rb +296 -0
  24. data/lib/logging/log_event.rb +51 -0
  25. data/lib/logging/logger.rb +490 -0
  26. data/lib/logging/repository.rb +172 -0
  27. data/lib/logging/root_logger.rb +61 -0
  28. data/lib/logging/stats.rb +278 -0
  29. data/lib/logging/utils.rb +130 -0
  30. data/logging.gemspec +41 -0
  31. data/test/appenders/test_buffered_io.rb +183 -0
  32. data/test/appenders/test_console.rb +66 -0
  33. data/test/appenders/test_email.rb +171 -0
  34. data/test/appenders/test_file.rb +93 -0
  35. data/test/appenders/test_growl.rb +128 -0
  36. data/test/appenders/test_io.rb +142 -0
  37. data/test/appenders/test_rolling_file.rb +207 -0
  38. data/test/appenders/test_syslog.rb +194 -0
  39. data/test/benchmark.rb +87 -0
  40. data/test/config/test_configurator.rb +70 -0
  41. data/test/config/test_yaml_configurator.rb +40 -0
  42. data/test/layouts/test_basic.rb +43 -0
  43. data/test/layouts/test_pattern.rb +177 -0
  44. data/test/setup.rb +74 -0
  45. data/test/test_appender.rb +166 -0
  46. data/test/test_layout.rb +110 -0
  47. data/test/test_log_event.rb +80 -0
  48. data/test/test_logger.rb +734 -0
  49. data/test/test_logging.rb +267 -0
  50. data/test/test_repository.rb +126 -0
  51. data/test/test_root_logger.rb +81 -0
  52. data/test/test_stats.rb +274 -0
  53. data/test/test_utils.rb +116 -0
  54. metadata +156 -0
@@ -0,0 +1,190 @@
1
+
2
+ module Logging::Config
3
+
4
+ # The Configurator class is used to configure the Logging framework
5
+ # using information found in a block of Ruby code. This block is evaluated
6
+ # in the context of the configurator's DSL.
7
+ #
8
+ class Configurator
9
+
10
+ class Error < StandardError; end # :nodoc:
11
+
12
+ # call-seq:
13
+ # Configuraotr.process( &block )
14
+ #
15
+ def self.process( &block )
16
+ new.load(&block)
17
+ end
18
+
19
+ # call-seq:
20
+ # load { block }
21
+ #
22
+ # Loads the configuration from the _block_ and configures the Logging
23
+ # gem.
24
+ #
25
+ def load( &block )
26
+ raise Error, "missing configuration block" unless block
27
+
28
+ dsl = TopLevelDSL.new
29
+ dsl.__instance_eval(&block)
30
+
31
+ pre_config dsl.__pre_config
32
+ ::Logging::Logger[:root] # ensures the log levels are defined
33
+ appenders dsl.__appenders
34
+ loggers dsl.__loggers
35
+ end
36
+
37
+ # call-seq:
38
+ # pre_config( config )
39
+ #
40
+ # Configures the logging levels, object format style, and root logging
41
+ # level.
42
+ #
43
+ def pre_config( config )
44
+ if config.nil?
45
+ ::Logging.init unless ::Logging.const_defined? 'MAX_LEVEL_LENGTH'
46
+ return
47
+ end
48
+
49
+ # define levels
50
+ levels = config[:levels]
51
+ ::Logging.init(levels) unless levels.nil?
52
+
53
+ # format as
54
+ format = config[:format_as]
55
+ ::Logging.format_as(format) unless format.nil?
56
+
57
+ # backtrace
58
+ value = config[:backtrace]
59
+ ::Logging.backtrace(value) unless value.nil?
60
+ end
61
+
62
+ # call-seq:
63
+ # appenders( ary )
64
+ #
65
+ # Given an array of Appender configurations, this method will iterate
66
+ # over each and create the Appender(s).
67
+ #
68
+ def appenders( ary )
69
+ ary.each {|name, config| appender(name, config)}
70
+ end
71
+
72
+ # call-seq:
73
+ # loggers( ary )
74
+ #
75
+ # Given an array of Logger configurations, this method will iterate over
76
+ # each and create the Logger(s).
77
+ #
78
+ def loggers( ary )
79
+ ary.each do |name, config|
80
+ l = Logging::Logger[name]
81
+ l.level = config[:level] if config[:level]
82
+ l.additive = config[:additive] if l.respond_to? :additive=
83
+ l.trace = config[:trace]
84
+ l.appenders = Array(config[:appenders]).
85
+ map {|name| ::Logging::Appender[name]}
86
+ end
87
+ end
88
+
89
+ # call-seq:
90
+ # appender( name, config )
91
+ #
92
+ # Creates a new Appender based on the given _config_ options (a hash).
93
+ # The type of Appender created is determined by the 'type' option in the
94
+ # config. The remaining config options are passed to the Appender
95
+ # initializer.
96
+ #
97
+ # The config options can also contain a 'layout' option. This should be
98
+ # another set of options used to create a Layout for this Appender.
99
+ #
100
+ def appender( name, config )
101
+ type = config.delete(:type)
102
+ raise Error, "appender type not given for #{name.inspect}" if type.nil?
103
+
104
+ config[:layout] = layout(config[:layout]) if config.has_key? :layout
105
+
106
+ clazz = ::Logging::Appenders.const_get type
107
+ clazz.new(name, config)
108
+ rescue NameError => err
109
+ raise Error, "unknown appender class Logging::Appenders::#{type}"
110
+ end
111
+
112
+ # call-seq:
113
+ # layout( config )
114
+ #
115
+ # Creates a new Layout based on the given _config_ options (a hash).
116
+ # The type of Layout created is determined by the 'type' option in the
117
+ # config. The remaining config options are passed to the Layout
118
+ # initializer.
119
+ #
120
+ def layout( config )
121
+ return ::Logging::Layouts::Basic.new if config.nil?
122
+
123
+ type = config.delete(:type)
124
+ raise Error, 'layout type not given' if type.nil?
125
+
126
+ clazz = ::Logging::Layouts.const_get type
127
+ clazz.new config
128
+ rescue NameError => err
129
+ raise Error, "unknown layout class Logging::Layouts::#{type}"
130
+ end
131
+
132
+ class DSL
133
+ alias :__instance_eval :instance_eval
134
+
135
+ instance_methods.each do |m|
136
+ undef_method m unless m[%r/^(__|object_id)/]
137
+ end
138
+
139
+ def self.process( &block )
140
+ dsl = new
141
+ dsl.__instance_eval(&block)
142
+ dsl.__hash
143
+ end
144
+
145
+ def __hash
146
+ @hash ||= Hash.new
147
+ end
148
+
149
+ def method_missing( method, *args, &block )
150
+ args << DSL.process(&block) if block
151
+
152
+ key = method.to_sym
153
+ value = (1 == args.length ? args.first : args)
154
+ __store(key, value)
155
+ end
156
+
157
+ def __store( key, value )
158
+ __hash[key] = value
159
+ end
160
+ end
161
+
162
+ class TopLevelDSL < DSL
163
+ undef_method :method_missing
164
+
165
+ def initialize
166
+ @loggers = []
167
+ @appenders = []
168
+ end
169
+
170
+ def pre_config( &block )
171
+ __store(:preconfig, DSL.process(&block))
172
+ end
173
+
174
+ def logger( name, &block )
175
+ @loggers << [name, DSL.process(&block)]
176
+ end
177
+
178
+ def appender( name, &block )
179
+ @appenders << [name, DSL.process(&block)]
180
+ end
181
+
182
+ def __pre_config() __hash[:preconfig]; end
183
+ def __loggers() @loggers; end
184
+ def __appenders() @appenders; end
185
+ end
186
+
187
+ end # class Configurator
188
+ end # module Logging::Config
189
+
190
+ # EOF
@@ -0,0 +1,195 @@
1
+
2
+ require 'yaml'
3
+
4
+ module Logging
5
+ module Config
6
+
7
+ # The YamlConfigurator class is used to configure the Logging framework
8
+ # using information found in a YAML file.
9
+ #
10
+ class YamlConfigurator
11
+
12
+ class Error < StandardError; end # :nodoc:
13
+
14
+ class << self
15
+
16
+ # call-seq:
17
+ # YamlConfigurator.load( file, key = 'logging_config' )
18
+ #
19
+ # Load the given YAML _file_ and use it to configure the Logging
20
+ # framework. The file can be either a filename, and open File, or an
21
+ # IO object. If it is the latter two, the File / IO object will not be
22
+ # closed by this method.
23
+ #
24
+ # The configuration will be loaded from the given _key_ in the YAML
25
+ # stream.
26
+ #
27
+ def load( file, key = 'logging_config' )
28
+ io, close = nil, false
29
+ case file
30
+ when String
31
+ io = File.open(file, 'r')
32
+ close = true
33
+ when IO
34
+ io = file
35
+ else
36
+ raise Error, 'expecting a filename or a File'
37
+ end
38
+
39
+ begin
40
+ new(io, key).load
41
+ ensure
42
+ io.close if close
43
+ end
44
+ nil
45
+ end
46
+ end # class << self
47
+
48
+ # call-seq:
49
+ # YamlConfigurator.new( io, key )
50
+ #
51
+ # Creates a new YAML configurator that will load the Logging
52
+ # configuration from the given _io_ stream. The configuration will be
53
+ # loaded from the given _key_ in the YAML stream.
54
+ #
55
+ def initialize( io, key )
56
+ YAML.load_documents(io) do |doc|
57
+ @config = doc[key]
58
+ break if @config.instance_of?(Hash)
59
+ end
60
+
61
+ unless @config.instance_of?(Hash)
62
+ raise Error, "Key '#{key}' not defined in YAML configuration"
63
+ end
64
+ end
65
+
66
+ # call-seq:
67
+ # load
68
+ #
69
+ # Loads the Logging configuration from the data loaded from the YAML
70
+ # file.
71
+ #
72
+ def load
73
+ pre_config @config['pre_config']
74
+ ::Logging::Logger[:root] # ensures the log levels are defined
75
+ appenders @config['appenders']
76
+ loggers @config['loggers']
77
+ end
78
+
79
+ # call-seq:
80
+ # pre_config( config )
81
+ #
82
+ # Configures the logging levels, object format style, and root logging
83
+ # level.
84
+ #
85
+ def pre_config( config )
86
+ # if no pre_config section was given, just create an empty hash
87
+ # we do this to ensure that some logging levels are always defined
88
+ config ||= Hash.new
89
+
90
+ # define levels
91
+ levels = config['define_levels']
92
+ ::Logging.init(levels) unless levels.nil?
93
+
94
+ # format as
95
+ format = config['format_as']
96
+ ::Logging.format_as(format) unless format.nil?
97
+
98
+ # backtrace
99
+ value = config['backtrace']
100
+ ::Logging.backtrace(value) unless value.nil?
101
+
102
+ # grab the root logger and set the logging level
103
+ root = ::Logging::Logger.root
104
+ if config.has_key?('root')
105
+ root.level = config['root']['level']
106
+ end
107
+ end
108
+
109
+ # call-seq:
110
+ # appenders( ary )
111
+ #
112
+ # Given an array of Appender configurations, this method will iterate
113
+ # over each and create the Appender(s).
114
+ #
115
+ def appenders( ary )
116
+ return if ary.nil?
117
+
118
+ ary.each {|h| appender(h)}
119
+ end
120
+
121
+ # call-seq:
122
+ # loggers( ary )
123
+ #
124
+ # Given an array of Logger configurations, this method will iterate over
125
+ # each and create the Logger(s).
126
+ #
127
+ def loggers( ary )
128
+ return if ary.nil?
129
+
130
+ ary.each do |config|
131
+ name = config['name']
132
+ raise Error, 'Logger name not given' if name.nil?
133
+
134
+ l = Logging::Logger.new name
135
+ l.level = config['level'] if config.has_key?('level')
136
+ l.additive = config['additive'] if l.respond_to? :additive=
137
+ l.trace = config['trace'] if l.respond_to? :trace=
138
+
139
+ if config.has_key?('appenders')
140
+ l.appenders = config['appenders'].map {|n| ::Logging::Appender[n]}
141
+ end
142
+ end
143
+ end
144
+
145
+ # call-seq:
146
+ # appender( config )
147
+ #
148
+ # Creates a new Appender based on the given _config_ options (a hash).
149
+ # The type of Appender created is determined by the 'type' option in the
150
+ # config. The remaining config options are passed to the Appender
151
+ # initializer.
152
+ #
153
+ # The config options can also contain a 'layout' option. This should be
154
+ # another set of options used to create a Layout for this Appender.
155
+ #
156
+ def appender( config )
157
+ return if config.nil?
158
+ config = config.dup
159
+
160
+ type = config.delete('type')
161
+ raise Error, 'Appender type not given' if type.nil?
162
+
163
+ name = config.delete('name')
164
+ raise Error, 'Appender name not given' if name.nil?
165
+
166
+ config['layout'] = layout(config.delete('layout'))
167
+
168
+ clazz = ::Logging::Appenders.const_get type
169
+ clazz.new(name, config)
170
+ end
171
+
172
+ # call-seq:
173
+ # layout( config )
174
+ #
175
+ # Creates a new Layout based on the given _config_ options (a hash).
176
+ # The type of Layout created is determined by the 'type' option in the
177
+ # config. The remaining config options are passed to the Layout
178
+ # initializer.
179
+ #
180
+ def layout( config )
181
+ return if config.nil?
182
+ config = config.dup
183
+
184
+ type = config.delete('type')
185
+ raise Error, 'Layout type not given' if type.nil?
186
+
187
+ clazz = ::Logging::Layouts.const_get type
188
+ clazz.new config
189
+ end
190
+
191
+ end # class YamlConfigurator
192
+ end # module Config
193
+ end # module Logging
194
+
195
+ # EOF
@@ -0,0 +1,119 @@
1
+
2
+ require 'yaml'
3
+
4
+ module Logging
5
+
6
+ # The +Layout+ class provides methods for formatting log events into a
7
+ # string representation. Layouts are used by Appenders to format log
8
+ # events before writing them to the logging destination.
9
+ #
10
+ # All other Layouts inherit from this class which provides stub methods.
11
+ # Each subclass should provide a +format+ method. A layout can be used by
12
+ # more than one +Appender+ so all the methods need to be thread safe.
13
+ #
14
+ class Layout
15
+
16
+ # call-seq:
17
+ # Layout.new( :format_as => :string )
18
+ #
19
+ # Creates a new layout that will format objecs as strings using the
20
+ # given <tt>:format_as</tt> style. This can be one of <tt>:string</tt>,
21
+ # <tt>:inspect</tt>, or <tt>:yaml</tt>. These formatting commands map to
22
+ # the following object methods:
23
+ #
24
+ # * :string => to_s
25
+ # * :inspect => inspect
26
+ # * :yaml => to_yaml
27
+ #
28
+ # If the format is not specified then the global object format is used
29
+ # (see Logging#format_as). If the global object format is not specified
30
+ # then <tt>:string</tt> is used.
31
+ #
32
+ def initialize( opts = {} )
33
+ default = ::Logging.const_defined?('OBJ_FORMAT') ?
34
+ ::Logging::OBJ_FORMAT : nil
35
+
36
+ f = opts.getopt(:format_as, default)
37
+ f = f.intern if f.instance_of? String
38
+
39
+ @obj_format = case f
40
+ when :inspect, :yaml; f
41
+ else :string end
42
+
43
+ b = opts.getopt(:backtrace, ::Logging.backtrace)
44
+ @backtrace = case b
45
+ when :on, 'on', true; true
46
+ when :off, 'off', false; false
47
+ else
48
+ raise ArgumentError, "backtrace must be true or false"
49
+ end
50
+ end
51
+
52
+ # call-seq:
53
+ # format( event )
54
+ #
55
+ # Returns a string representation of the given loggging _event_. It is
56
+ # up to subclasses to implement this method.
57
+ #
58
+ def format( event ) nil end
59
+
60
+ # call-seq:
61
+ # header
62
+ #
63
+ # Returns a header string to be used at the beginning of a logging
64
+ # appender.
65
+ #
66
+ def header( ) '' end
67
+
68
+ # call-seq:
69
+ # footer
70
+ #
71
+ # Returns a footer string to be used at the end of a logging appender.
72
+ #
73
+ def footer( ) '' end
74
+
75
+ # call-seq:
76
+ # format_obj( obj )
77
+ #
78
+ # Return a string representation of the given object. Depending upon
79
+ # the configuration of the logger system the format will be an +inspect+
80
+ # based represenation or a +yaml+ based representation.
81
+ #
82
+ def format_obj( obj )
83
+ case obj
84
+ when String; obj
85
+ when Exception
86
+ str = "<#{obj.class.name}> #{obj.message}"
87
+ if @backtrace && !obj.backtrace.nil?
88
+ str << "\n\t" << obj.backtrace.join("\n\t")
89
+ end
90
+ str
91
+ when nil; "<#{obj.class.name}> nil"
92
+ else
93
+ str = "<#{obj.class.name}> "
94
+ str << case @obj_format
95
+ when :inspect; obj.inspect
96
+ when :yaml; try_yaml(obj)
97
+ else obj.to_s end
98
+ str
99
+ end
100
+ end
101
+
102
+ # call-seq:
103
+ # try_yaml( obj )
104
+ #
105
+ # Attempt to format the _obj_ using yaml, but fall back to inspect style
106
+ # formatting if yaml fails.
107
+ #
108
+ def try_yaml( obj )
109
+ "\n#{obj.to_yaml}"
110
+ rescue TypeError
111
+ obj.inspect
112
+ end
113
+
114
+ end # class Layout
115
+ end # module Logging
116
+
117
+ Logging.require_all_libs_relative_to(__FILE__, 'layouts')
118
+
119
+ # EOF