process_safe_logger 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.pryrc +3 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +5 -0
- data/LICENSE +1 -0
- data/README.md +43 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/examples/process_safe_logger_in_processes.rb +9 -0
- data/examples/process_safe_logger_in_threads.rb +9 -0
- data/examples/ruby_logger_in_processes.rb +9 -0
- data/examples/ruby_logger_in_threads.rb +9 -0
- data/lib/process_safe_logger.rb +105 -0
- data/process_safe_logger.gemspec +25 -0
- data/spec/spec_helper.rb +14 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 85efddfa248dd513471e22b9f6bcd61f10cc831c
|
4
|
+
data.tar.gz: acebb65714e21fd05b62ce88fef2deb907aef1ed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 68ee62bad0557f9fab0f3667e3349efb27e2eebcd0d95cbc586bccc958f3d2f54968d7c50a65af67efe6d28fb32c4a31c7c8b48a2ab311e1802860d07a526f30
|
7
|
+
data.tar.gz: 3e83568c498d45670e7583f2aa3bcec9913fd09948408e7e4942d55121009199e886edff011c8edfa0abe0e0fe8a44f44a3e4ac866f586b61284e8aa7fbbf40d
|
data/.gitignore
ADDED
data/.pryrc
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Same with Ruby
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Process Safe Logger [](http://travis-ci.org/sonots/process_safe_logger) [](https://gemnasium.com/sonots/process_safe_logger)
|
2
|
+
|
3
|
+
testing ruby: 1.9.2, 1.9.3, 2.0.0;
|
4
|
+
|
5
|
+
## About Process Safe Logger
|
6
|
+
|
7
|
+
Process Safe Logger supports log rotations in multi-processes *safely*.
|
8
|
+
|
9
|
+
## Objective
|
10
|
+
|
11
|
+
Ruby's standard Logger class originally have had a problem that it's log rotation function does not work safely in multi process environment. This gem fixes the problem.
|
12
|
+
|
13
|
+
The patch is already pull requested to the [githb.com:ruby/ruby](https://github.com/ruby/ruby/pull/428) and will be released with ruby 2.1.0.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
gem install process_safe_logger
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'process_safe_logger'
|
23
|
+
logger = ProcessSafeLogger.new('logfile.log', 3, 1024)
|
24
|
+
```
|
25
|
+
|
26
|
+
Option parameters are same with Ruby's Logger. See [docs.ruby-lang.org:Logger](http://docs.ruby-lang.org/en/2.0.0/Logger.html).
|
27
|
+
|
28
|
+
## Further Reading
|
29
|
+
|
30
|
+
1. [sonots:blog : RubyのLoggerはスレッドセーフ(&プロセスセーフ)かどうか調べてみた](http://blog.livedoor.jp/sonots/archives/32645828.html) (Japanese)
|
31
|
+
2. [Inter-process locking for log rotation by sonots · Pull Request #428 · ruby/ruby](https://github.com/ruby/ruby/pull/428)
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create new [Pull Request](../../pull/new/master)
|
40
|
+
|
41
|
+
## License
|
42
|
+
|
43
|
+
Same with ruby.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
desc 'Open an irb session preloaded with the gem library'
|
12
|
+
task :console do
|
13
|
+
sh 'irb -rubygems -I lib -r process_safe_logger.rb'
|
14
|
+
end
|
15
|
+
task :c => :console
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
if ::Logger::LogDevice.private_method_defined?(:lock_shift_log)
|
4
|
+
class ProcessSafeLogger < ::Logger
|
5
|
+
end
|
6
|
+
else
|
7
|
+
class ProcessSafeLogger < ::Logger
|
8
|
+
# Override to use ::ProcessSafeLogger::LogDevice
|
9
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576)
|
10
|
+
super(nil, shift_age, shift_size)
|
11
|
+
if logdev
|
12
|
+
@logdev = ::ProcessSafeLogger::LogDevice.new(logdev, :shift_age => shift_age,
|
13
|
+
:shift_size => shift_size)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class LogDevice < ::Logger::LogDevice
|
18
|
+
# Override as my patch
|
19
|
+
def open_logfile(filename)
|
20
|
+
begin
|
21
|
+
open(filename, (File::WRONLY | File::APPEND))
|
22
|
+
rescue Errno::ENOENT
|
23
|
+
create_logfile(filename)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Override as my patch
|
28
|
+
def create_logfile(filename)
|
29
|
+
begin
|
30
|
+
logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
|
31
|
+
logdev.flock(File::LOCK_EX)
|
32
|
+
logdev.sync = true
|
33
|
+
add_log_header(logdev)
|
34
|
+
logdev.flock(File::LOCK_UN)
|
35
|
+
rescue Errno::EEXIST
|
36
|
+
# file is created by another process
|
37
|
+
logdev = open_logfile(filename)
|
38
|
+
logdev.sync = true
|
39
|
+
end
|
40
|
+
logdev
|
41
|
+
end
|
42
|
+
|
43
|
+
# Override as my patch
|
44
|
+
def add_log_header(file)
|
45
|
+
file.write(
|
46
|
+
"# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
|
47
|
+
) if file.size == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
# Override as my patch
|
51
|
+
def check_shift_log
|
52
|
+
if @shift_age.is_a?(Integer)
|
53
|
+
# Note: always returns false if '0'.
|
54
|
+
if @filename && (@shift_age > 0) && (@dev.stat.size > @shift_size)
|
55
|
+
lock_shift_log { shift_log_age }
|
56
|
+
end
|
57
|
+
else
|
58
|
+
now = Time.now
|
59
|
+
period_end = previous_period_end(now)
|
60
|
+
if @dev.stat.mtime <= period_end
|
61
|
+
lock_shift_log { shift_log_period(period_end) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Defien as my patch
|
67
|
+
if /mswin|mingw/ =~ RUBY_PLATFORM
|
68
|
+
def lock_shift_log
|
69
|
+
yield
|
70
|
+
end
|
71
|
+
else
|
72
|
+
def lock_shift_log
|
73
|
+
retry_limit = 8
|
74
|
+
retry_sleep = 0.1
|
75
|
+
begin
|
76
|
+
File.open(@filename, File::WRONLY | File::APPEND) do |lock|
|
77
|
+
lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file
|
78
|
+
ino = lock.stat.ino
|
79
|
+
if ino == File.stat(@filename).ino
|
80
|
+
yield # log shifting
|
81
|
+
else
|
82
|
+
# log shifted by another process (i-node before locking and i-node after locking are different)
|
83
|
+
@dev.close rescue nil
|
84
|
+
@dev = open_logfile(@filename)
|
85
|
+
@dev.sync = true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
rescue Errno::ENOENT
|
89
|
+
# @filename file would not exist right after #rename and before #create_logfile
|
90
|
+
if retry_limit <= 0
|
91
|
+
warn("log rotation inter-process lock failed. #{$!}")
|
92
|
+
else
|
93
|
+
sleep retry_sleep
|
94
|
+
retry_limit -= 1
|
95
|
+
retry_sleep *= 2
|
96
|
+
retry
|
97
|
+
end
|
98
|
+
end
|
99
|
+
rescue
|
100
|
+
warn("log rotation inter-process lock failed. #{$!}")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#! /usr/bin/env gem build
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'process_safe_logger'
|
6
|
+
gem.version = File.read(File.expand_path('VERSION', File.dirname(__FILE__))).chomp
|
7
|
+
gem.authors = ["Naotoshi Seo"]
|
8
|
+
gem.email = ["sonots@gmail.com"]
|
9
|
+
gem.homepage = "https://github.com/sonots/process_safe_logger"
|
10
|
+
gem.summary = "Process-safe Logger supports log rotations in multi-processes safely"
|
11
|
+
gem.description = gem.summary
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
|
18
|
+
# for testing
|
19
|
+
gem.add_development_dependency "rake"
|
20
|
+
gem.add_development_dependency "rspec", "~> 2.11"
|
21
|
+
|
22
|
+
# for debug
|
23
|
+
gem.add_development_dependency "pry"
|
24
|
+
gem.add_development_dependency "pry-nav"
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require "pry"
|
5
|
+
require 'process_safe_logger'
|
6
|
+
|
7
|
+
ROOT = File.dirname(__FILE__)
|
8
|
+
Dir[File.expand_path("support/**/*.rb", ROOT)].each {|f| require f }
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
end
|
14
|
+
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: process_safe_logger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Naotoshi Seo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-nav
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Process-safe Logger supports log rotations in multi-processes safely
|
70
|
+
email:
|
71
|
+
- sonots@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .pryrc
|
78
|
+
- .rspec
|
79
|
+
- .travis.yml
|
80
|
+
- CHANGELOG.md
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- VERSION
|
86
|
+
- examples/process_safe_logger_in_processes.rb
|
87
|
+
- examples/process_safe_logger_in_threads.rb
|
88
|
+
- examples/ruby_logger_in_processes.rb
|
89
|
+
- examples/ruby_logger_in_threads.rb
|
90
|
+
- lib/process_safe_logger.rb
|
91
|
+
- process_safe_logger.gemspec
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
homepage: https://github.com/sonots/process_safe_logger
|
94
|
+
licenses: []
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.0.3
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Process-safe Logger supports log rotations in multi-processes safely
|
116
|
+
test_files:
|
117
|
+
- spec/spec_helper.rb
|