Class: Logbert::Handlers::LogRotator
- Inherits:
-
BaseHandler
- Object
- BaseHandler
- Logbert::Handlers::LogRotator
- Defined in:
- lib/logbert/handlers/log_rotator.rb
Overview
This class is a custom Handler responsible for rotating logs. This # means that it will periodically: #
-
Close the current log file and rename it. #
-
Begin writing future log messages to a new file. #
-
Delete the oldest log files to free up space #
Time-based log rotation #
Instance Attribute Summary collapse
-
#expiration_timestamp ⇒ Object
readonly
Returns the value of attribute expiration_timestamp.
-
#file_handle ⇒ Object
readonly
Returns the value of attribute file_handle.
-
#interval ⇒ Object
readonly
Returns the value of attribute interval.
-
#max_backups ⇒ Object
readonly
Returns the value of attribute max_backups.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#timestamp_formatter ⇒ Object
readonly
Returns the value of attribute timestamp_formatter.
Instance Method Summary collapse
- #already_rotated? ⇒ Boolean
- #attach_to_logfile! ⇒ Object
- #attached? ⇒ Boolean
- #compress_backups ⇒ Object
- #compute_expiration_timestamp_from(timestamp) ⇒ Object
- #delete_backups ⇒ Object
- #emit(output) ⇒ Object
- #get_old_logs ⇒ Object
- #gzip(file) ⇒ Object
-
#initialize(path, options = {}) ⇒ LogRotator
constructor
A new instance of LogRotator.
- #lock(&block) ⇒ Object
- #lock_file_name_for(log_path) ⇒ Object
- #rotate_logs! ⇒ Object
- #rotation_required? ⇒ Boolean
Methods inherited from BaseHandler
#formatter, #formatter=, #publish
Constructor Details
#initialize(path, options = {}) ⇒ LogRotator
Returns a new instance of LogRotator.
40 41 42 43 44 45 |
# File 'lib/logbert/handlers/log_rotator.rb', line 40 def initialize(path, = {}) @path = path @max_backups = .fetch(:max_backups, nil) @timestamp_formatter = .fetch(:timestamp_formatter, LocaltimeFormatter.new) @interval = .fetch(:interval, (24 * 60 * 60)) end |
Instance Attribute Details
#expiration_timestamp ⇒ Object (readonly)
Returns the value of attribute expiration_timestamp.
37 38 39 |
# File 'lib/logbert/handlers/log_rotator.rb', line 37 def @expiration_timestamp end |
#file_handle ⇒ Object (readonly)
Returns the value of attribute file_handle.
36 37 38 |
# File 'lib/logbert/handlers/log_rotator.rb', line 36 def file_handle @file_handle end |
#interval ⇒ Object (readonly)
Returns the value of attribute interval.
36 37 38 |
# File 'lib/logbert/handlers/log_rotator.rb', line 36 def interval @interval end |
#max_backups ⇒ Object (readonly)
Returns the value of attribute max_backups.
37 38 39 |
# File 'lib/logbert/handlers/log_rotator.rb', line 37 def max_backups @max_backups end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
38 39 40 |
# File 'lib/logbert/handlers/log_rotator.rb', line 38 def path @path end |
#timestamp_formatter ⇒ Object (readonly)
Returns the value of attribute timestamp_formatter.
36 37 38 |
# File 'lib/logbert/handlers/log_rotator.rb', line 36 def @timestamp_formatter end |
Instance Method Details
#already_rotated? ⇒ Boolean
59 60 61 |
# File 'lib/logbert/handlers/log_rotator.rb', line 59 def already_rotated? return File.ctime(@path) > @expiration_timestamp end |
#attach_to_logfile! ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/logbert/handlers/log_rotator.rb', line 63 def attach_to_logfile! lock do dirname = File.dirname(File.absolute_path(@path)) FileUtils.mkdir_p dirname unless File.exists? dirname @file_handle = File.open(@path, 'a') = File.ctime(@path) @expiration_timestamp = () end end |
#attached? ⇒ Boolean
47 48 49 |
# File 'lib/logbert/handlers/log_rotator.rb', line 47 def attached? return !file_handle.nil? end |
#compress_backups ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/logbert/handlers/log_rotator.rb', line 128 def compress_backups # Compress older log files (unless already compressed) get_old_logs.each do |log| unless File.extname(log) == ".gz" # Compress the file gzip(log) # Delete the actual log file File.delete(log) end end end |
#compute_expiration_timestamp_from(timestamp) ⇒ Object
80 81 82 |
# File 'lib/logbert/handlers/log_rotator.rb', line 80 def () return + @interval end |
#delete_backups ⇒ Object
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/logbert/handlers/log_rotator.rb', line 140 def delete_backups # Delete, if any, old log files based upon max_backups unless @max_backups.nil? # Grab all the logs. Sort from newest to oldest old_logs = get_old_logs.sort_by {|f| File.ctime(f)}.reverse[@max_backups..-1] # If we have more than max_backups logs, then delete the extras old_logs.each {|f| File.delete(f)} if old_logs end end |
#emit(output) ⇒ Object
73 74 75 76 77 78 |
# File 'lib/logbert/handlers/log_rotator.rb', line 73 def emit(output) attach_to_logfile! unless attached? rotate_logs! if rotation_required? @file_handle.puts output @file_handle.flush end |
#get_old_logs ⇒ Object
160 161 162 163 164 |
# File 'lib/logbert/handlers/log_rotator.rb', line 160 def get_old_logs absolute_dir = File.dirname(File.absolute_path(@path)) older_files = Dir[File.join(absolute_dir, "#{@path}.backup.*")] return older_files end |
#gzip(file) ⇒ Object
151 152 153 154 155 156 157 158 |
# File 'lib/logbert/handlers/log_rotator.rb', line 151 def gzip(file) Zlib::GzipWriter.open("#{file}.gz") do |gz| gz.mtime = File.mtime(file) gz.orig_name = file gz.write IO.binread(file) gz.close end end |
#lock(&block) ⇒ Object
84 85 86 87 88 89 90 91 |
# File 'lib/logbert/handlers/log_rotator.rb', line 84 def lock(&block) p = lock_file_name_for(@path) FileUtils.mkdir_p File.dirname(p) Lockfile.new(p) do block.call end end |
#lock_file_name_for(log_path) ⇒ Object
51 52 53 |
# File 'lib/logbert/handlers/log_rotator.rb', line 51 def lock_file_name_for(log_path) return "#{log_path}.lock" end |
#rotate_logs! ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/logbert/handlers/log_rotator.rb', line 93 def rotate_logs! performed_swap = false lock do # Double-check that the file wasn't already rotated unless already_rotated? performed_swap = true # Close the old log if @file_handle and not @file_handle.closed? @file_handle.close end # Rename the old log if File.exists? @path FileUtils.mv @path, archive_destination end end end # Lockfile lock attach_to_logfile! # Post-Processing logic if the rotation was performed post_process if performed_swap end |
#rotation_required? ⇒ Boolean
55 56 57 |
# File 'lib/logbert/handlers/log_rotator.rb', line 55 def rotation_required? return Time.now > @expiration_timestamp end |