sgeorgi-logging 1.4.2

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