logging 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/History.txt +9 -1
  2. data/Manifest.txt +3 -4
  3. data/Rakefile +8 -7
  4. data/lib/logging.rb +2 -2
  5. data/lib/logging/appender.rb +1 -1
  6. data/lib/logging/appenders/console.rb +1 -1
  7. data/lib/logging/appenders/email.rb +3 -2
  8. data/lib/logging/appenders/file.rb +1 -1
  9. data/lib/logging/appenders/growl.rb +1 -1
  10. data/lib/logging/appenders/io.rb +1 -1
  11. data/lib/logging/appenders/rolling_file.rb +3 -3
  12. data/lib/logging/appenders/syslog.rb +1 -1
  13. data/lib/logging/config/yaml_configurator.rb +1 -1
  14. data/lib/logging/layout.rb +1 -1
  15. data/lib/logging/layouts/basic.rb +1 -1
  16. data/lib/logging/layouts/pattern.rb +1 -1
  17. data/lib/logging/log_event.rb +1 -1
  18. data/lib/logging/logger.rb +59 -17
  19. data/lib/logging/repository.rb +15 -1
  20. data/lib/logging/root_logger.rb +6 -4
  21. data/lib/logging/utils.rb +1 -1
  22. data/tasks/ann.rake +20 -15
  23. data/tasks/bones.rake +7 -26
  24. data/tasks/gem.rake +49 -36
  25. data/tasks/git.rake +41 -0
  26. data/tasks/notes.rake +28 -0
  27. data/tasks/post_load.rake +19 -10
  28. data/tasks/{doc.rake → rdoc.rake} +10 -7
  29. data/tasks/rubyforge.rake +12 -11
  30. data/tasks/setup.rb +122 -81
  31. data/tasks/test.rake +6 -6
  32. data/test/appenders/test_console.rb +1 -1
  33. data/test/appenders/test_email.rb +4 -2
  34. data/test/appenders/test_file.rb +1 -1
  35. data/test/appenders/test_growl.rb +1 -1
  36. data/test/appenders/test_io.rb +1 -1
  37. data/test/appenders/test_rolling_file.rb +1 -1
  38. data/test/appenders/test_syslog.rb +1 -1
  39. data/test/benchmark.rb +1 -1
  40. data/test/config/test_yaml_configurator.rb +1 -1
  41. data/test/layouts/test_basic.rb +1 -1
  42. data/test/layouts/test_pattern.rb +1 -1
  43. data/test/setup.rb +3 -8
  44. data/test/test_appender.rb +1 -1
  45. data/test/test_layout.rb +1 -1
  46. data/test/test_log_event.rb +1 -1
  47. data/test/test_logger.rb +88 -11
  48. data/test/test_logging.rb +1 -1
  49. data/test/test_repository.rb +5 -1
  50. data/test/test_root_logger.rb +1 -1
  51. data/test/test_utils.rb +1 -1
  52. metadata +15 -7
  53. data/lib/logging/stelan/lockfile.rb +0 -530
  54. data/tasks/annotations.rake +0 -22
  55. data/tasks/svn.rake +0 -44
@@ -6,19 +6,19 @@ namespace :test do
6
6
 
7
7
  Rake::TestTask.new(:run) do |t|
8
8
  t.libs = PROJ.libs
9
- t.test_files = if test(?f, PROJ.test_file) then [PROJ.test_file]
10
- else PROJ.tests end
9
+ t.test_files = if test(?f, PROJ.test.file) then [PROJ.test.file]
10
+ else PROJ.test.files end
11
11
  t.ruby_opts += PROJ.ruby_opts
12
- t.ruby_opts += PROJ.test_opts
12
+ t.ruby_opts += PROJ.test.opts
13
13
  end
14
14
 
15
15
  if HAVE_RCOV
16
16
  desc 'Run rcov on the unit tests'
17
17
  task :rcov => :clobber_rcov do
18
- opts = PROJ.rcov_opts.dup << '-o' << PROJ.rcov_dir
18
+ opts = PROJ.rcov.opts.dup << '-o' << PROJ.rcov.dir
19
19
  opts = opts.join(' ')
20
- files = if test(?f, PROJ.test_file) then [PROJ.test_file]
21
- else PROJ.tests end
20
+ files = if test(?f, PROJ.test.file) then [PROJ.test.file]
21
+ else PROJ.test.files end
22
22
  files = files.join(' ')
23
23
  sh "#{RCOV} #{files} #{opts}"
24
24
  end
@@ -1,4 +1,4 @@
1
- # $Id: test_console.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_email.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
  require 'flexmock'
@@ -47,7 +47,9 @@ module TestAppenders
47
47
  assert_equal([], appender.instance_variable_get(:@immediate))
48
48
  assert_equal('localhost', appender.server)
49
49
  assert_equal(25, appender.port)
50
- assert_equal(ENV['HOSTNAME'], appender.domain)
50
+
51
+ domain = ENV['HOSTNAME'] || 'localhost.localdomain'
52
+ assert_equal(domain, appender.domain)
51
53
  assert_equal(nil, appender.acct)
52
54
  assert_equal(:cram_md5, appender.authtype)
53
55
  assert_equal("Message of #{$0}", appender.subject)
@@ -1,4 +1,4 @@
1
- # $Id: test_file.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_growl.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
  require 'flexmock'
@@ -1,4 +1,4 @@
1
- # $Id: test_io.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_rolling_file.rb 105 2008-02-26 04:43:21Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_syslog.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: benchmark.rb 46 2007-10-31 14:39:01Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  begin
4
4
  require 'logging'
@@ -1,4 +1,4 @@
1
- # $Id: test_yaml_configurator.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_basic.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_pattern.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[.. setup])
4
4
 
@@ -1,13 +1,15 @@
1
- # $Id: setup.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  # Equivalent to a header guard in C/C++
4
4
  # Used to prevent the class/module from being loaded more than once
5
5
  unless defined? LOGGING_TEST_SETUP
6
6
  LOGGING_TEST_SETUP = true
7
7
 
8
+ require 'rubygems'
8
9
  require 'test/unit'
9
10
  require 'fileutils'
10
11
  require 'stringio'
12
+ require 'turn' rescue nil
11
13
 
12
14
  # This line is needed for Ruby 1.9 -- hashes throw a "KeyError" in 1.9
13
15
  # whereas they throw an "IndexError" in 1.8
@@ -16,13 +18,6 @@ KeyError = IndexError if not defined? KeyError
16
18
 
17
19
  require File.join(File.dirname(__FILE__), %w[.. lib logging])
18
20
 
19
- begin
20
- require 'turn'
21
- rescue LoadError
22
- require 'rubygems'
23
- begin; require 'turn'; rescue LoadError; end
24
- end
25
-
26
21
 
27
22
  module TestLogging
28
23
  module LoggingTestCase
@@ -1,4 +1,4 @@
1
- # $Id: test_appender.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_layout.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_log_event.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_logger.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -255,6 +255,13 @@ module TestLogging
255
255
  assert_nil a2.readline
256
256
  end
257
257
 
258
+ def test_inspect
259
+ root = ::Logging::Logger.new :root
260
+
261
+ str = "<#{root.class.name}:0x%x name=\"#{root.name}\">" % root.object_id
262
+ assert_equal str, root.inspect
263
+ end
264
+
258
265
  def test_level
259
266
  root = ::Logging::Logger.new :root
260
267
  log = ::Logging::Logger.new 'A'
@@ -264,7 +271,7 @@ module TestLogging
264
271
 
265
272
  root.level = :warn
266
273
  assert_equal 2, root.level
267
- assert_equal 0, log.level
274
+ assert_equal 2, log.level
268
275
 
269
276
  log.level = nil
270
277
  assert_equal 2, root.level
@@ -278,9 +285,14 @@ module TestLogging
278
285
  def test_level_eq
279
286
  root = ::Logging::Logger.new :root
280
287
  log = ::Logging::Logger.new 'A'
288
+ logb = ::Logging::Logger.new 'A::B'
281
289
 
282
290
  assert_equal 0, root.level
283
291
  assert_equal 0, log.level
292
+ assert_equal 0, logb.level
293
+ assert_equal true, root.debug?
294
+ assert_equal true, log.debug?
295
+ assert_equal true, logb.debug?
284
296
 
285
297
  assert_raise(ArgumentError) {root.level = -1}
286
298
  assert_raise(ArgumentError) {root.level = 6}
@@ -290,47 +302,112 @@ module TestLogging
290
302
 
291
303
  root.level = 'INFO'
292
304
  assert_equal 1, root.level
293
- assert_equal 0, log.level
305
+ assert_equal 1, log.level
306
+ assert_equal 1, logb.level
307
+ assert_equal false, root.debug?
308
+ assert_equal true, root.info?
309
+ assert_equal false, log.debug?
310
+ assert_equal true , log.info?
311
+ assert_equal false, logb.debug?
312
+ assert_equal true , logb.info?
294
313
 
295
314
  root.level = :warn
296
315
  assert_equal 2, root.level
297
- assert_equal 0, log.level
316
+ assert_equal 2, log.level
317
+ assert_equal 2, logb.level
318
+ assert_equal false, root.info?
319
+ assert_equal true, root.warn?
320
+ assert_equal false, log.info?
321
+ assert_equal true , log.warn?
322
+ assert_equal false, logb.info?
323
+ assert_equal true , logb.warn?
298
324
 
299
325
  root.level = 'error'
300
326
  assert_equal 3, root.level
301
- assert_equal 0, log.level
327
+ assert_equal 3, log.level
328
+ assert_equal 3, logb.level
329
+ assert_equal false, root.warn?
330
+ assert_equal true, root.error?
331
+ assert_equal false, log.warn?
332
+ assert_equal true , log.error?
333
+ assert_equal false, logb.warn?
334
+ assert_equal true , logb.error?
302
335
 
303
336
  root.level = 4
304
337
  assert_equal 4, root.level
305
- assert_equal 0, log.level
338
+ assert_equal 4, log.level
339
+ assert_equal 4, logb.level
340
+ assert_equal false, root.error?
341
+ assert_equal true, root.fatal?
342
+ assert_equal false, log.error?
343
+ assert_equal true , log.fatal?
344
+ assert_equal false, logb.error?
345
+ assert_equal true , logb.fatal?
306
346
 
307
347
  log.level = nil
308
348
  assert_equal 4, root.level
309
349
  assert_equal 4, log.level
350
+ assert_equal 4, logb.level
351
+ assert_equal false, root.error?
352
+ assert_equal true, root.fatal?
353
+ assert_equal false, log.error?
354
+ assert_equal true , log.fatal?
355
+ assert_equal false, logb.error?
356
+ assert_equal true , logb.fatal?
310
357
 
311
358
  log.level = :DEBUG
312
359
  assert_equal 4, root.level
313
360
  assert_equal 0, log.level
361
+ assert_equal 0, logb.level
362
+ assert_equal false, root.error?
363
+ assert_equal true, root.fatal?
364
+ assert_equal true, log.debug?
365
+ assert_equal true, logb.debug?
314
366
 
315
367
  log.level = :off
316
368
  assert_equal 4, root.level
317
369
  assert_equal 5, log.level
370
+ assert_equal 5, logb.level
371
+ assert_equal false, root.error?
372
+ assert_equal true, root.fatal?
373
+ assert_equal false, log.fatal?
374
+ assert_equal false, logb.fatal?
318
375
 
319
376
  root.level = :all
320
377
  assert_equal 0, root.level
321
378
  assert_equal 5, log.level
379
+ assert_equal 5, logb.level
380
+ assert_equal true, root.debug?
381
+ assert_equal false, log.fatal?
382
+ assert_equal false, logb.fatal?
322
383
 
323
384
  log.level = nil
324
385
  assert_equal 0, root.level
325
386
  assert_equal 0, log.level
387
+ assert_equal 0, logb.level
388
+ assert_equal true, root.debug?
389
+ assert_equal true, log.debug?
390
+ assert_equal true, logb.debug?
326
391
 
327
- root.level = :warn
328
- assert_equal 2, root.level
329
- assert_equal 0, log.level
330
-
331
- root.level = nil
392
+ logb.level = :warn
332
393
  assert_equal 0, root.level
333
394
  assert_equal 0, log.level
395
+ assert_equal 2, logb.level
396
+ assert_equal true, root.debug?
397
+ assert_equal true, log.debug?
398
+ assert_equal false, logb.info?
399
+ assert_equal true, logb.warn?
400
+
401
+ log.level = :info
402
+ logb.level = nil
403
+ assert_equal 0, root.level
404
+ assert_equal 1, log.level
405
+ assert_equal 1, logb.level
406
+ assert_equal true, root.debug?
407
+ assert_equal false, logb.debug?
408
+ assert_equal true, log.info?
409
+ assert_equal false, logb.debug?
410
+ assert_equal true, logb.info?
334
411
  end
335
412
 
336
413
  def test_log
@@ -1,4 +1,4 @@
1
- # $Id: test_logging.rb 97 2008-02-13 00:32:18Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_repository.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -79,6 +79,8 @@ module TestLogging
79
79
  ::Logging::Logger.new('A::B::C::E::G')
80
80
 
81
81
  assert_same @repo['A::B::C::E'], @repo.parent('A::B::C::E::G')
82
+
83
+ assert_nil @repo.parent('root')
82
84
  end
83
85
 
84
86
  def test_children
@@ -102,6 +104,8 @@ module TestLogging
102
104
 
103
105
  assert_equal a, @repo.children('A::B::C')
104
106
  assert_equal [@repo['A::B::C::E::G']], @repo.children('A::B::C::E')
107
+
108
+ assert_equal [@repo['A']], @repo.children('root')
105
109
  end
106
110
 
107
111
  def test_to_key
@@ -1,4 +1,4 @@
1
- # $Id: test_root_logger.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
@@ -1,4 +1,4 @@
1
- # $Id: test_utils.rb 88 2008-02-08 18:47:36Z tim_pease $
1
+ # $Id$
2
2
 
3
3
  require File.join(File.dirname(__FILE__), %w[setup])
4
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Pease
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-25 00:00:00 -07:00
12
+ date: 2008-07-02 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -21,6 +21,15 @@ dependencies:
21
21
  - !ruby/object:Gem::Version
22
22
  version: 0.8.0
23
23
  version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: lockfile
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.4.3
32
+ version:
24
33
  description: Logging is a flexible logging library for use in Ruby programs based on the design of Java's log4j library. It features a hierarchical logging system, custom level names, multiple output destinations per log event, custom formatting, and more.
25
34
  email: tim.pease@gmail.com
26
35
  executables: []
@@ -53,18 +62,17 @@ files:
53
62
  - lib/logging/logger.rb
54
63
  - lib/logging/repository.rb
55
64
  - lib/logging/root_logger.rb
56
- - lib/logging/stelan/lockfile.rb
57
65
  - lib/logging/utils.rb
58
66
  - tasks/ann.rake
59
- - tasks/annotations.rake
60
67
  - tasks/bones.rake
61
- - tasks/doc.rake
62
68
  - tasks/gem.rake
69
+ - tasks/git.rake
63
70
  - tasks/manifest.rake
71
+ - tasks/notes.rake
64
72
  - tasks/post_load.rake
73
+ - tasks/rdoc.rake
65
74
  - tasks/rubyforge.rake
66
75
  - tasks/setup.rb
67
- - tasks/svn.rake
68
76
  - tasks/test.rake
69
77
  - test/appenders/test_console.rb
70
78
  - test/appenders/test_email.rb
@@ -109,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
117
  requirements: []
110
118
 
111
119
  rubyforge_project: logging
112
- rubygems_version: 1.0.1
120
+ rubygems_version: 1.1.1
113
121
  signing_key:
114
122
  specification_version: 2
115
123
  summary: A flexible and extendable logging library for Ruby
@@ -1,530 +0,0 @@
1
- # $Id: lockfile.rb 101 2008-02-13 17:10:47Z tim_pease $
2
-
3
- # This file was stolen with permission from Ara T. Howrad's gem of the same
4
- # name. The only difference is the removal of Ara's vim folding turds and
5
- # making the code work with Ruby1.9
6
-
7
- unless(defined?($__logging_lockfile__) or defined?(Logging::Lockfile))
8
-
9
- require 'socket'
10
- require 'timeout'
11
- require 'fileutils'
12
-
13
- module Logging
14
- class Lockfile
15
-
16
- VERSION = '1.4.3'
17
- def version() VERSION end
18
-
19
- class LockError < StandardError; end
20
- class StolenLockError < LockError; end
21
- class StackingLockError < LockError; end
22
- class StatLockError < LockError; end
23
- class MaxTriesLockError < LockError; end
24
- class TimeoutLockError < LockError; end
25
- class NFSLockError < LockError; end
26
- class UnLockError < LockError; end
27
-
28
- class SleepCycle < Array
29
- attr :min
30
- attr :max
31
- attr :range
32
- attr :inc
33
-
34
- def initialize( min, max, inc )
35
- @min, @max, @inc = Float(min), Float(max), Float(inc)
36
- @range = @max - @min
37
- raise RangeError, "max(#{ @max }) <= min(#{ @min })" if @max <= @min
38
- raise RangeError, "inc(#{ @inc }) > range(#{ @range })" if @inc > @range
39
- raise RangeError, "inc(#{ @inc }) <= 0" if @inc <= 0
40
- raise RangeError, "range(#{ @range }) <= 0" if @range <= 0
41
- s = @min
42
- push(s) and s += @inc while(s <= @max)
43
- self[-1] = @max if self[-1] < @max
44
- reset
45
- end
46
-
47
- def next
48
- ret = self[@idx]
49
- @idx = ((@idx + 1) % self.size)
50
- ret
51
- end
52
-
53
- def reset
54
- @idx = 0
55
- end
56
- end # class SleepCycle
57
-
58
- HOSTNAME = Socket::gethostname
59
-
60
- DEFAULT_RETRIES = nil # maximum number of attempts
61
- DEFAULT_TIMEOUT = nil # the longest we will try
62
- DEFAULT_MAX_AGE = 3600 # lockfiles older than this are stale
63
- DEFAULT_SLEEP_INC = 2 # sleep cycle is this much longer each time
64
- DEFAULT_MIN_SLEEP = 2 # shortest sleep time
65
- DEFAULT_MAX_SLEEP = 32 # longest sleep time
66
- DEFAULT_SUSPEND = 1800 # iff we steal a lock wait this long before we go on
67
- DEFAULT_REFRESH = 8 # how often we touch/validate the lock
68
- DEFAULT_DONT_CLEAN = false # iff we leave lock files lying around
69
- DEFAULT_POLL_RETRIES = 16 # this many polls makes one 'try'
70
- DEFAULT_POLL_MAX_SLEEP = 0.08 # the longest we'll sleep between polls
71
- DEFAULT_DONT_SWEEP = false # if we cleanup after other process on our host
72
- DEFAULT_DONT_USE_LOCK_ID = false # if we dump lock info into lockfile
73
-
74
- DEFAULT_DEBUG = ENV['LOCKFILE_DEBUG'] || false
75
-
76
- class << self
77
- attr_accessor :retries
78
- attr_accessor :max_age
79
- attr_accessor :sleep_inc
80
- attr_accessor :min_sleep
81
- attr_accessor :max_sleep
82
- attr_accessor :suspend
83
- attr_accessor :timeout
84
- attr_accessor :refresh
85
- attr_accessor :debug
86
- attr_accessor :dont_clean
87
- attr_accessor :poll_retries
88
- attr_accessor :poll_max_sleep
89
- attr_accessor :dont_sweep
90
- attr_accessor :dont_use_lock_id
91
-
92
- def init
93
- @retries = DEFAULT_RETRIES
94
- @max_age = DEFAULT_MAX_AGE
95
- @sleep_inc = DEFAULT_SLEEP_INC
96
- @min_sleep = DEFAULT_MIN_SLEEP
97
- @max_sleep = DEFAULT_MAX_SLEEP
98
- @suspend = DEFAULT_SUSPEND
99
- @timeout = DEFAULT_TIMEOUT
100
- @refresh = DEFAULT_REFRESH
101
- @dont_clean = DEFAULT_DONT_CLEAN
102
- @poll_retries = DEFAULT_POLL_RETRIES
103
- @poll_max_sleep = DEFAULT_POLL_MAX_SLEEP
104
- @dont_sweep = DEFAULT_DONT_SWEEP
105
- @dont_use_lock_id = DEFAULT_DONT_USE_LOCK_ID
106
-
107
- @debug = DEFAULT_DEBUG
108
-
109
- STDOUT.sync = true if @debug
110
- STDERR.sync = true if @debug
111
- end
112
- end
113
- self.init
114
-
115
- attr :klass
116
- attr :path
117
- attr :opts
118
- attr :locked
119
- attr :thief
120
- attr :dirname
121
- attr :basename
122
- attr :clean
123
- attr :retries
124
- attr :max_age
125
- attr :sleep_inc
126
- attr :min_sleep
127
- attr :max_sleep
128
- attr :suspend
129
- attr :refresh
130
- attr :timeout
131
- attr :dont_clean
132
- attr :poll_retries
133
- attr :poll_max_sleep
134
- attr :dont_sweep
135
- attr :dont_use_lock_id
136
-
137
- attr_accessor :debug
138
-
139
- alias thief? thief
140
- alias locked? locked
141
- alias debug? debug
142
-
143
- def self::create( path, *a, &b )
144
- opts = {
145
- 'retries' => 0,
146
- 'min_sleep' => 0,
147
- 'max_sleep' => 1,
148
- 'sleep_inc' => 1,
149
- 'max_age' => nil,
150
- 'suspend' => 0,
151
- 'refresh' => nil,
152
- 'timeout' => nil,
153
- 'poll_retries' => 0,
154
- 'dont_clean' => true,
155
- 'dont_sweep' => false,
156
- 'dont_use_lock_id' => true
157
- }
158
- begin
159
- new(path, opts).lock
160
- rescue LockError
161
- raise Errno::EEXIST, path
162
- end
163
- open(path, *a, &b)
164
- end
165
-
166
- def initialize( path, opts = {}, &block )
167
- @klass = self.class
168
- @path = path
169
- @opts = opts
170
-
171
- @retries = getopt 'retries' , @klass.retries
172
- @max_age = getopt 'max_age' , @klass.max_age
173
- @sleep_inc = getopt 'sleep_inc' , @klass.sleep_inc
174
- @min_sleep = getopt 'min_sleep' , @klass.min_sleep
175
- @max_sleep = getopt 'max_sleep' , @klass.max_sleep
176
- @suspend = getopt 'suspend' , @klass.suspend
177
- @timeout = getopt 'timeout' , @klass.timeout
178
- @refresh = getopt 'refresh' , @klass.refresh
179
- @dont_clean = getopt 'dont_clean' , @klass.dont_clean
180
- @poll_retries = getopt 'poll_retries' , @klass.poll_retries
181
- @poll_max_sleep = getopt 'poll_max_sleep' , @klass.poll_max_sleep
182
- @dont_sweep = getopt 'dont_sweep' , @klass.dont_sweep
183
- @dont_use_lock_id = getopt 'dont_use_lock_id' , @klass.dont_use_lock_id
184
- @debug = getopt 'debug' , @klass.debug
185
-
186
- @sleep_cycle = SleepCycle::new @min_sleep, @max_sleep, @sleep_inc
187
-
188
- @clean = @dont_clean ? nil : lambda{ File::unlink @path rescue nil }
189
- @dirname = File::dirname @path
190
- @basename = File::basename @path
191
- @thief = false
192
- @locked = false
193
-
194
- lock(&block) if block
195
- end
196
-
197
- def lock
198
- raise StackingLockError, "<#{ @path }> is locked!" if @locked
199
-
200
- sweep unless @dont_sweep
201
-
202
- ret = nil
203
-
204
- attempt do
205
- begin
206
- @sleep_cycle.reset
207
- create_tmplock do |f|
208
- begin
209
- Timeout::timeout(@timeout) do
210
- tmp_path = f.path
211
- tmp_stat = f.lstat
212
- n_retries = 0
213
- trace{ "attempting to lock <#{ @path }>..." }
214
- begin
215
- i = 0
216
- begin
217
- trace{ "polling attempt <#{ i }>..." }
218
- begin
219
- File::link tmp_path, @path
220
- rescue Errno::ENOENT
221
- try_again!
222
- end
223
- lock_stat = File::lstat @path
224
- raise StatLockError, "stat's do not agree" unless
225
- tmp_stat.rdev == lock_stat.rdev and tmp_stat.ino == lock_stat.ino
226
- trace{ "aquired lock <#{ @path }>" }
227
- @locked = true
228
- rescue => e
229
- i += 1
230
- unless i >= @poll_retries
231
- t = [rand(@poll_max_sleep), @poll_max_sleep].min
232
- trace{ "poll sleep <#{ t }>..." }
233
- sleep t
234
- retry
235
- end
236
- raise
237
- end
238
-
239
- rescue => e
240
- n_retries += 1
241
- trace{ "n_retries <#{ n_retries }>" }
242
- case validlock?
243
- when true
244
- raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
245
- @retries and n_retries >= @retries
246
- trace{ "found valid lock" }
247
- sleeptime = @sleep_cycle.next
248
- trace{ "sleep <#{ sleeptime }>..." }
249
- sleep sleeptime
250
- when false
251
- trace{ "found invalid lock and removing" }
252
- begin
253
- File::unlink @path
254
- @thief = true
255
- warn "<#{ @path }> stolen by <#{ Process.pid }> at <#{ timestamp }>"
256
- trace{ "i am a thief!" }
257
- rescue Errno::ENOENT
258
- end
259
- trace{ "suspending <#{ @suspend }>" }
260
- sleep @suspend
261
- when nil
262
- raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
263
- @retries and n_retries >= @retries
264
- end
265
- retry
266
- end # begin
267
- end # timeout
268
- rescue Timeout::Error
269
- raise TimeoutLockError, "surpassed timeout <#{ @timeout }>"
270
- end # begin
271
- end # create_tmplock
272
-
273
- if block_given?
274
- stolen = false
275
- refresher = (@refresh ? new_refresher : nil)
276
- begin
277
- begin
278
- ret = yield @path
279
- rescue StolenLockError
280
- stolen = true
281
- raise
282
- end
283
- ensure
284
- begin
285
- refresher.kill if refresher and refresher.status
286
- ensure
287
- unlock unless stolen
288
- end
289
- end
290
- else
291
- ObjectSpace.define_finalizer self, @clean if @clean
292
- ret = self
293
- end
294
- rescue Errno::ESTALE, Errno::EIO => e
295
- raise(NFSLockError, errmsg(e))
296
- end
297
- end
298
-
299
- return ret
300
- end
301
-
302
- def sweep
303
- begin
304
- glob = File::join(@dirname, ".*lck")
305
- paths = Dir[glob]
306
- paths.each do |path|
307
- begin
308
- basename = File::basename path
309
- pat = %r/^\s*\.([^_]+)_([^_]+)/o
310
- if pat.match(basename)
311
- host, pid = $1, $2
312
- else
313
- next
314
- end
315
- host.gsub!(%r/^\.+|\.+$/,'')
316
- quad = host.split %r/\./
317
- host = quad.first
318
- pat = %r/^\s*#{ host }/i
319
- if pat.match(HOSTNAME) and %r/^\s*\d+\s*$/.match(pid)
320
- unless alive?(pid)
321
- trace{ "process <#{ pid }> on <#{ host }> is no longer alive" }
322
- trace{ "sweeping <#{ path }>" }
323
- FileUtils::rm_f path
324
- else
325
- trace{ "process <#{ pid }> on <#{ host }> is still alive" }
326
- trace{ "ignoring <#{ path }>" }
327
- end
328
- else
329
- trace{ "ignoring <#{ path }> generated by <#{ host }>" }
330
- end
331
- rescue
332
- next
333
- end
334
- end
335
- rescue => e
336
- warn(errmsg(e))
337
- end
338
- end
339
-
340
- def alive?( pid )
341
- pid = Integer("#{ pid }")
342
- begin
343
- Process::kill 0, pid
344
- true
345
- rescue Errno::ESRCH
346
- false
347
- end
348
- end
349
-
350
- def unlock
351
- raise UnLockError, "<#{ @path }> is not locked!" unless @locked
352
- begin
353
- File::unlink @path
354
- rescue Errno::ENOENT
355
- raise StolenLockError, @path
356
- ensure
357
- @thief = false
358
- @locked = false
359
- ObjectSpace.undefine_finalizer self if @clean
360
- end
361
- end
362
-
363
- def new_refresher
364
- Thread::new(Thread::current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
365
- loop do
366
- begin
367
- touch path
368
- trace{"touched <#{ path }> @ <#{ Time.now.to_f }>"}
369
- unless dont_use_lock_id
370
- loaded = load_lock_id(IO.read(path))
371
- trace{"loaded <\n#{ loaded.inspect }\n>"}
372
- raise unless loaded == @lock_id
373
- end
374
- sleep refresh
375
- rescue Exception => e
376
- trace{errmsg e}
377
- thread.raise StolenLockError
378
- Thread::exit
379
- end
380
- end
381
- end
382
- end
383
-
384
- def validlock?
385
- if @max_age
386
- uncache @path rescue nil
387
- begin
388
- return((Time.now - File::stat(@path).mtime) < @max_age)
389
- rescue Errno::ENOENT
390
- return nil
391
- end
392
- else
393
- exist = File::exist?(@path)
394
- return(exist ? true : nil)
395
- end
396
- end
397
-
398
- def uncache( file )
399
- refresh = nil
400
- begin
401
- is_a_file = File === file
402
- path = (is_a_file ? file.path : file.to_s)
403
- stat = (is_a_file ? file.stat : File::stat(file.to_s))
404
- refresh = tmpnam(File::dirname(path))
405
- File::link path, refresh
406
- File::chmod stat.mode, path
407
- File::utime stat.atime, stat.mtime, path
408
- ensure
409
- begin
410
- File::unlink refresh if refresh
411
- rescue Errno::ENOENT
412
- end
413
- end
414
- end
415
-
416
- def create_tmplock
417
- tmplock = tmpnam @dirname
418
- begin
419
- create(tmplock) do |f|
420
- unless dont_use_lock_id
421
- @lock_id = gen_lock_id
422
- dumped = dump_lock_id
423
- trace{"lock_id <\n#{ @lock_id.inspect }\n>"}
424
- f.write dumped
425
- f.flush
426
- end
427
- yield f
428
- end
429
- ensure
430
- begin; File::unlink tmplock; rescue Errno::ENOENT; end if tmplock
431
- end
432
- end
433
-
434
- def gen_lock_id
435
- Hash[
436
- 'host' => "#{ HOSTNAME }",
437
- 'pid' => "#{ Process.pid }",
438
- 'ppid' => "#{ Process.ppid }",
439
- 'time' => timestamp
440
- ]
441
- end
442
-
443
- def timestamp
444
- time = Time.now
445
- usec = time.usec.to_s
446
- usec << '0' while usec.size < 6
447
- "#{ time.strftime('%Y-%m-%d %H:%M:%S') }.#{ usec }"
448
- end
449
-
450
- def dump_lock_id lock_id = @lock_id
451
- "host: %s\npid: %s\nppid: %s\ntime: %s\n" %
452
- lock_id.values_at('host','pid','ppid','time')
453
- end
454
-
455
- def load_lock_id( buf )
456
- lock_id = {}
457
- kv = %r/([^:]+):(.*)/o
458
- buf.each do |line|
459
- m = kv.match line
460
- k, v = m[1], m[2]
461
- next unless m and k and v
462
- lock_id[k.strip] = v.strip
463
- end
464
- lock_id
465
- end
466
-
467
- def tmpnam( dir, seed = File::basename($0) )
468
- pid = Process.pid
469
- time = Time.now
470
- sec = time.to_i
471
- usec = time.usec
472
- "%s%s.%s_%d_%s_%d_%d_%d.lck" %
473
- [dir, File::SEPARATOR, HOSTNAME, pid, seed, sec, usec, rand(sec)]
474
- end
475
-
476
- def create( path )
477
- umask = nil
478
- f = nil
479
- begin
480
- umask = File::umask 022
481
- f = open path, File::WRONLY|File::CREAT|File::EXCL, 0644
482
- ensure
483
- File::umask umask if umask
484
- end
485
- return(block_given? ? begin; yield f; ensure; f.close; end : f)
486
- end
487
-
488
- def touch( path )
489
- FileUtils.touch path
490
- end
491
-
492
- def getopt( key, default = nil )
493
- [ key, key.to_s, key.to_s.intern ].each do |k|
494
- return @opts[k] if @opts.has_key?(k)
495
- end
496
- return default
497
- end
498
-
499
- def to_str
500
- @path
501
- end
502
- alias to_s to_str
503
-
504
- def trace( s = nil )
505
- STDERR.puts((s ? s : yield)) if @debug
506
- end
507
-
508
- def errmsg( e )
509
- "%s (%s)\n%s\n" % [e.class, e.message, e.backtrace.join("\n")]
510
- end
511
-
512
- def attempt
513
- ret = nil
514
- loop{ break unless catch('attempt'){ ret = yield } == 'try_again' }
515
- ret
516
- end
517
-
518
- def try_again!
519
- throw 'attempt', 'try_again'
520
- end
521
- alias again! try_again!
522
-
523
- def give_up!
524
- throw 'attempt', 'give_up'
525
- end
526
- end # class Lockfile
527
- end # module Logging
528
-
529
- $__logging_lockfile__ = __FILE__
530
- end