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,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