chrono_logger 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4231d70e04d8cc920687cb1f31c11f6bba61cb8
4
- data.tar.gz: 7e3697d47afa57f7b22d99e169ce64cf85b1e588
3
+ metadata.gz: e4685d19b4094e975b08164b4041c82d20a0d843
4
+ data.tar.gz: 87f197078fead7232cc75b576a5eee36def4b0dd
5
5
  SHA512:
6
- metadata.gz: d9398a7c7046b9e171f499ee3a2dd8638ae964d660133b884c4bdf905d2c2f024fe4159130fc60f2b375bdd1d9727a631ddd1c8f903adac40582cf384f63be5e
7
- data.tar.gz: 6292f9aa38ea3f72b72d50c6ffe3cdea0fdaf443a36b6737da812e3e80fff042360d2e91753bbc66ef18838ca12ef29ac0524029440d478a4b7ff5e1941a6f7f
6
+ metadata.gz: 6c453b8b694c821b515c7b40a4b8641e2fad33295676b11894aa6e6efedc995dffc1dd91ff83b5ee0a07e554a2b7fa943e1f173e0f0f540bcb334ec45535d57c
7
+ data.tar.gz: 53db7768b5ecfbafded33375ccf583faed190bf2997c78cb25ebb2e41e0db00189d1737c039b254ea762b678b9b7a7501d94b74122962065b8fcbe733af676f2
data/.gitignore CHANGED
@@ -13,3 +13,4 @@
13
13
  *.a
14
14
  mkmf.log
15
15
  /vendor/bundle
16
+ .ruby-version
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ChronoLogger
2
2
 
3
- TODO: Write a gem description
3
+ A lock-free logger with timebased file rotation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,11 +20,22 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ Same interfaces ruby's stdlib `Logger` except for `new` method.
24
+
25
+ ```
26
+ require 'chrono_logger'
27
+
28
+ logger = ChronoLogger.new('development.%Y%m%d')
29
+
30
+ logger.error("Enjoy")
31
+ logger.warn("logging!")
32
+ logger.info("Enjoy")
33
+ logger.debug("programming!")
34
+ ```
24
35
 
25
36
  ## Contributing
26
37
 
27
- 1. Fork it ( https://github.com/[my-github-username]/chrono_logger/fork )
38
+ 1. Fork it ( https://github.com/ma2gedev/chrono_logger/fork )
28
39
  2. Create your feature branch (`git checkout -b my-new-feature`)
29
40
  3. Commit your changes (`git commit -am 'Add some feature'`)
30
41
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ require "rake/testtask"
3
3
 
4
4
  Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test"
6
+ t.test_files = Dir["test/**/test_*.rb"]
6
7
  end
7
8
 
8
9
  task :default => :test
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["takayuki.1229@gmail.com"]
11
11
  spec.summary = %q{A lock-free logger with timebased file rotation.}
12
12
  spec.description = %q{A lock-free logger with timebased file rotation.}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/ma2gedev/chrono_logger"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.7"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "test-unit"
24
24
  spec.add_development_dependency "pry"
25
25
  spec.add_development_dependency "delorean"
26
26
  spec.add_development_dependency "parallel"
@@ -1,5 +1,5 @@
1
1
  require 'logger'
2
2
 
3
3
  class ChronoLogger < Logger
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
data/lib/chrono_logger.rb CHANGED
@@ -30,7 +30,7 @@ class ChronoLogger < Logger
30
30
  end
31
31
 
32
32
  def write(message)
33
- if @dev.respond_to?(:stat)
33
+ if @pattern && @dev.respond_to?(:stat)
34
34
  begin
35
35
  check_shift_log
36
36
  rescue
@@ -61,10 +61,7 @@ class ChronoLogger < Logger
61
61
  def create_logfile(filename)
62
62
  begin
63
63
  logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
64
- logdev.flock(File::LOCK_EX)
65
64
  logdev.sync = true
66
- add_log_header(logdev)
67
- logdev.flock(File::LOCK_UN)
68
65
  rescue Errno::EEXIST
69
66
  # file is created by another process
70
67
  logdev = open_logfile(filename)
@@ -73,12 +70,6 @@ class ChronoLogger < Logger
73
70
  logdev
74
71
  end
75
72
 
76
- def add_log_header(file)
77
- file.write(
78
- "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
79
- ) if file.size == 0
80
- end
81
-
82
73
  def check_shift_log
83
74
  unless Time.now.strftime(@pattern) == @filename
84
75
  new_filename = Time.now.strftime(@pattern)
@@ -0,0 +1,153 @@
1
+ # coding: US-ASCII
2
+ require 'helper'
3
+ require 'tempfile'
4
+ require 'tmpdir'
5
+ require 'parallel'
6
+ require 'delorean'
7
+ require 'pry'
8
+
9
+ class TestLogDevice < Test::Unit::TestCase
10
+ class LogExcnRaiser
11
+ def write(*arg)
12
+ raise 'disk is full'
13
+ end
14
+
15
+ def close
16
+ end
17
+ end
18
+
19
+ def setup
20
+ @tempfile = Tempfile.new("logger")
21
+ @tempfile.close
22
+ @format = [@tempfile.path, '%Y%m%d'].join
23
+ @filename = Time.now.strftime(@format)
24
+ File.unlink(@tempfile.path)
25
+ end
26
+
27
+ def teardown
28
+ @tempfile.close(true)
29
+ end
30
+
31
+ def d(format, opt = {})
32
+ ChronoLogger::TimeBasedLogDevice.new(format, opt)
33
+ end
34
+
35
+ def test_initialize
36
+ logdev = d(STDERR)
37
+ assert_equal(STDERR, logdev.dev)
38
+ assert_nil(logdev.filename)
39
+ assert_raises(TypeError) do
40
+ d(nil)
41
+ end
42
+ #
43
+ logdev = d(@format)
44
+ begin
45
+ assert(File.exist?(@filename))
46
+ assert(logdev.dev.sync)
47
+ assert_equal(@filename, logdev.filename)
48
+ logdev.write('hello')
49
+ ensure
50
+ logdev.close
51
+ end
52
+ # create logfile whitch is already exist.
53
+ logdev = d(@format)
54
+ begin
55
+ logdev.write('world')
56
+ logfile = File.read(@filename)
57
+ assert_equal(1, logfile.split(/\n/).size)
58
+ assert_match(/^helloworld$/, logfile)
59
+ ensure
60
+ logdev.close
61
+ end
62
+ end
63
+
64
+ def test_write
65
+ r, w = IO.pipe
66
+ logdev = d(w)
67
+ logdev.write("msg2\n\n")
68
+ IO.select([r], nil, nil, 0.1)
69
+ w.close
70
+ msg = r.read
71
+ r.close
72
+ assert_equal("msg2\n\n", msg)
73
+ #
74
+ logdev = d(LogExcnRaiser.new)
75
+ class << (stderr = '')
76
+ alias write <<
77
+ end
78
+ $stderr, stderr = stderr, $stderr
79
+ begin
80
+ assert_nothing_raised do
81
+ logdev.write('hello')
82
+ end
83
+ ensure
84
+ logdev.close
85
+ $stderr, stderr = stderr, $stderr
86
+ end
87
+ assert_equal "log writing failed. disk is full\n", stderr
88
+ end
89
+
90
+ def test_close
91
+ r, w = IO.pipe
92
+ logdev = d(w)
93
+ logdev.write("msg2\n\n")
94
+ IO.select([r], nil, nil, 0.1)
95
+ assert(!w.closed?)
96
+ logdev.close
97
+ assert(w.closed?)
98
+ r.close
99
+ end
100
+
101
+ def test_shifting_age_in_multiprocess
102
+ old_log = [@tempfile.path, '20150122'].join
103
+ new_log = [@tempfile.path, '20150123'].join
104
+ $stderr, stderr = StringIO.new, $stderr
105
+ begin
106
+ Delorean.time_travel_to '2015-01-22 23:59:59'
107
+ logger = ChronoLogger.new(@format)
108
+ Parallel.map(['a', 'b'], :in_processes => 2) do |letter|
109
+ 5000.times do
110
+ logger.info letter * 5000
111
+ end
112
+ end
113
+ assert_no_match(/log shifting failed/, $stderr.string)
114
+ assert_no_match(/log writing failed/, $stderr.string)
115
+ assert { File.exist?(old_log) }
116
+ assert { File.exist?(new_log) }
117
+ ensure
118
+ $stderr, stderr = stderr, $stderr
119
+ Delorean.back_to_the_present
120
+ File.unlink(old_log)
121
+ File.unlink(new_log)
122
+ end
123
+ end
124
+
125
+ def test_shifting_midnight
126
+ Dir.mktmpdir do |tmpdir|
127
+ log = "log20140102"
128
+ old_log = File.join(tmpdir, log)
129
+ begin
130
+ File.open(old_log, "w") {}
131
+ File.utime(*[Time.mktime(2014, 1, 1, 23, 59, 59)]*2, old_log)
132
+
133
+ Delorean.time_travel_to '2014-01-02 23:59:59'
134
+ dev = ChronoLogger::TimeBasedLogDevice.new(File.join(tmpdir, "log%Y%m%d"))
135
+ dev.write("#{Time.now} hello-1\n")
136
+
137
+ Delorean.time_travel_to '2014-01-03 00:00:01'
138
+ dev.write("#{Time.now} hello-2\n")
139
+ ensure
140
+ Delorean.back_to_the_present
141
+ dev.close
142
+ end
143
+
144
+ cont = File.read(old_log)
145
+ assert_match(/hello-1/, cont)
146
+ assert_not_match(/hello-2/, cont)
147
+ new_log = File.join(tmpdir, "log20140103")
148
+ bug = '[GH-539]'
149
+ assert { File.exist?(new_log) }
150
+ assert_match(/hello-2/, File.read(new_log), bug)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,243 @@
1
+ # coding: US-ASCII
2
+ require 'helper'
3
+ require 'tempfile'
4
+
5
+ class TestLogger < Test::Unit::TestCase
6
+ include ChronoLogger::Severity
7
+
8
+ def setup
9
+ @logger = ChronoLogger.new(nil)
10
+ end
11
+
12
+ class Log
13
+ attr_reader :label, :datetime, :pid, :severity, :progname, :msg
14
+ def initialize(line)
15
+ /\A(\w+), \[([^#]*)#(\d+)\]\s+(\w+) -- (\w*): ([\x0-\xff]*)/ =~ line
16
+ @label, @datetime, @pid, @severity, @progname, @msg = $1, $2, $3, $4, $5, $6
17
+ end
18
+ end
19
+
20
+ def log_add(logger, severity, msg, progname = nil, &block)
21
+ log(logger, :add, severity, msg, progname, &block)
22
+ end
23
+
24
+ def log(logger, msg_id, *arg, &block)
25
+ Log.new(log_raw(logger, msg_id, *arg, &block))
26
+ end
27
+
28
+ def log_raw(logger, msg_id, *arg, &block)
29
+ Tempfile.create(File.basename(__FILE__) + '.log') {|logdev|
30
+ logger.instance_eval { @logdev = ChronoLogger::TimeBasedLogDevice.new(logdev) }
31
+ logger.__send__(msg_id, *arg, &block)
32
+ logdev.rewind
33
+ logdev.read
34
+ }
35
+ end
36
+
37
+ def test_level
38
+ @logger.level = UNKNOWN
39
+ assert_equal(UNKNOWN, @logger.level)
40
+ @logger.level = INFO
41
+ assert_equal(INFO, @logger.level)
42
+ @logger.sev_threshold = ERROR
43
+ assert_equal(ERROR, @logger.sev_threshold)
44
+ @logger.sev_threshold = WARN
45
+ assert_equal(WARN, @logger.sev_threshold)
46
+ assert_equal(WARN, @logger.level)
47
+
48
+ @logger.level = DEBUG
49
+ assert(@logger.debug?)
50
+ assert(@logger.info?)
51
+ @logger.level = INFO
52
+ assert(!@logger.debug?)
53
+ assert(@logger.info?)
54
+ assert(@logger.warn?)
55
+ @logger.level = WARN
56
+ assert(!@logger.info?)
57
+ assert(@logger.warn?)
58
+ assert(@logger.error?)
59
+ @logger.level = ERROR
60
+ assert(!@logger.warn?)
61
+ assert(@logger.error?)
62
+ assert(@logger.fatal?)
63
+ @logger.level = FATAL
64
+ assert(!@logger.error?)
65
+ assert(@logger.fatal?)
66
+ @logger.level = UNKNOWN
67
+ assert(!@logger.error?)
68
+ assert(!@logger.fatal?)
69
+ end
70
+
71
+ def test_progname
72
+ assert_nil(@logger.progname)
73
+ @logger.progname = "name"
74
+ assert_equal("name", @logger.progname)
75
+ end
76
+
77
+ def test_datetime_format
78
+ dummy = STDERR
79
+ logger = ChronoLogger.new(dummy)
80
+ log = log_add(logger, INFO, "foo")
81
+ assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+ $/, log.datetime)
82
+ logger.datetime_format = "%d%b%Y@%H:%M:%S"
83
+ log = log_add(logger, INFO, "foo")
84
+ assert_match(/^\d\d\w\w\w\d\d\d\d@\d\d:\d\d:\d\d$/, log.datetime)
85
+ logger.datetime_format = ""
86
+ log = log_add(logger, INFO, "foo")
87
+ assert_match(/^$/, log.datetime)
88
+ end
89
+
90
+ def test_formatter
91
+ dummy = STDERR
92
+ logger = ChronoLogger.new(dummy)
93
+ # default
94
+ log = log(logger, :info, "foo")
95
+ assert_equal("foo\n", log.msg)
96
+ # config
97
+ logger.formatter = proc { |severity, timestamp, progname, msg|
98
+ "#{severity}:#{msg}\n\n"
99
+ }
100
+ line = log_raw(logger, :info, "foo")
101
+ assert_equal("INFO:foo\n\n", line)
102
+ # recover
103
+ logger.formatter = nil
104
+ log = log(logger, :info, "foo")
105
+ assert_equal("foo\n", log.msg)
106
+ # again
107
+ o = Object.new
108
+ def o.call(severity, timestamp, progname, msg)
109
+ "<<#{severity}-#{msg}>>\n"
110
+ end
111
+ logger.formatter = o
112
+ line = log_raw(logger, :info, "foo")
113
+ assert_equal("<""<INFO-foo>>\n", line)
114
+ end
115
+
116
+ def test_initialize
117
+ logger = ChronoLogger.new(STDERR)
118
+ assert_nil(logger.progname)
119
+ assert_equal(DEBUG, logger.level)
120
+ assert_nil(logger.datetime_format)
121
+ end
122
+
123
+ def test_add
124
+ logger = ChronoLogger.new(nil)
125
+ logger.progname = "my_progname"
126
+ assert(logger.add(INFO))
127
+ log = log_add(logger, nil, "msg")
128
+ assert_equal("ANY", log.severity)
129
+ assert_equal("my_progname", log.progname)
130
+ logger.level = WARN
131
+ assert(logger.log(INFO))
132
+ assert_nil(log_add(logger, INFO, "msg").msg)
133
+ log = log_add(logger, WARN, nil) { "msg" }
134
+ assert_equal("msg\n", log.msg)
135
+ log = log_add(logger, WARN, "") { "msg" }
136
+ assert_equal("\n", log.msg)
137
+ assert_equal("my_progname", log.progname)
138
+ log = log_add(logger, WARN, nil, "progname?")
139
+ assert_equal("progname?\n", log.msg)
140
+ assert_equal("my_progname", log.progname)
141
+ end
142
+
143
+ def test_level_log
144
+ logger = ChronoLogger.new(nil)
145
+ logger.progname = "my_progname"
146
+ log = log(logger, :debug, "custom_progname") { "msg" }
147
+ assert_equal("msg\n", log.msg)
148
+ assert_equal("custom_progname", log.progname)
149
+ assert_equal("DEBUG", log.severity)
150
+ assert_equal("D", log.label)
151
+ #
152
+ log = log(logger, :debug) { "msg_block" }
153
+ assert_equal("msg_block\n", log.msg)
154
+ assert_equal("my_progname", log.progname)
155
+ log = log(logger, :debug, "msg_inline")
156
+ assert_equal("msg_inline\n", log.msg)
157
+ assert_equal("my_progname", log.progname)
158
+ #
159
+ log = log(logger, :info, "custom_progname") { "msg" }
160
+ assert_equal("msg\n", log.msg)
161
+ assert_equal("custom_progname", log.progname)
162
+ assert_equal("INFO", log.severity)
163
+ assert_equal("I", log.label)
164
+ #
165
+ log = log(logger, :warn, "custom_progname") { "msg" }
166
+ assert_equal("msg\n", log.msg)
167
+ assert_equal("custom_progname", log.progname)
168
+ assert_equal("WARN", log.severity)
169
+ assert_equal("W", log.label)
170
+ #
171
+ log = log(logger, :error, "custom_progname") { "msg" }
172
+ assert_equal("msg\n", log.msg)
173
+ assert_equal("custom_progname", log.progname)
174
+ assert_equal("ERROR", log.severity)
175
+ assert_equal("E", log.label)
176
+ #
177
+ log = log(logger, :fatal, "custom_progname") { "msg" }
178
+ assert_equal("msg\n", log.msg)
179
+ assert_equal("custom_progname", log.progname)
180
+ assert_equal("FATAL", log.severity)
181
+ assert_equal("F", log.label)
182
+ #
183
+ log = log(logger, :unknown, "custom_progname") { "msg" }
184
+ assert_equal("msg\n", log.msg)
185
+ assert_equal("custom_progname", log.progname)
186
+ assert_equal("ANY", log.severity)
187
+ assert_equal("A", log.label)
188
+ end
189
+
190
+ def test_close
191
+ r, w = IO.pipe
192
+ assert(!w.closed?)
193
+ logger = ChronoLogger.new(w)
194
+ logger.close
195
+ assert(w.closed?)
196
+ r.close
197
+ end
198
+
199
+ class MyError < StandardError
200
+ end
201
+
202
+ class MyMsg
203
+ def inspect
204
+ "my_msg"
205
+ end
206
+ end
207
+
208
+ def test_format
209
+ logger = ChronoLogger.new(nil)
210
+ log = log_add(logger, INFO, "msg\n")
211
+ assert_equal("msg\n\n", log.msg)
212
+ begin
213
+ raise MyError.new("excn")
214
+ rescue MyError => e
215
+ log = log_add(logger, INFO, e)
216
+ assert_match(/^excn \(TestLogger::MyError\)/, log.msg)
217
+ # expects backtrace is dumped across multi lines. 10 might be changed.
218
+ assert(log.msg.split(/\n/).size >= 10)
219
+ end
220
+ log = log_add(logger, INFO, MyMsg.new)
221
+ assert_equal("my_msg\n", log.msg)
222
+ end
223
+
224
+ def test_lshift
225
+ r, w = IO.pipe
226
+ logger = ChronoLogger.new(w)
227
+ logger << "msg"
228
+ read_ready, = IO.select([r], nil, nil, 0.1)
229
+ w.close
230
+ msg = r.read
231
+ r.close
232
+ assert_equal("msg", msg)
233
+ #
234
+ r, w = IO.pipe
235
+ logger = ChronoLogger.new(w)
236
+ logger << "msg2\n\n"
237
+ read_ready, = IO.select([r], nil, nil, 0.1)
238
+ w.close
239
+ msg = r.read
240
+ r.close
241
+ assert_equal("msg2\n\n", msg)
242
+ end
243
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+
3
+ class TestLoggerSeverity < Test::Unit::TestCase
4
+ def test_enum
5
+ logger_levels = ChronoLogger.constants
6
+ levels = ["WARN", "UNKNOWN", "INFO", "FATAL", "DEBUG", "ERROR"]
7
+ ChronoLogger::Severity.constants.each do |level|
8
+ assert(levels.include?(level.to_s))
9
+ assert(logger_levels.include?(level))
10
+ end
11
+ assert_equal(levels.size, ChronoLogger::Severity.constants.size)
12
+ end
13
+ end
@@ -1,4 +1,4 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'chrono_logger'
3
3
 
4
- require 'minitest/autorun'
4
+ require 'test/unit'
@@ -1,11 +1,7 @@
1
- require 'minitest_helper'
1
+ require 'helper'
2
2
 
3
- class TestChronoLogger < MiniTest::Unit::TestCase
3
+ class TestChronoLogger < Test::Unit::TestCase
4
4
  def test_that_it_has_a_version_number
5
5
  refute_nil ::ChronoLogger::VERSION
6
6
  end
7
-
8
- def test_it_does_something_useful
9
- assert false
10
- end
11
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chrono_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takayuki Matsubara
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-21 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: minitest
42
+ name: test-unit
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -110,9 +110,12 @@ files:
110
110
  - chrono_logger.gemspec
111
111
  - lib/chrono_logger.rb
112
112
  - lib/chrono_logger/version.rb
113
- - test/minitest_helper.rb
113
+ - test/from_ruby_repo/test_logdevice.rb
114
+ - test/from_ruby_repo/test_logger.rb
115
+ - test/from_ruby_repo/test_severity.rb
116
+ - test/helper.rb
114
117
  - test/test_chrono_logger.rb
115
- homepage: ''
118
+ homepage: https://github.com/ma2gedev/chrono_logger
116
119
  licenses:
117
120
  - MIT
118
121
  metadata: {}
@@ -137,5 +140,8 @@ signing_key:
137
140
  specification_version: 4
138
141
  summary: A lock-free logger with timebased file rotation.
139
142
  test_files:
140
- - test/minitest_helper.rb
143
+ - test/from_ruby_repo/test_logdevice.rb
144
+ - test/from_ruby_repo/test_logger.rb
145
+ - test/from_ruby_repo/test_severity.rb
146
+ - test/helper.rb
141
147
  - test/test_chrono_logger.rb