Created
May 30, 2017 07:34
-
-
Save miyucy/077a3238f34aba7460258fde47455366 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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