Class: Logging::Appenders::RollingFile::Roller

Inherits:
Object
  • Object
show all
Defined in:
lib/logging/appenders/rolling_file.rb

Overview

Not intended for general consumption, but the Roller class is used internally by the RollingFile appender to roll dem log files according to the user’s desires.

Constant Summary collapse

RGXP =

The magic regex for finding user-defined roller patterns.

%r/{{(([^%]+)?.*?)}}/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, opts) ⇒ Roller

Create a new roller. See the RollingFile#initialize documentation for the list of options.

name - The appender name as a String opts - The options Hash

Raises:

  • (ArgumentError)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/logging/appenders/rolling_file.rb', line 261

def initialize( name, opts )
  # raise an error if a filename was not given
  @fn = opts.fetch(:filename, name)
  raise ArgumentError, 'no filename was given' if @fn.nil?

  if (m = RGXP.match @fn)
    @roll_by = ("#{m[2]}%d" == m[1]) ? :number : :date
  else
    age = opts.fetch(:age, nil)
    size = opts.fetch(:size, nil)

    @roll_by =
        case opts.fetch(:roll_by, nil)
        when 'number'; :number
        when 'date'; :date
        else
          (age && !size) ? :date : :number
        end

    ext = ::File.extname(@fn)
    bn  = ::File.join(::File.dirname(@fn), ::File.basename(@fn, ext))

    @fn = if :date == @roll_by && %w[daily weekly monthly].include?(age)
            "#{bn}{{.%Y%m%d}}#{ext}"
          elsif :date == @roll_by
            "#{bn}{{.%Y%m%d-%H%M%S}}#{ext}"
          else
            "#{bn}{{.%d}}#{ext}"
          end
  end

  @fn = ::File.expand_path(@fn)
  ::Logging::Appenders::File.assert_valid_logfile(filename)

  @roll = false
  @keep = opts.fetch(:keep, nil)
  @keep = Integer(keep) unless keep.nil?
end

Instance Attribute Details

#keepObject (readonly)

Returns the value of attribute keep.



300
301
302
# File 'lib/logging/appenders/rolling_file.rb', line 300

def keep
  @keep
end

#rollObject

Returns the value of attribute roll.



301
302
303
# File 'lib/logging/appenders/rolling_file.rb', line 301

def roll
  @roll
end

#roll_byObject (readonly)

Returns the value of attribute roll_by.



300
301
302
# File 'lib/logging/appenders/rolling_file.rb', line 300

def roll_by
  @roll_by
end

Instance Method Details

#copy_fileObject

Returns the file name to use as the temporary copy location. We are using copy-and-truncate semantics for rolling files so that the IO file descriptor remains valid during rolling.



313
314
315
316
317
# File 'lib/logging/appenders/rolling_file.rb', line 313

def copy_file
  return @copy_file if defined? @copy_file
  @copy_file = filename + '._copy_'
  @copy_file.freeze
end

#filenameObject

Returns the regular log file name without any roller text.



304
305
306
307
308
# File 'lib/logging/appenders/rolling_file.rb', line 304

def filename
  return @filename if defined? @filename
  @filename = (@fn =~ RGXP ?  @fn.sub(RGXP, '') : @fn.dup)
  @filename.freeze
end

#formatObject

Returns the format String used to generate rolled file names. Depending upon the ‘roll_by` type (:date or :number), this String will be processed by `sprintf` or `Time#strftime`.



331
332
333
334
335
336
# File 'lib/logging/appenders/rolling_file.rb', line 331

def format
  return @format if defined? @format
  m = RGXP.match @fn
  @format = @fn.sub(RGXP, m[1])
  @format.freeze
end

#globObject

Returns the glob pattern used to find rolled log files. We use this list for pruning older log files and doing the numbered rolling.



321
322
323
324
325
326
# File 'lib/logging/appenders/rolling_file.rb', line 321

def glob
  return @glob if defined? @glob
  m = RGXP.match @fn
  @glob = @fn.sub(RGXP, (m[2] ? "#{m[2]}*" : '*'))
  @glob.freeze
end

#roll_by_date(files) ⇒ Object

Roll the list of log files optionally removing older files. The “older files” are determined by the mtime of the log files. So touching log files or otherwise messing with them will screw this up.

files - The Array of filename Strings

Returns nil



394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/logging/appenders/rolling_file.rb', line 394

def roll_by_date( files )
  length = files.length

  if keep && length >= keep
    files = files.sort do |a,b|
              a = ::File.mtime(a)
              b = ::File.mtime(b)
              b <=> a
            end
    files.last(length-keep+1).each { |fn| ::File.delete fn }
  end

  # rename the copied log file
  ::File.rename(copy_file, Time.now.strftime(format))
end

#roll_by_number(files) ⇒ Object

Roll the list of log files optionally removing older files. The “older files” are determined by extracting the number from the log file name and order by the number.

files - The Array of filename Strings

Returns nil



363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/logging/appenders/rolling_file.rb', line 363

def roll_by_number( files )
  @number_rgxp ||= Regexp.new(@fn.sub(RGXP, '\2(\d+)'))

  # sort the files in reverse order based on their count number
  files = files.sort do |a,b|
            a = Integer(@number_rgxp.match(a)[1])
            b = Integer(@number_rgxp.match(b)[1])
            b <=> a
          end

  # for each file, roll its count number one higher
  files.each do |fn|
    cnt = Integer(@number_rgxp.match(fn)[1])
    if keep && cnt >= keep
      ::File.delete fn
      next
    end
    ::File.rename fn, sprintf(format, cnt+1)
  end

  # finally rename the copied log file
  ::File.rename(copy_file, sprintf(format, 1))
end

#roll_filesObject

Roll the log files. This method will collect the list of rolled files and then pass that list to either ‘roll_by_number` or `roll_by_date` to perform the actual rolling.

Returns nil



343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/logging/appenders/rolling_file.rb', line 343

def roll_files
  return unless roll && ::File.exist?(copy_file)

  files = Dir.glob(glob)
  files.delete copy_file

  self.send "roll_by_#{roll_by}", files

  nil
ensure
  self.roll = false
end