logging 0.7.1 → 0.8.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 (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