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 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