diff options
Diffstat (limited to 'lib/yahns/log.rb')
-rw-r--r-- | lib/yahns/log.rb | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/yahns/log.rb b/lib/yahns/log.rb new file mode 100644 index 0000000..59baa85 --- /dev/null +++ b/lib/yahns/log.rb @@ -0,0 +1,73 @@ +# -*- encoding: binary -*- +# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors +# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) + +# logging-related utility functions for all of yahns +module Yahns::Log # :nodoc: + def self.exception(logger, prefix, exc) + message = exc.message + message = message.dump if /[[:cntrl:]]/ =~ message # prevent code injection + logger.error "#{prefix}: #{message} (#{exc.class})" + exc.backtrace.each { |line| logger.error(line) } + end + + def self.is_log?(fp) + append_flags = IO::WRONLY | IO::APPEND + + ! fp.closed? && + fp.stat.file? && + fp.sync && + (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags + rescue IOError, Errno::EBADF + false + end + + def self.chown_all(uid, gid) + ObjectSpace.each_object(File) do |fp| + fp.chown(uid, gid) if is_log?(fp) + end + end + + # This reopens ALL logfiles in the process that have been rotated + # using logrotate(8) (without copytruncate) or similar tools. + # A +File+ object is considered for reopening if it is: + # 1) opened with the O_APPEND and O_WRONLY flags + # 2) the current open file handle does not match its original open path + # 3) unbuffered (as far as userspace buffering goes, not O_SYNC) + # Returns the number of files reopened + def self.reopen_all + to_reopen = [] + nr = 0 + ObjectSpace.each_object(File) { |fp| is_log?(fp) and to_reopen << fp } + + to_reopen.each do |fp| + orig_st = begin + fp.stat + rescue IOError, Errno::EBADF + next + end + + begin + b = File.stat(fp.path) + next if orig_st.ino == b.ino && orig_st.dev == b.dev + rescue Errno::ENOENT + end + + begin + File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) } + fp.sync = true + new_st = fp.stat + + # this should only happen in the master: + if orig_st.uid != new_st.uid || orig_st.gid != new_st.gid + fp.chown(orig_st.uid, orig_st.gid) + end + + nr += 1 + rescue IOError, Errno::EBADF + # not much we can do... + end + end + nr + end +end |