Class: FileSeries

Inherits:
Object
  • Object
show all
Defined in:
lib/file_series.rb

Overview

Writes to this logger will be directed to new files at a configurable frequency.

=> logger = FileSeries.new('.', :prefix=>'test', :rotate_every=>60)
=> logger.write("some message\n")

This will create a file like ‘test-1342477810-60.log’. A new file will be created every 60 seconds. You don’t need to do anything except keep calling logger.write().

Files are created as needed, so you won’t end up with lots of 0-length files. If you do see a recent 0-length file, it’s probably due to your OS buffering writes to the file.

Other configuration options:

:binary - boolean. If true, log files are opened in binary mode. (Useful for Marshal.dump)
:separator - string. Appended to each write. Defaults to \n. Use something else in :binary mode.

Constant Summary collapse

DEFAULT_DIR =
'.'
DEFAULT_PREFIX =
'log'
DEFAULT_FREQ =
60
DEFAULT_SEPARATOR =
"\n"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ FileSeries

Returns a new instance of FileSeries.



32
33
34
35
36
37
38
39
40
41
# File 'lib/file_series.rb', line 32

def initialize(options={})
  @dir = options[:dir] || DEFAULT_DIR
  @file = nil
  @current_ts = nil
  @filename_prefix = options[:prefix] || DEFAULT_PREFIX
  @rotate_freq = options[:rotate_every] || DEFAULT_FREQ #seconds
  @binary_mode = options[:binary]
  @separator = options[:separator] || DEFAULT_SEPARATOR
  @sync = options[:sync] || false
end

Instance Attribute Details

#current_tsObject

Returns the value of attribute current_ts.



30
31
32
# File 'lib/file_series.rb', line 30

def current_ts
  @current_ts
end

#dirObject

Returns the value of attribute dir.



28
29
30
# File 'lib/file_series.rb', line 28

def dir
  @dir
end

#fileObject

Returns the value of attribute file.



29
30
31
# File 'lib/file_series.rb', line 29

def file
  @file
end

#separatorObject

Returns the value of attribute separator.



27
28
29
# File 'lib/file_series.rb', line 27

def separator
  @separator
end

Class Method Details

.parse_filename(filename) ⇒ Object

extract the parts of a filename



86
87
88
89
90
91
92
93
94
# File 'lib/file_series.rb', line 86

def self.parse_filename(filename)
  base = File.basename(filename, '.log')
  prefix, date, time, duration = base.split('-')
  {
    prefix: prefix,
    start_time: Time.parse("#{date} #{time}").utc,
    duration: duration.to_i
  }
end

Instance Method Details

#complete_filesObject

get all files which match our pattern which are not current. (safe for consumption. no longer being written to.)



106
107
108
109
110
111
112
113
114
# File 'lib/file_series.rb', line 106

def complete_files
  current_file = filename

  Dir.glob(
    File.join(@dir, "#{@filename_prefix}-*-#{@rotate_freq}.log")
  ).select do |name|
    name != current_file
  end
end

#eachObject

enumerate over all the writes in a series, across all files.



117
118
119
120
121
122
123
# File 'lib/file_series.rb', line 117

def each
  complete_files.sort.each do |file|
    File.open(file,"r#{'b' if @binary_mode}").each_line(@separator) do |raw|
      yield raw
    end
  end
end

#filename(ts = nil) ⇒ Object

return a string filename for the logfile for the supplied timestamp. defaults to current time period.

changes to filename structure must be matched by changes to parse_filename



80
81
82
83
# File 'lib/file_series.rb', line 80

def filename(ts=nil)
  ts ||= this_period
  File.join(@dir, "#{@filename_prefix}-#{Time.at(ts).utc.strftime('%Y%m%d-%H%M%SZ')}-#{@rotate_freq}.log")
end

#log_fileObject

return a File object for the current log file.



49
50
51
52
53
54
55
56
57
58
# File 'lib/file_series.rb', line 49

def log_file
  ts = this_period

  # if we're in a new time period, start writing to new file.
  if (! file) || (ts != current_ts)
    rotate(ts)
  end

  file
end

#parse_filename(filename) ⇒ Object



96
97
98
# File 'lib/file_series.rb', line 96

def parse_filename(filename)
  self.class.parse_filename(filename)
end

#pathObject



100
101
102
# File 'lib/file_series.rb', line 100

def path
  filename
end

#rotate(ts = nil) ⇒ Object

close current file handle and open a new one for a new logging period. ts defaults to the current time period.



68
69
70
71
72
73
74
# File 'lib/file_series.rb', line 68

def rotate(ts=nil)
  ts ||= this_period
  @file.close if @file
  @file = File.open(filename(ts), "a#{'b' if @binary_mode}")
  @file.sync = @sync
  @current_ts = ts
end

#this_periodObject

compute the current time period.



61
62
63
64
# File 'lib/file_series.rb', line 61

def this_period
  t = Time.now.to_i
  t - (t % @rotate_freq)
end

#write(message) ⇒ Object

write something to the current log file.



44
45
46
# File 'lib/file_series.rb', line 44

def write(message)
  log_file.write(message.to_s + @separator)
end