logger 1.6.2 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 513b3bfa57e4f617976d220ea3ab04b6a72f8ce0f3734b80a2de276b623d6b49
4
- data.tar.gz: 26bf01af278a060e23d1d80c83e46d474933d2af9425360223656f62c04c8df6
3
+ metadata.gz: c84ac2b70e090b47e48cc054906f75f21b26b3648dad0b363f54bba83f37e372
4
+ data.tar.gz: f7b0cbf4e55fd9c5831cb2500e21d27faa6bc02356ddc484d819a4ef806e4dee
5
5
  SHA512:
6
- metadata.gz: be737e542a0c9763d280be61f8fe045c72db441f4c25032c3ac332c926abf21c0e957dcdabe17f8cc403348636c71c1e0ee5d9220ea9108572b8d3457e1e00f9
7
- data.tar.gz: bcc5494d61bda582003ba814ceadce03476ca58cbecad391053b5d7b98538d3ee047bb2cce72efb80af54df0947ec82c9c993124dd91dbb1c421401b356b613f
6
+ metadata.gz: 1ffa55991e59e4dadd824e1bcf19b0deee701fc9512ba4dc97f15d45f7450bff12422266bac8b9d041222cb386bd5b70ffbb2379107a2c76cd5a4cdcf418a9cf
7
+ data.tar.gz: 03e58b69f2e3f0eae398506fc1aa417d70fe17c190efa2c4c2ceb558b90bcadee62e088929a774f3d01242c9e72486f365b9555a78419c8553140a3517f2dad3
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ BSDL
2
+ COPYING
3
+ README.md
4
+ lib/
data/.rdoc_options ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ main_page: README.md
3
+ title: Documentation for Logger
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Logger
2
+
3
+ Logger is a simple but powerful logging utility to output messages in your Ruby program.
4
+
5
+ Logger has the following features:
6
+
7
+ * Print messages to different levels such as `info` and `error`
8
+ * Auto-rolling of log files
9
+ * Setting the format of log messages
10
+ * Specifying a program name in conjunction with the message
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'logger'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install logger
27
+
28
+ ## Usage
29
+
30
+ ### Simple Example
31
+
32
+ ```ruby
33
+ require 'logger'
34
+
35
+ # Create a Logger that prints to STDOUT
36
+ log = Logger.new(STDOUT)
37
+ log.debug("Created Logger")
38
+
39
+ log.info("Program finished")
40
+
41
+ # Create a Logger that prints to STDERR
42
+ error_log = Logger.new(STDERR)
43
+ error_log = error_log.error("fatal error")
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run the following to install dependencies.
49
+
50
+ ```
51
+ $ bin/setup
52
+ ```
53
+
54
+ Then, run the tests as:
55
+
56
+ ```
57
+ $ rake test
58
+ ```
59
+
60
+ To install this gem onto your local machine, run
61
+
62
+ ```
63
+ $ rake install
64
+ ```
65
+
66
+ To release a new version, update the version number in `lib/logger/version.rb`, and then run
67
+
68
+ ```
69
+ $ rake release
70
+ ```
71
+
72
+ which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
73
+
74
+ ## Advanced Development
75
+
76
+ ### Run tests of a specific file
77
+
78
+ ```
79
+ $ ruby test/logger/test_logger.rb
80
+ ```
81
+
82
+ ### Run tests filtering test methods by a name
83
+
84
+ `--name` option is available as:
85
+
86
+ ```
87
+ $ ruby test/logger/test_logger.rb --name test_lshift
88
+ ```
89
+
90
+ ### Publish documents to GitHub Pages
91
+
92
+ ```
93
+ $ rake gh-pages
94
+ ```
95
+
96
+ Then, git commit and push the generated HTMLs onto `gh-pages` branch.
97
+
98
+ ## Contributing
99
+
100
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/logger.
101
+
102
+ ## License
103
+
104
+ The gem is available as open source under the terms of the [BSD-2-Clause](BSDL).
@@ -11,48 +11,27 @@ class Logger
11
11
  attr_reader :filename
12
12
  include MonitorMixin
13
13
 
14
- def initialize(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil, binmode: false, reraise_write_errors: [])
14
+ def initialize(
15
+ log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil,
16
+ binmode: false, reraise_write_errors: [], skip_header: false
17
+ )
15
18
  @dev = @filename = @shift_age = @shift_size = @shift_period_suffix = nil
16
19
  @binmode = binmode
17
20
  @reraise_write_errors = reraise_write_errors
21
+ @skip_header = skip_header
18
22
  mon_initialize
19
23
  set_dev(log)
20
- if @filename
21
- @shift_age = shift_age || 7
22
- @shift_size = shift_size || 1048576
23
- @shift_period_suffix = shift_period_suffix || '%Y%m%d'
24
-
25
- unless @shift_age.is_a?(Integer)
26
- base_time = @dev.respond_to?(:stat) ? @dev.stat.mtime : Time.now
27
- @next_rotate_time = next_rotate_time(base_time, @shift_age)
28
- end
29
- end
24
+ set_file(shift_age, shift_size, shift_period_suffix) if @filename
30
25
  end
31
26
 
32
27
  def write(message)
33
- begin
28
+ handle_write_errors("writing") do
34
29
  synchronize do
35
30
  if @shift_age and @dev.respond_to?(:stat)
36
- begin
37
- check_shift_log
38
- rescue *@reraise_write_errors
39
- raise
40
- rescue
41
- warn("log shifting failed. #{$!}")
42
- end
43
- end
44
- begin
45
- @dev.write(message)
46
- rescue *@reraise_write_errors
47
- raise
48
- rescue
49
- warn("log writing failed. #{$!}")
31
+ handle_write_errors("shifting") {check_shift_log}
50
32
  end
33
+ handle_write_errors("writing") {@dev.write(message)}
51
34
  end
52
- rescue *@reraise_write_errors
53
- raise
54
- rescue Exception => ignored
55
- warn("log writing failed. #{ignored}")
56
35
  end
57
36
  end
58
37
 
@@ -66,9 +45,10 @@ class Logger
66
45
  end
67
46
  end
68
47
 
69
- def reopen(log = nil)
48
+ def reopen(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil, binmode: nil)
70
49
  # reopen the same filename if no argument, do nothing for IO
71
50
  log ||= @filename if @filename
51
+ @binmode = binmode unless binmode.nil?
72
52
  if log
73
53
  synchronize do
74
54
  if @filename and @dev
@@ -76,6 +56,7 @@ class Logger
76
56
  @filename = nil
77
57
  end
78
58
  set_dev(log)
59
+ set_file(shift_age, shift_size, shift_period_suffix) if @filename
79
60
  end
80
61
  end
81
62
  self
@@ -83,6 +64,17 @@ class Logger
83
64
 
84
65
  private
85
66
 
67
+ # :stopdoc:
68
+
69
+ MODE = File::WRONLY | File::APPEND
70
+ # TruffleRuby < 24.2 does not have File::SHARE_DELETE
71
+ if File.const_defined? :SHARE_DELETE
72
+ MODE_TO_OPEN = MODE | File::SHARE_DELETE | File::BINARY
73
+ else
74
+ MODE_TO_OPEN = MODE | File::BINARY
75
+ end
76
+ MODE_TO_CREATE = MODE_TO_OPEN | File::CREAT | File::EXCL
77
+
86
78
  def set_dev(log)
87
79
  if log.respond_to?(:write) and log.respond_to?(:close)
88
80
  @dev = log
@@ -93,34 +85,72 @@ class Logger
93
85
  end
94
86
  else
95
87
  @dev = open_logfile(log)
96
- @dev.sync = true
97
- @dev.binmode if @binmode
98
88
  @filename = log
99
89
  end
100
90
  end
101
91
 
92
+ def set_file(shift_age, shift_size, shift_period_suffix)
93
+ @shift_age = shift_age || @shift_age || 7
94
+ @shift_size = shift_size || @shift_size || 1048576
95
+ @shift_period_suffix = shift_period_suffix || @shift_period_suffix || '%Y%m%d'
96
+
97
+ unless @shift_age.is_a?(Integer)
98
+ base_time = @dev.respond_to?(:stat) ? @dev.stat.mtime : Time.now
99
+ @next_rotate_time = next_rotate_time(base_time, @shift_age)
100
+ end
101
+ end
102
+
103
+ if MODE_TO_OPEN == MODE
104
+ def fixup_mode(dev)
105
+ dev
106
+ end
107
+ else
108
+ def fixup_mode(dev)
109
+ return dev if @binmode
110
+ dev.autoclose = false
111
+ old_dev = dev
112
+ dev = File.new(dev.fileno, mode: MODE, path: dev.path)
113
+ old_dev.close
114
+ PathAttr.set_path(dev, filename) if defined?(PathAttr)
115
+ dev
116
+ end
117
+ end
118
+
102
119
  def open_logfile(filename)
103
120
  begin
104
- File.open(filename, (File::WRONLY | File::APPEND))
121
+ dev = File.open(filename, MODE_TO_OPEN)
105
122
  rescue Errno::ENOENT
106
123
  create_logfile(filename)
124
+ else
125
+ dev = fixup_mode(dev)
126
+ dev.sync = true
127
+ dev.binmode if @binmode
128
+ dev
107
129
  end
108
130
  end
109
131
 
110
132
  def create_logfile(filename)
111
133
  begin
112
- logdev = File.open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
134
+ logdev = File.open(filename, MODE_TO_CREATE)
113
135
  logdev.flock(File::LOCK_EX)
136
+ logdev = fixup_mode(logdev)
114
137
  logdev.sync = true
115
138
  logdev.binmode if @binmode
116
- add_log_header(logdev)
139
+ add_log_header(logdev) unless @skip_header
117
140
  logdev.flock(File::LOCK_UN)
141
+ logdev
118
142
  rescue Errno::EEXIST
119
143
  # file is created by another process
120
- logdev = open_logfile(filename)
121
- logdev.sync = true
144
+ open_logfile(filename)
122
145
  end
123
- logdev
146
+ end
147
+
148
+ def handle_write_errors(mesg)
149
+ yield
150
+ rescue *@reraise_write_errors
151
+ raise
152
+ rescue
153
+ warn("log #{mesg} failed. #{$!}")
124
154
  end
125
155
 
126
156
  def add_log_header(file)
@@ -144,40 +174,34 @@ class Logger
144
174
  end
145
175
  end
146
176
 
147
- if /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
148
- def lock_shift_log
149
- yield
150
- end
151
- else
152
- def lock_shift_log
153
- retry_limit = 8
154
- retry_sleep = 0.1
155
- begin
156
- File.open(@filename, File::WRONLY | File::APPEND) do |lock|
157
- lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file
158
- if File.identical?(@filename, lock) and File.identical?(lock, @dev)
159
- yield # log shifting
160
- else
161
- # log shifted by another process (i-node before locking and i-node after locking are different)
162
- @dev.close rescue nil
163
- @dev = open_logfile(@filename)
164
- @dev.sync = true
165
- end
166
- end
167
- rescue Errno::ENOENT
168
- # @filename file would not exist right after #rename and before #create_logfile
169
- if retry_limit <= 0
170
- warn("log rotation inter-process lock failed. #{$!}")
177
+ def lock_shift_log
178
+ retry_limit = 8
179
+ retry_sleep = 0.1
180
+ begin
181
+ File.open(@filename, MODE_TO_OPEN) do |lock|
182
+ lock.flock(File::LOCK_EX) # inter-process locking. will be unlocked at closing file
183
+ if File.identical?(@filename, lock) and File.identical?(lock, @dev)
184
+ yield # log shifting
171
185
  else
172
- sleep retry_sleep
173
- retry_limit -= 1
174
- retry_sleep *= 2
175
- retry
186
+ # log shifted by another process (i-node before locking and i-node after locking are different)
187
+ @dev.close rescue nil
188
+ @dev = open_logfile(@filename)
176
189
  end
177
190
  end
178
- rescue
179
- warn("log rotation inter-process lock failed. #{$!}")
191
+ true
192
+ rescue Errno::ENOENT
193
+ # @filename file would not exist right after #rename and before #create_logfile
194
+ if retry_limit <= 0
195
+ warn("log rotation inter-process lock failed. #{$!}")
196
+ else
197
+ sleep retry_sleep
198
+ retry_limit -= 1
199
+ retry_sleep *= 2
200
+ retry
201
+ end
180
202
  end
203
+ rescue
204
+ warn("log rotation inter-process lock failed. #{$!}")
181
205
  end
182
206
 
183
207
  def shift_log_age
@@ -186,10 +210,7 @@ class Logger
186
210
  File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}")
187
211
  end
188
212
  end
189
- @dev.close rescue nil
190
- File.rename("#{@filename}", "#{@filename}.0")
191
- @dev = create_logfile(@filename)
192
- return true
213
+ shift_log_file("#{@filename}.0")
193
214
  end
194
215
 
195
216
  def shift_log_period(period_end)
@@ -205,10 +226,40 @@ class Logger
205
226
  break unless FileTest.exist?(age_file)
206
227
  end
207
228
  end
229
+ shift_log_file(age_file)
230
+ end
231
+
232
+ def shift_log_file(shifted)
233
+ stat = @dev.stat
208
234
  @dev.close rescue nil
209
- File.rename("#{@filename}", age_file)
235
+ File.rename(@filename, shifted)
210
236
  @dev = create_logfile(@filename)
237
+ mode, uid, gid = stat.mode, stat.uid, stat.gid
238
+ begin
239
+ @dev.chmod(mode) if mode
240
+ mode = nil
241
+ @dev.chown(uid, gid)
242
+ rescue Errno::EPERM
243
+ if mode
244
+ # failed to chmod, probably nothing can do more.
245
+ elsif uid
246
+ uid = nil
247
+ retry # to change gid only
248
+ end
249
+ end
211
250
  return true
212
251
  end
213
252
  end
214
253
  end
254
+
255
+ File.open(__FILE__) do |f|
256
+ File.new(f.fileno, autoclose: false, path: "").path
257
+ rescue IOError
258
+ module PathAttr # :nodoc:
259
+ attr_reader :path
260
+
261
+ def self.set_path(file, path)
262
+ file.extend(self).instance_variable_set(:@path, path)
263
+ end
264
+ end
265
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Logger
4
- VERSION = "1.6.2"
4
+ VERSION = "1.7.0"
5
5
  end
data/lib/logger.rb CHANGED
@@ -543,10 +543,20 @@ class Logger
543
543
  # - A string filepath: entries are to be written
544
544
  # to the file at that path; if the file at that path exists,
545
545
  # new entries are appended.
546
- # - An IO stream (typically +$stdout+, +$stderr+. or an open file):
547
- # entries are to be written to the given stream.
546
+ # - An IO stream (typically <tt>$stdout</tt>, <tt>$stderr</tt>. or
547
+ # an open file): entries are to be written to the given stream.
548
548
  # - +nil+ or +File::NULL+: no entries are to be written.
549
549
  #
550
+ # Argument +shift_age+ must be one of:
551
+ #
552
+ # - The number of log files to be in the rotation.
553
+ # See {Size-Based Rotation}[rdoc-ref:Logger@Size-Based+Rotation].
554
+ # - A string period indicator.
555
+ # See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
556
+ #
557
+ # Argument +shift_size+ is the maximum size (in bytes) of each log file.
558
+ # See {Size-Based Rotation}[rdoc-ref:Logger@Size-Based+Rotation].
559
+ #
550
560
  # Examples:
551
561
  #
552
562
  # Logger.new('t.log')
@@ -566,22 +576,29 @@ class Logger
566
576
  #
567
577
  # - +formatter+: sets the entry formatter; default is +nil+.
568
578
  # See {formatter=}[Logger.html#attribute-i-formatter].
579
+ #
569
580
  # - +datetime_format+: sets the format for entry timestamp;
570
581
  # default is +nil+.
571
582
  # See #datetime_format=.
583
+ #
572
584
  # - +binmode+: sets whether the logger writes in binary mode;
573
585
  # default is +false+.
586
+ #
574
587
  # - +shift_period_suffix+: sets the format for the filename suffix
575
588
  # for periodic log file rotation; default is <tt>'%Y%m%d'</tt>.
576
589
  # See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
590
+ #
577
591
  # - +reraise_write_errors+: An array of exception classes, which will
578
592
  # be reraised if there is an error when writing to the log device.
579
593
  # The default is to swallow all exceptions raised.
594
+ # - +skip_header+: If +true+, prevents the logger from writing a header
595
+ # when creating a new log file. The default is +false+, meaning
596
+ # the header will be written as usual.
580
597
  #
581
598
  def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
582
599
  progname: nil, formatter: nil, datetime_format: nil,
583
600
  binmode: false, shift_period_suffix: '%Y%m%d',
584
- reraise_write_errors: [])
601
+ reraise_write_errors: [], skip_header: false)
585
602
  self.level = level
586
603
  self.progname = progname
587
604
  @default_formatter = Formatter.new
@@ -594,7 +611,8 @@ class Logger
594
611
  shift_size: shift_size,
595
612
  shift_period_suffix: shift_period_suffix,
596
613
  binmode: binmode,
597
- reraise_write_errors: reraise_write_errors)
614
+ reraise_write_errors: reraise_write_errors,
615
+ skip_header: skip_header)
598
616
  end
599
617
  end
600
618
 
@@ -621,8 +639,9 @@ class Logger
621
639
  # # "E, [2022-05-12T14:21:27.596726 #22428] ERROR -- : one\n",
622
640
  # # "E, [2022-05-12T14:23:05.847241 #22428] ERROR -- : three\n"]
623
641
  #
624
- def reopen(logdev = nil)
625
- @logdev&.reopen(logdev)
642
+ def reopen(logdev = nil, shift_age = nil, shift_size = nil, shift_period_suffix: nil, binmode: nil)
643
+ @logdev&.reopen(logdev, shift_age: shift_age, shift_size: shift_size,
644
+ shift_period_suffix: shift_period_suffix, binmode: binmode)
626
645
  self
627
646
  end
628
647
 
@@ -748,6 +767,15 @@ private
748
767
 
749
768
  # Guarantee the existence of this ivar even when subclasses don't call the superclass constructor.
750
769
  def level_override
770
+ unless defined?(@level_override)
771
+ bad = self.class.instance_method(:initialize)
772
+ file, line = bad.source_location
773
+ Kernel.warn <<~";;;", uplevel: 2
774
+ Logger not initialized properly
775
+ #{file}:#{line}: info: #{bad.owner}\##{bad.name}: \
776
+ does not call super probably
777
+ ;;;
778
+ end
751
779
  @level_override ||= {}
752
780
  end
753
781
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  - SHIBATA Hiroshi
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-12-02 00:00:00.000000000 Z
12
+ date: 2025-03-27 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Provides a simple logging utility for outputting messages.
15
15
  email:
@@ -19,8 +19,11 @@ executables: []
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
+ - ".document"
23
+ - ".rdoc_options"
22
24
  - BSDL
23
25
  - COPYING
26
+ - README.md
24
27
  - lib/logger.rb
25
28
  - lib/logger/errors.rb
26
29
  - lib/logger/formatter.rb
@@ -28,13 +31,13 @@ files:
28
31
  - lib/logger/period.rb
29
32
  - lib/logger/severity.rb
30
33
  - lib/logger/version.rb
31
- - logger.gemspec
32
34
  homepage: https://github.com/ruby/logger
33
35
  licenses:
34
36
  - Ruby
35
37
  - BSD-2-Clause
36
- metadata: {}
37
- post_install_message:
38
+ metadata:
39
+ changelog_uri: https://github.com/ruby/logger/releases
40
+ post_install_message:
38
41
  rdoc_options: []
39
42
  require_paths:
40
43
  - lib
@@ -50,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
53
  version: '0'
51
54
  requirements: []
52
55
  rubygems_version: 3.5.11
53
- signing_key:
56
+ signing_key:
54
57
  specification_version: 4
55
58
  summary: Provides a simple logging utility for outputting messages.
56
59
  test_files: []
data/logger.gemspec DELETED
@@ -1,22 +0,0 @@
1
- begin
2
- require_relative "lib/logger/version"
3
- rescue LoadError # Fallback to load version file in ruby core repository
4
- require_relative "version"
5
- end
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = "logger"
9
- spec.version = Logger::VERSION
10
- spec.authors = ["Naotoshi Seo", "SHIBATA Hiroshi"]
11
- spec.email = ["sonots@gmail.com", "hsbt@ruby-lang.org"]
12
-
13
- spec.summary = %q{Provides a simple logging utility for outputting messages.}
14
- spec.description = %q{Provides a simple logging utility for outputting messages.}
15
- spec.homepage = "https://github.com/ruby/logger"
16
- spec.licenses = ["Ruby", "BSD-2-Clause"]
17
-
18
- spec.files = Dir.glob("lib/**/*.rb") + ["logger.gemspec", "BSDL", "COPYING"]
19
- spec.require_paths = ["lib"]
20
-
21
- spec.required_ruby_version = ">= 2.5.0"
22
- end