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.
- data/History.txt +9 -1
- data/Manifest.txt +3 -4
- data/Rakefile +8 -7
- data/lib/logging.rb +2 -2
- data/lib/logging/appender.rb +1 -1
- data/lib/logging/appenders/console.rb +1 -1
- data/lib/logging/appenders/email.rb +3 -2
- data/lib/logging/appenders/file.rb +1 -1
- data/lib/logging/appenders/growl.rb +1 -1
- data/lib/logging/appenders/io.rb +1 -1
- data/lib/logging/appenders/rolling_file.rb +3 -3
- data/lib/logging/appenders/syslog.rb +1 -1
- data/lib/logging/config/yaml_configurator.rb +1 -1
- data/lib/logging/layout.rb +1 -1
- data/lib/logging/layouts/basic.rb +1 -1
- data/lib/logging/layouts/pattern.rb +1 -1
- data/lib/logging/log_event.rb +1 -1
- data/lib/logging/logger.rb +59 -17
- data/lib/logging/repository.rb +15 -1
- data/lib/logging/root_logger.rb +6 -4
- data/lib/logging/utils.rb +1 -1
- data/tasks/ann.rake +20 -15
- data/tasks/bones.rake +7 -26
- data/tasks/gem.rake +49 -36
- data/tasks/git.rake +41 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +19 -10
- data/tasks/{doc.rake → rdoc.rake} +10 -7
- data/tasks/rubyforge.rake +12 -11
- data/tasks/setup.rb +122 -81
- data/tasks/test.rake +6 -6
- data/test/appenders/test_console.rb +1 -1
- data/test/appenders/test_email.rb +4 -2
- data/test/appenders/test_file.rb +1 -1
- data/test/appenders/test_growl.rb +1 -1
- data/test/appenders/test_io.rb +1 -1
- data/test/appenders/test_rolling_file.rb +1 -1
- data/test/appenders/test_syslog.rb +1 -1
- data/test/benchmark.rb +1 -1
- data/test/config/test_yaml_configurator.rb +1 -1
- data/test/layouts/test_basic.rb +1 -1
- data/test/layouts/test_pattern.rb +1 -1
- data/test/setup.rb +3 -8
- data/test/test_appender.rb +1 -1
- data/test/test_layout.rb +1 -1
- data/test/test_log_event.rb +1 -1
- data/test/test_logger.rb +88 -11
- data/test/test_logging.rb +1 -1
- data/test/test_repository.rb +5 -1
- data/test/test_root_logger.rb +1 -1
- data/test/test_utils.rb +1 -1
- metadata +15 -7
- data/lib/logging/stelan/lockfile.rb +0 -530
- data/tasks/annotations.rake +0 -22
- data/tasks/svn.rake +0 -44
data/tasks/test.rake
CHANGED
@@ -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.
|
10
|
-
else PROJ.
|
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.
|
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.
|
18
|
+
opts = PROJ.rcov.opts.dup << '-o' << PROJ.rcov.dir
|
19
19
|
opts = opts.join(' ')
|
20
|
-
files = if test(?f, PROJ.
|
21
|
-
else PROJ.
|
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
|
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
|
-
|
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)
|
data/test/appenders/test_file.rb
CHANGED
data/test/appenders/test_io.rb
CHANGED
data/test/benchmark.rb
CHANGED
data/test/layouts/test_basic.rb
CHANGED
data/test/setup.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
# $Id
|
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
|
data/test/test_appender.rb
CHANGED
data/test/test_layout.rb
CHANGED
data/test/test_log_event.rb
CHANGED
data/test/test_logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
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
|
data/test/test_logging.rb
CHANGED
data/test/test_repository.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id
|
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
|
data/test/test_root_logger.rb
CHANGED
data/test/test_utils.rb
CHANGED
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.
|
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
|
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.
|
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
|