Skip to content

Instantly share code, notes, and snippets.

@miyucy
Created May 30, 2017 07:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miyucy/077a3238f34aba7460258fde47455366 to your computer and use it in GitHub Desktop.
Save miyucy/077a3238f34aba7460258fde47455366 to your computer and use it in GitHub Desktop.
require 'find'
class Watchlog
class LogFile
def initialize(path)
@path = path
@pid = nil
@wth = nil
end
def perform
unless @pid
@pid = fork_and_exec('tail', '-f', @path)
@wth = Thread.new(@pid) { |pid| Process.waitpid pid }
end
end
def kill
if @pid
Process.kill :TERM, @pid
@pid = nil
@wth = nil
end
end
def fork_and_exec(*command)
pid = Process.fork { Process.exec(*command, out: :out, err: :err) }
pid.nil? ? exit! : pid
end
end
def initialize(dir, retains=nil, interval=3)
@target = dir
@retains = Array(retains).map { |f| File.expand_path f }
@interval = interval
@log_files = {}
@create = []
@delete = []
@paths = []
@first = true
@break = false
end
def perform
STDOUT.sync = true
STDERR.sync = true
sigtrap
loop do
find
unwatch
watch
sleep @interval
break if @break
end
unwatch!
end
def find
paths = to_paths Find.find(@target)
if @first
@create = paths.dup
@paths = paths
@first = false
else
@create = paths - @paths
@delete = @paths - paths
@paths = paths
end
end
def watch
to_paths(@create | @retains).each do |path|
log_file = @log_files[path] || LogFile.new(path)
log_file.perform
@log_files[path] = log_file
end
@create.clear
end
def unwatch
@delete.each do |path|
log_file = @log_files.delete path
log_file.kill if log_file
end
@delete.clear
end
def unwatch!
@log_files.each_value(&:kill)
@log_files.clear
end
def sigtrap
Signal.trap(:TERM) { @break = true }
Signal.trap(:INT) { @break = true }
end
def to_paths(enum)
enum.select { |f| File.file? f }.map { |f| File.expand_path f }.select { |f| File.extname(f).downcase == '.log' }
end
end
if __FILE__ == $PROGRAM_NAME
dir = ARGV.shift || '/path/to/log_dir'
Watchlog.new(File.expand_path(dir), ARGV).perform
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment