logging 0.8.0 → 0.9.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.
Files changed (59) hide show
  1. data/History.txt +9 -0
  2. data/Manifest.txt +6 -0
  3. data/Rakefile +1 -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/simple_logging.rb +13 -0
  8. data/lib/logging.rb +14 -8
  9. data/lib/logging/appender.rb +36 -6
  10. data/lib/logging/appenders/console.rb +0 -1
  11. data/lib/logging/appenders/email.rb +3 -4
  12. data/lib/logging/appenders/file.rb +0 -1
  13. data/lib/logging/appenders/growl.rb +16 -5
  14. data/lib/logging/appenders/io.rb +0 -1
  15. data/lib/logging/appenders/rolling_file.rb +1 -2
  16. data/lib/logging/appenders/syslog.rb +0 -1
  17. data/lib/logging/config/configurator.rb +182 -0
  18. data/lib/logging/config/yaml_configurator.rb +0 -1
  19. data/lib/logging/layout.rb +0 -1
  20. data/lib/logging/layouts/basic.rb +0 -1
  21. data/lib/logging/layouts/pattern.rb +5 -6
  22. data/lib/logging/log_event.rb +0 -1
  23. data/lib/logging/logger.rb +24 -14
  24. data/lib/logging/repository.rb +13 -3
  25. data/lib/logging/root_logger.rb +0 -1
  26. data/lib/logging/utils.rb +0 -1
  27. data/tasks/ann.rake +0 -1
  28. data/tasks/bones.rake +0 -1
  29. data/tasks/gem.rake +0 -1
  30. data/tasks/git.rake +1 -2
  31. data/tasks/manifest.rake +0 -1
  32. data/tasks/notes.rake +0 -1
  33. data/tasks/post_load.rake +0 -1
  34. data/tasks/rdoc.rake +0 -1
  35. data/tasks/rubyforge.rake +1 -2
  36. data/tasks/setup.rb +0 -1
  37. data/tasks/test.rake +0 -1
  38. data/test/appenders/test_console.rb +0 -1
  39. data/test/appenders/test_email.rb +0 -1
  40. data/test/appenders/test_file.rb +0 -1
  41. data/test/appenders/test_growl.rb +22 -9
  42. data/test/appenders/test_io.rb +30 -3
  43. data/test/appenders/test_rolling_file.rb +0 -1
  44. data/test/appenders/test_syslog.rb +0 -1
  45. data/test/benchmark.rb +0 -1
  46. data/test/config/test_configurator.rb +70 -0
  47. data/test/config/test_yaml_configurator.rb +0 -1
  48. data/test/layouts/test_basic.rb +0 -1
  49. data/test/layouts/test_pattern.rb +0 -1
  50. data/test/setup.rb +0 -1
  51. data/test/test_appender.rb +0 -1
  52. data/test/test_layout.rb +0 -1
  53. data/test/test_log_event.rb +0 -1
  54. data/test/test_logger.rb +2 -2
  55. data/test/test_logging.rb +1 -2
  56. data/test/test_repository.rb +2 -3
  57. data/test/test_root_logger.rb +0 -1
  58. data/test/test_utils.rb +0 -1
  59. metadata +9 -2
@@ -1,3 +1,12 @@
1
+ == 0.9.0 / 2008-07-
2
+
3
+ 2 minor enhancement
4
+ - Exceptions from appenders are captured and logged
5
+ - Internal logger for the Logging framework (disabled by default)
6
+ - Added a DSL configuration format (more readable than YAML)
7
+ 1 bug fix
8
+ - Modules could not have their own logger instance
9
+
1
10
  == 0.8.0 / 2008-07-02
2
11
 
3
12
  1 minor enhancement
@@ -2,7 +2,11 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
+ data/bad_logging_1.rb
6
+ data/bad_logging_2.rb
7
+ data/logging.rb
5
8
  data/logging.yaml
9
+ data/simple_logging.rb
6
10
  lib/logging.rb
7
11
  lib/logging/appender.rb
8
12
  lib/logging/appenders/console.rb
@@ -12,6 +16,7 @@ lib/logging/appenders/growl.rb
12
16
  lib/logging/appenders/io.rb
13
17
  lib/logging/appenders/rolling_file.rb
14
18
  lib/logging/appenders/syslog.rb
19
+ lib/logging/config/configurator.rb
15
20
  lib/logging/config/yaml_configurator.rb
16
21
  lib/logging/layout.rb
17
22
  lib/logging/layouts/basic.rb
@@ -40,6 +45,7 @@ test/appenders/test_io.rb
40
45
  test/appenders/test_rolling_file.rb
41
46
  test/appenders/test_syslog.rb
42
47
  test/benchmark.rb
48
+ test/config/test_configurator.rb
43
49
  test/config/test_yaml_configurator.rb
44
50
  test/layouts/test_basic.rb
45
51
  test/layouts/test_pattern.rb
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ PROJ.rdoc.dir = 'doc/rdoc'
17
17
  #PROJ.rdoc.remote_dir = 'rdoc'
18
18
  PROJ.rdoc.remote_dir = ''
19
19
  PROJ.version = Logging::VERSION
20
+ PROJ.release_name = 'Monkeyful Chimptacular'
20
21
 
21
22
  PROJ.exclude << %w[^tags$ ^tasks/archive ^coverage]
22
23
  PROJ.rdoc.exclude << '^data'
@@ -0,0 +1,13 @@
1
+
2
+ Logging.configure {
3
+
4
+ logger(:root) {
5
+ level :info
6
+ appenders 'bad'
7
+ }
8
+
9
+ appender('bad') {
10
+ type 'FooBar'
11
+ }
12
+
13
+ } # logging configuration
@@ -0,0 +1,21 @@
1
+
2
+ Logging.configure {
3
+
4
+ logger(:root) {
5
+ level :info
6
+ appenders 'logfile'
7
+ }
8
+
9
+ appender('logfile') {
10
+ type 'File'
11
+ level 'DEB'
12
+ filename 'tmp/temp.log'
13
+ truncate true
14
+ layout {
15
+ type 'BadLayout'
16
+ date_method 'to_s'
17
+ pattern '[%d] %l %c : %m\n'
18
+ }
19
+ }
20
+
21
+ } # logging configuration
@@ -0,0 +1,42 @@
1
+
2
+ Logging.configure {
3
+
4
+ pre_config {
5
+ levels %w[DEB INF PRT WRN ERR FAT]
6
+ format_as :inspect
7
+ }
8
+
9
+ logger('A::B::C') {
10
+ level 'DEB'
11
+ additive false
12
+ trace false
13
+ appenders %w[stderr logfile]
14
+ }
15
+
16
+ logger('yourlogger') {
17
+ level 'INF'
18
+ appenders %w[stderr logfile]
19
+ }
20
+
21
+ appender('stderr') {
22
+ type 'Stderr'
23
+ level 'DEB'
24
+ layout {
25
+ type 'Basic'
26
+ format_as :string
27
+ }
28
+ }
29
+
30
+ appender('logfile') {
31
+ type 'File'
32
+ level 'DEB'
33
+ filename 'tmp/temp.log'
34
+ truncate true
35
+ layout {
36
+ type 'Pattern'
37
+ date_method 'to_s'
38
+ pattern '[%d] %l %c : %m\n'
39
+ }
40
+ }
41
+
42
+ } # logging configuration
@@ -0,0 +1,13 @@
1
+
2
+ Logging.configure {
3
+
4
+ logger(:root) {
5
+ level :info
6
+ appenders 'stdout'
7
+ }
8
+
9
+ appender('stdout') {
10
+ type 'Stdout'
11
+ }
12
+
13
+ } # logging configuration
@@ -1,10 +1,8 @@
1
- # $Id$
2
1
 
3
2
  # Equivalent to a header guard in C/C++
4
3
  # Used to prevent the class/module from being loaded more than once
5
4
  unless defined? Logging
6
5
 
7
- # TODO: internal logger for debugging
8
6
  # TODO: Windows Log Service appender
9
7
 
10
8
  #
@@ -12,7 +10,7 @@ unless defined? Logging
12
10
  module Logging
13
11
 
14
12
  # :stopdoc:
15
- VERSION = '0.8.0'
13
+ VERSION = '0.9.0'
16
14
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
17
15
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
18
16
  WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM
@@ -24,12 +22,20 @@ module Logging
24
22
 
25
23
  # call-seq:
26
24
  # Logging.configure( filename )
25
+ # Logging.configure { block }
27
26
  #
28
27
  # Configures the Logging framework using the configuration information
29
28
  # found in the given file. The file extension should be either '.yaml'
30
29
  # or '.yml' (XML configuration is not yet supported).
31
30
  #
32
- def configure( filename, *args )
31
+ def configure( *args, &block )
32
+ if block
33
+ return ::Logging::Config::Configurator.process(&block)
34
+ end
35
+
36
+ filename = args.shift
37
+ raise ArgumentError, 'a filename was not given' if filename.nil?
38
+
33
39
  case File.extname(filename)
34
40
  when '.yaml', '.yml'
35
41
  ::Logging::Config::YamlConfigurator.load(filename, *args)
@@ -187,7 +193,7 @@ module Logging
187
193
  end
188
194
 
189
195
  longest = names.values.inject {|x,y| (x.length > y.length) ? x : y}
190
- module_eval "MAX_LEVEL_LENGTH = #{longest.length}"
196
+ module_eval "MAX_LEVEL_LENGTH = #{longest.length}", __FILE__, __LINE__
191
197
 
192
198
  levels.keys
193
199
  end
@@ -214,7 +220,7 @@ module Logging
214
220
  raise ArgumentError, "unknown object format '#{f}'"
215
221
  end
216
222
 
217
- module_eval "OBJ_FORMAT = :#{f}"
223
+ module_eval "OBJ_FORMAT = :#{f}", __FILE__, __LINE__
218
224
  end
219
225
 
220
226
  # Returns the version string for the library.
@@ -228,7 +234,7 @@ module Logging
228
234
  # <tt>File.join</tt>.
229
235
  #
230
236
  def libpath( *args )
231
- args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
237
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
232
238
  end
233
239
 
234
240
  # Returns the lpath for the module. If any arguments are given,
@@ -236,7 +242,7 @@ module Logging
236
242
  # <tt>File.join</tt>.
237
243
  #
238
244
  def path( *args )
239
- args.empty? ? PATH : ::File.join(PATH, *args)
245
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
240
246
  end
241
247
 
242
248
  # Utility method used to rquire all files ending in .rb that lie in the
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require 'thread'
4
3
 
@@ -71,7 +70,8 @@ class Appender
71
70
 
72
71
  end # class << self
73
72
 
74
- attr_reader :name, :layout, :level
73
+ attr_reader :name, :layout, :level, :log
74
+ private :log
75
75
 
76
76
  # call-seq:
77
77
  # Appender.new( name )
@@ -83,6 +83,8 @@ class Appender
83
83
  # created.
84
84
  #
85
85
  def initialize( name, opts = {} )
86
+ @log = ::Logging::Logger[self]
87
+
86
88
  @name = name.to_s
87
89
  @closed = false
88
90
 
@@ -91,7 +93,14 @@ class Appender
91
93
 
92
94
  @mutex = Mutex.new
93
95
  header = @layout.header
94
- sync {write(header)} unless header.nil? || header.empty?
96
+
97
+ unless header.nil? || header.empty?
98
+ begin
99
+ sync {write(header)}
100
+ rescue StandardError => err
101
+ log.error err
102
+ end
103
+ end
95
104
 
96
105
  ::Logging::Appender[@name] = self
97
106
  end
@@ -108,7 +117,16 @@ class Appender
108
117
  "appender '<#{self.class.name}: #{@name}>' is closed"
109
118
  end
110
119
 
111
- sync {write(event)} unless @level > event.level
120
+ # only append if the event level is less than or equal to the configured
121
+ # appender level
122
+ unless @level > event.level
123
+ begin
124
+ sync {write(event)}
125
+ rescue StandardError => err
126
+ log.error err
127
+ end
128
+ end
129
+
112
130
  self
113
131
  end
114
132
 
@@ -124,7 +142,13 @@ class Appender
124
142
  "appender '<#{self.class.name}: #{@name}>' is closed"
125
143
  end
126
144
 
127
- sync {write(str)} unless @level >= ::Logging::LEVELS.length
145
+ unless @level >= ::Logging::LEVELS.length
146
+ begin
147
+ sync {write(str)}
148
+ rescue StandardError => err
149
+ log.error err
150
+ end
151
+ end
128
152
  self
129
153
  end
130
154
 
@@ -197,7 +221,13 @@ class Appender
197
221
  @closed = true
198
222
  if footer
199
223
  footer = @layout.footer
200
- sync {write(footer)} unless footer.nil? || footer.empty?
224
+ unless footer.nil? || footer.empty?
225
+ begin
226
+ sync {write(footer)}
227
+ rescue StandardError => err
228
+ log.error err
229
+ end
230
+ end
201
231
  end
202
232
  self
203
233
  end
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require Logging.libpath(*%w[logging appenders io])
4
3
 
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require 'net/smtp'
4
3
  require 'time' # get rfc822 time format
@@ -116,10 +115,10 @@ class Email < ::Logging::Appender
116
115
  ### send email
117
116
  begin
118
117
  Net::SMTP.start(*@params) {|smtp| smtp.sendmail(rfc822msg, @from, @to)}
119
- rescue Exception => e
118
+ rescue StandardError => err
120
119
  self.level = :off
121
- STDERR.puts e.message
122
- # TODO - log that e-mail notification has been turned off
120
+ log.warn 'e-mail notifications have been disabled'
121
+ log.error err
123
122
  ensure
124
123
  @buff.clear
125
124
  end
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  module Logging::Appenders
4
3
 
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  module Logging::Appenders
4
3
 
@@ -35,7 +34,7 @@ module Logging::Appenders
35
34
  # make sure the growlnotify command can be called
36
35
  unless system('growlnotify -v 2>&1 > /dev/null')
37
36
  self.level = :off
38
- # TODO - log that the growl notification is turned off
37
+ log.warn 'growl notifications have been disabled'
39
38
  end
40
39
  end
41
40
 
@@ -118,7 +117,7 @@ module Logging::Appenders
118
117
  def growl( title, message, priority )
119
118
  message.tr!("`", "'")
120
119
  if @coalesce then coalesce(title, message, priority)
121
- else system @growl % [title, message, priority] end
120
+ else call_growl(title, message, priority) end
122
121
  end
123
122
 
124
123
  # call-seq:
@@ -168,15 +167,27 @@ module Logging::Appenders
168
167
  loop do
169
168
  sleep 0.5
170
169
  @c_mutex.synchronize {
171
- system(@growl % @c_queue.shift) until @c_queue.empty?
170
+ call_growl(*@c_queue.shift) until @c_queue.empty?
172
171
  }
173
172
  Thread.stop if @c_queue.empty?
174
173
  end # loop
175
174
  end # Thread.new
176
175
  end
177
176
 
178
- end # class Growl
177
+ # call-seq:
178
+ # call_growl( title, message, priority )
179
+ #
180
+ # Call the growlnotify application with the given parameters. If the
181
+ # system call fails, the growl appender will be disabled.
182
+ #
183
+ def call_growl( *args )
184
+ unless system(@growl % args)
185
+ self.level = :off
186
+ log.warn 'growl notifications have been disabled'
187
+ end
188
+ end
179
189
 
190
+ end # class Growl
180
191
  end # module Logging::Appenders
181
192
 
182
193
  # EOF
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  module Logging::Appenders
4
3
 
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require 'lockfile'
4
3
 
@@ -133,7 +132,7 @@ module Logging::Appenders
133
132
  CODE
134
133
  end
135
134
  meta = class << self; self end
136
- meta.class_eval code
135
+ meta.class_eval code, __FILE__, __LINE__
137
136
 
138
137
  # if the truncate flag was set to true, then roll
139
138
  roll_now = opts.getopt(:truncate, false)
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  begin
4
3
  require 'syslog'
@@ -0,0 +1,182 @@
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
+ appenders dsl.__appenders
33
+ loggers dsl.__loggers
34
+ end
35
+
36
+ # call-seq:
37
+ # pre_config( config )
38
+ #
39
+ # Configures the logging levels, object format style, and root logging
40
+ # level.
41
+ #
42
+ def pre_config( config )
43
+ if config.nil?
44
+ ::Logging.init unless ::Logging.const_defined? 'MAX_LEVEL_LENGTH'
45
+ return
46
+ end
47
+
48
+ # define levels
49
+ levels = config[:levels]
50
+ ::Logging.init(levels) unless levels.nil?
51
+
52
+ # format as
53
+ format = config[:format_as]
54
+ ::Logging.format_as(format) unless format.nil?
55
+ end
56
+
57
+ # call-seq:
58
+ # appenders( ary )
59
+ #
60
+ # Given an array of Appender configurations, this method will iterate
61
+ # over each and create the Appender(s).
62
+ #
63
+ def appenders( ary )
64
+ ary.each {|name, config| appender(name, config)}
65
+ end
66
+
67
+ # call-seq:
68
+ # loggers( ary )
69
+ #
70
+ # Given an array of Logger configurations, this method will iterate over
71
+ # each and create the Logger(s).
72
+ #
73
+ def loggers( ary )
74
+ ary.each do |name, config|
75
+ l = Logging::Logger[name]
76
+ l.level = config[:level] if config[:level]
77
+ l.additive = config[:additive] if l.respond_to? :additive=
78
+ l.trace = config[:trace]
79
+ l.appenders = Array(config[:appenders]).
80
+ map {|name| ::Logging::Appender[name]}
81
+ end
82
+ end
83
+
84
+ # call-seq:
85
+ # appender( name, config )
86
+ #
87
+ # Creates a new Appender based on the given _config_ options (a hash).
88
+ # The type of Appender created is determined by the 'type' option in the
89
+ # config. The remaining config options are passed to the Appender
90
+ # initializer.
91
+ #
92
+ # The config options can also contain a 'layout' option. This should be
93
+ # another set of options used to create a Layout for this Appender.
94
+ #
95
+ def appender( name, config )
96
+ type = config.delete(:type)
97
+ raise Error, "appender type not given for #{name.inspect}" if type.nil?
98
+
99
+ config[:layout] = layout(config[:layout]) if config.has_key? :layout
100
+
101
+ clazz = ::Logging::Appenders.const_get type
102
+ clazz.new(name, config)
103
+ rescue NameError => err
104
+ raise Error, "unknown appender class Logging::Appenders::#{type}"
105
+ end
106
+
107
+ # call-seq:
108
+ # layout( config )
109
+ #
110
+ # Creates a new Layout based on the given _config_ options (a hash).
111
+ # The type of Layout created is determined by the 'type' option in the
112
+ # config. The remaining config options are passed to the Layout
113
+ # initializer.
114
+ #
115
+ def layout( config )
116
+ return ::Logging::Layouts::Basic.new if config.nil?
117
+
118
+ type = config.delete(:type)
119
+ raise Error, 'layout type not given' if type.nil?
120
+
121
+ clazz = ::Logging::Layouts.const_get type
122
+ clazz.new config
123
+ rescue NameError => err
124
+ raise Error, "unknown layout class Logging::Layouts::#{type}"
125
+ end
126
+
127
+ class DSL
128
+ alias :__instance_eval :instance_eval
129
+
130
+ instance_methods.each do |m|
131
+ undef_method m unless m[%r/^__/]
132
+ end
133
+
134
+ def self.process( &block )
135
+ dsl = new
136
+ dsl.__instance_eval(&block)
137
+ dsl.__hash
138
+ end
139
+
140
+ def __hash
141
+ @hash ||= Hash.new
142
+ end
143
+
144
+ def method_missing( method, *args, &block )
145
+ args << DSL.process(&block) if block
146
+
147
+ key = method.to_sym
148
+ value = (1 == args.length ? args.first : args)
149
+ __store(key, value)
150
+ end
151
+
152
+ def __store( key, value )
153
+ __hash[key] = value
154
+ end
155
+ end
156
+
157
+ class TopLevelDSL < DSL
158
+ undef_method :method_missing
159
+
160
+ def pre_config( &block )
161
+ __store(:preconfig, DSL.process(&block))
162
+ end
163
+
164
+ def logger( name, &block )
165
+ @loggers ||= []
166
+ @loggers << [name, DSL.process(&block)]
167
+ end
168
+
169
+ def appender( name, &block )
170
+ @appenders ||= []
171
+ @appenders << [name, DSL.process(&block)]
172
+ end
173
+
174
+ def __pre_config() __hash[:preconfig]; end
175
+ def __loggers() @loggers; end
176
+ def __appenders() @appenders; end
177
+ end
178
+
179
+ end # class Configurator
180
+ end # module Logging::Config
181
+
182
+ # EOF