sgeorgi-logging 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
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,201 @@
1
+
2
+ # --------------------------------------------------------------------------
3
+ class Hash
4
+
5
+ # call-seq:
6
+ # getopt( key, default = nil, :as => class )
7
+ #
8
+ # Returns the value associated with the _key_. If the has does not contain
9
+ # the _key_, then the _default_ value is returned.
10
+ #
11
+ # Optionally, the value can be converted into to an instance of the given
12
+ # _class_. The supported classes are:
13
+ #
14
+ # Integer
15
+ # Float
16
+ # Array
17
+ # String
18
+ # Symbol
19
+ #
20
+ # If the value is +nil+, then no converstion will be performed.
21
+ #
22
+ def getopt( *args )
23
+ opts = args.last.instance_of?(Hash) ? args.pop : {}
24
+ key, default = args
25
+
26
+ val = if has_key?(key); self[key]
27
+ elsif has_key?(key.to_s); self[key.to_s]
28
+ elsif has_key?(key.to_s.intern); self[key.to_s.intern]
29
+ else default end
30
+
31
+ return if val.nil?
32
+ return val unless opts.has_key?(:as)
33
+
34
+ case opts[:as].name.intern
35
+ when :Integer; Integer(val)
36
+ when :Float; Float(val)
37
+ when :Array; Array(val)
38
+ when :String; String(val)
39
+ when :Symbol; String(val).intern
40
+ else val end
41
+ end
42
+ end
43
+
44
+ # --------------------------------------------------------------------------
45
+ class String
46
+
47
+ # call-seq:
48
+ # reduce( width, ellipses = '...' ) #=> string
49
+ #
50
+ # Reduce the size of the current string to the given _width_ by removing
51
+ # characters from the middle of the string and replacing them with
52
+ # _ellipses_. If the _width_ is greater than the length of the string, the
53
+ # string is returned unchanged. If the _width_ is less than the length of
54
+ # the _ellipses_, then the _ellipses_ are returned.
55
+ #
56
+ def reduce( width, ellipses = '...')
57
+ raise ArgumentError, "width cannot be negative: #{width}" if width < 0
58
+
59
+ return self if length <= width
60
+
61
+ remove = length - width + ellipses.length
62
+ return ellipses.dup if remove >= length
63
+
64
+ left_end = (length + 1 - remove) / 2
65
+ right_start = left_end + remove
66
+
67
+ left = self[0,left_end]
68
+ right = self[right_start,length-right_start]
69
+
70
+ left << ellipses << right
71
+ end
72
+ end
73
+
74
+ # --------------------------------------------------------------------------
75
+ class Module
76
+
77
+ # call-seq:
78
+ # logger_name #=> string
79
+ #
80
+ # Returns a predictable logger name for the current module or class. If
81
+ # used within an anonymous class, the first non-anonymous class name will
82
+ # be used as the logger name. If used within a meta-class, the name of the
83
+ # actual class will be used as the logger name. If used within an
84
+ # anonymous module, the string 'anonymous' will be returned.
85
+ #
86
+ def logger_name
87
+ return name unless name.nil? or name.empty?
88
+
89
+ # check if this is a metaclass (or eigenclass)
90
+ if ancestors.include? Class
91
+ inspect =~ %r/#<Class:([^#>]+)>/
92
+ return $1
93
+ end
94
+
95
+ # see if we have a superclass
96
+ if respond_to? :superclass
97
+ return superclass.logger_name
98
+ end
99
+
100
+ # we are an anonymous module
101
+ ::Logging.log_internal(-2) {
102
+ 'cannot return a predictable, unique name for anonymous modules'
103
+ }
104
+ return 'anonymous'
105
+ end
106
+ end
107
+
108
+ # --------------------------------------------------------------------------
109
+ module Kernel
110
+
111
+ # call-seq:
112
+ # require?( string )
113
+ #
114
+ # Attempt to the load the library named _string_ using the standard
115
+ # Kernel#require method. Returns +true+ if the library was successfully
116
+ # loaded. Returns +false+ if the library could not be loaded. This method
117
+ # will never raise an exception.
118
+ #
119
+ def require?( string )
120
+ require string
121
+ return true
122
+ rescue LoadError
123
+ return false
124
+ end
125
+ end # module Kernel
126
+
127
+ # --------------------------------------------------------------------------
128
+ class File
129
+
130
+ # Returns <tt>true</tt> if another process holds an exclusive lock on the
131
+ # file. Returns <tt>false</tt> if this is not the case.
132
+ #
133
+ # If a <tt>block</tt> of code is passed to this method, it will be run iff
134
+ # this process can obtain an exclusive lock on the file. The block will be
135
+ # run while this lock is held, and the exclusive lock will be released when
136
+ # the method returns.
137
+ #
138
+ # The exclusive lock is requested in a non-blocking mode. This method will
139
+ # return immediately (and the block will not be executed) if an exclusive
140
+ # lock cannot be obtained.
141
+ #
142
+ def flock?( &block )
143
+ status = flock(LOCK_EX|LOCK_NB)
144
+ case status
145
+ when false; true
146
+ when 0; block ? block.call : false
147
+ else
148
+ raise SystemCallError, "flock failed with status: #{status}"
149
+ end
150
+ ensure
151
+ flock LOCK_UN
152
+ end
153
+
154
+ # Execute the <tt>block</tt> in the context of a shared lock on this file. A
155
+ # shared lock will be obtained on the file, the block executed, and the lock
156
+ # released.
157
+ #
158
+ def flock_sh( &block )
159
+ flock LOCK_SH
160
+ block.call
161
+ ensure
162
+ flock LOCK_UN
163
+ end
164
+
165
+ # :stopdoc:
166
+ if %r/mswin|mingw/ =~ RUBY_PLATFORM
167
+ undef :flock?, :flock_sh
168
+ def flock?() yield; end
169
+ def flock_sh() yield; end
170
+ end
171
+ # :startdoc:
172
+
173
+ end
174
+
175
+ # --------------------------------------------------------------------------
176
+ class ReentrantMutex < Mutex
177
+
178
+ def initialize
179
+ super
180
+ @locker = nil
181
+ end
182
+
183
+ alias :original_synchronize :synchronize
184
+
185
+ def synchronize
186
+ if @locker == Thread.current
187
+ yield
188
+ else
189
+ original_synchronize {
190
+ begin
191
+ @locker = Thread.current
192
+ yield
193
+ ensure
194
+ @locker = nil
195
+ end
196
+ }
197
+ end
198
+ end
199
+ end # class ReentrantMutex
200
+
201
+ # EOF
@@ -0,0 +1,34 @@
1
+
2
+ module Spec
3
+ module LoggingHelper
4
+
5
+ # Capture log messages from the Logging framework and make them
6
+ # available via a @log_output instance variable. The @log_output
7
+ # supports a readline method to access the log messags.
8
+ #
9
+ def capture_log_messages( opts = {} )
10
+ from = opts.getopt(:from, 'root')
11
+ to = opts.getopt(:to, '__rspec__')
12
+ exclusive = opts.getopt(:exclusive, true)
13
+
14
+ appender = Logging::Appenders[to] || Logging::Appenders::StringIo.new(to)
15
+ logger = Logging::Logger[from]
16
+ if exclusive
17
+ logger.appenders = appender
18
+ else
19
+ logger.add_appenders(appender)
20
+ end
21
+
22
+ before(:all) do
23
+ @log_output = Logging::Appenders[to]
24
+ end
25
+
26
+ before(:each) do
27
+ @log_output.reset
28
+ end
29
+ end
30
+
31
+ end # module LoggingHelper
32
+ end # module Spec
33
+
34
+ # EOF
@@ -0,0 +1,176 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[.. setup])
3
+
4
+ module TestLogging
5
+ module TestAppenders
6
+
7
+ class TestBufferedIO < Test::Unit::TestCase
8
+ include LoggingTestCase
9
+
10
+ def setup
11
+ super
12
+ @appender = Logging.appenders.string_io(
13
+ 'test_appender', :auto_flushing => 3, :immediate_at => :error
14
+ )
15
+ @appender.clear
16
+ @sio = @appender.sio
17
+ @levels = Logging::LEVELS
18
+ begin readline rescue EOFError end
19
+ end
20
+
21
+ def test_append
22
+ event = Logging::LogEvent.new('TestLogger', @levels['warn'],
23
+ [1, 2, 3, 4], false)
24
+ @appender.append event
25
+ assert_nil(readline)
26
+
27
+ @appender.append event
28
+ assert_nil(readline)
29
+
30
+ event.level = @levels['debug']
31
+ event.data = 'the big log message'
32
+ @appender.append event
33
+
34
+ assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
35
+ assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
36
+ assert_equal "DEBUG TestLogger : the big log message\n", readline
37
+ assert_nil(readline)
38
+
39
+ @appender.close
40
+ assert_raise(RuntimeError) {@appender.append event}
41
+ end
42
+
43
+ def test_append_error
44
+ # setup an internal logger to capture error messages from the IO
45
+ # appender
46
+ log = Logging.appenders.string_io('__internal_io')
47
+ Logging.logger[Logging].add_appenders(log)
48
+ Logging.logger[Logging].level = 'all'
49
+
50
+
51
+ # close the string IO object so we get an error
52
+ @sio.close
53
+ event = Logging::LogEvent.new('TestLogger', @levels['warn'],
54
+ [1, 2, 3, 4], false)
55
+ @appender.append event
56
+ assert_nil(log.readline)
57
+
58
+ @appender.append event
59
+ assert_nil(log.readline)
60
+
61
+ @appender.append event
62
+ assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
63
+ assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
64
+
65
+ assert_equal false, @appender.closed?
66
+ assert_equal 5, @appender.level
67
+ end
68
+
69
+ def test_auto_flushing
70
+ assert_raise(ArgumentError) {
71
+ @appender.auto_flushing = Object.new
72
+ }
73
+
74
+ assert_raise(ArgumentError) {
75
+ @appender.auto_flushing = -1
76
+ }
77
+ end
78
+
79
+ def test_close
80
+ assert_equal false, @sio.closed?
81
+ assert_equal false, @appender.closed?
82
+
83
+ @appender.close
84
+ assert_equal true, @sio.closed?
85
+ assert_equal true, @appender.closed?
86
+
87
+ [STDIN, STDERR, STDOUT].each do |io|
88
+ @appender = Logging.appenders.io('test', io)
89
+ @appender.close
90
+ assert_equal false, io.closed?
91
+ assert_equal true, @appender.closed?
92
+ end
93
+ end
94
+
95
+ def test_concat
96
+ @appender << "this is a test message\n"
97
+ assert_nil(readline)
98
+
99
+ @appender << "this is another message\n"
100
+ assert_nil(readline)
101
+
102
+ @appender << "some other line\n"
103
+
104
+ assert_equal "this is a test message\n", readline
105
+ assert_equal "this is another message\n", readline
106
+ assert_equal "some other line\n", readline
107
+ assert_nil(readline)
108
+
109
+ @appender.close
110
+ assert_raise(RuntimeError) {@appender << 'message'}
111
+ end
112
+
113
+ def test_concat_error
114
+ # setup an internal logger to capture error messages from the IO
115
+ # appender
116
+ log = Logging.appenders.string_io('__internal_io')
117
+ Logging.logger[Logging].add_appenders(log)
118
+ Logging.logger[Logging].level = 'all'
119
+
120
+ # close the string IO object so we get an error
121
+ @sio.close
122
+ @appender << 'oopsy'
123
+ assert_nil(log.readline)
124
+
125
+ @appender << 'whoopsy'
126
+ assert_nil(log.readline)
127
+
128
+ @appender << 'pooh'
129
+ assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
130
+ assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
131
+
132
+ # and the appender does not close itself
133
+ assert_equal false, @appender.closed?
134
+ assert_equal 5, @appender.level
135
+ end
136
+
137
+ def test_flush
138
+ ary = []
139
+ @sio.instance_variable_set :@ary, ary
140
+ def @sio.flush() @ary << :flush end
141
+
142
+ @appender << "this is a test message\n"
143
+ assert_nil(readline)
144
+
145
+ @appender.flush
146
+ assert_equal :flush, ary.pop
147
+ assert_equal "this is a test message\n", readline
148
+ assert_nil(readline)
149
+ end
150
+
151
+ def test_immediate_at
152
+ event = Logging::LogEvent.new('TestLogger', @levels['warn'],
153
+ [1, 2, 3, 4], false)
154
+ @appender.append event
155
+ assert_nil(readline)
156
+
157
+ event.level = @levels['error']
158
+ event.data = 'an error message'
159
+ @appender.append event
160
+
161
+ assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
162
+ assert_equal "ERROR TestLogger : an error message\n", readline
163
+ assert_nil(readline)
164
+ end
165
+
166
+ private
167
+ def readline
168
+ @appender.readline
169
+ end
170
+
171
+ end # class TestBufferedIO
172
+
173
+ end # module TestAppenders
174
+ end # module TestLogging
175
+
176
+ # EOF
@@ -0,0 +1,66 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[.. setup])
3
+
4
+ module TestLogging
5
+ module TestAppenders
6
+
7
+ class TestStdout < Test::Unit::TestCase
8
+ include LoggingTestCase
9
+
10
+ def test_initialize
11
+ Logging::Repository.instance
12
+
13
+ appender = Logging.appenders.stdout
14
+ assert_equal 'stdout', appender.name
15
+ assert_same STDOUT, appender.instance_variable_get(:@io)
16
+
17
+ appender.close
18
+ assert_equal true, appender.closed?
19
+ assert_equal false, STDOUT.closed?
20
+
21
+ appender = Logging.appenders.stdout('foo')
22
+ assert_equal 'foo', appender.name
23
+
24
+ appender = Logging.appenders.stdout(:level => :warn)
25
+ assert_equal 'stdout', appender.name
26
+ assert_equal 2, appender.level
27
+
28
+ appender = Logging.appenders.stdout('bar', :level => :error)
29
+ assert_equal 'bar', appender.name
30
+ assert_equal 3, appender.level
31
+ end
32
+
33
+ end # class TestStdout
34
+
35
+ class TestStderr < Test::Unit::TestCase
36
+ include LoggingTestCase
37
+
38
+ def test_initialize
39
+ Logging::Repository.instance
40
+
41
+ appender = Logging.appenders.stderr
42
+ assert_equal 'stderr', appender.name
43
+ assert_same STDERR, appender.instance_variable_get(:@io)
44
+
45
+ appender.close
46
+ assert_equal true, appender.closed?
47
+ assert_equal false, STDERR.closed?
48
+
49
+ appender = Logging.appenders.stderr('foo')
50
+ assert_equal 'foo', appender.name
51
+
52
+ appender = Logging.appenders.stderr(:level => :warn)
53
+ assert_equal 'stderr', appender.name
54
+ assert_equal 2, appender.level
55
+
56
+ appender = Logging.appenders.stderr('bar', :level => :error)
57
+ assert_equal 'bar', appender.name
58
+ assert_equal 3, appender.level
59
+ end
60
+
61
+ end # class TestStderr
62
+
63
+ end # module TestAppenders
64
+ end # module TestLogging
65
+
66
+ # EOF