process_safe_logger 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,12 @@
1
+ /*.gem
2
+ ~*
3
+ #*
4
+ *~
5
+ .bundle
6
+ Gemfile.lock
7
+ .rbenv-version
8
+ .ruby-version
9
+ vendor
10
+ doc/*
11
+ tmp/*
12
+ .yardoc
data/.pryrc ADDED
@@ -0,0 +1,3 @@
1
+ Pry.commands.alias_command 'c', 'continue'
2
+ Pry.commands.alias_command 's', 'step'
3
+ Pry.commands.alias_command 'n', 'next'
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ # - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+ gemfile:
7
+ - Gemfile
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.0.1
2
+
3
+ Initial Release
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+ source 'https://rubygems.org'
3
+
4
+ gemspec
5
+ gem 'parallel' # to run scripts in examples/, not required for this gem
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Same with Ruby
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Process Safe Logger [![Build Status](https://secure.travis-ci.org/sonots/process_safe_logger.png?branch=master)](http://travis-ci.org/sonots/process_safe_logger) [![Dependency Status](https://gemnasium.com/sonots/process_safe_logger.png)](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,9 @@
1
+ require 'process_safe_logger'
2
+ require 'parallel'
3
+
4
+ logger = ProcessSafeLogger.new("/tmp/test.log", 3, 1024 * 10)
5
+ Parallel.map(['a', 'b'], :in_processes => 2) do |letter|
6
+ 300000.times do
7
+ logger.info letter * 5000
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'process_safe_logger'
2
+ require 'parallel'
3
+
4
+ logger = ProcessSafeLogger.new("/tmp/test.log", 3, 1024 * 10)
5
+ Parallel.map(['a', 'b'], :in_threads => 2) do |letter|
6
+ 300000.times do
7
+ logger.info letter * 5000
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'logger'
2
+ require 'parallel'
3
+
4
+ logger = Logger.new("/tmp/test.log", 3, 1024 * 10)
5
+ Parallel.map(['a', 'b'], :in_processes => 2) do |letter|
6
+ 300000.times do
7
+ logger.info letter * 5000
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'logger'
2
+ require 'parallel'
3
+
4
+ logger = Logger.new("/tmp/test.log", 3, 1024 * 10)
5
+ Parallel.map(['a', 'b'], :in_threads => 2) do |letter|
6
+ 300000.times do
7
+ logger.info letter * 5000
8
+ end
9
+ end
@@ -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
@@ -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