Class: Syslogify::Forker

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/syslogify/forker.rb

Overview

Spawns a logger process that takes your stdout and stderr to syslog, by reopening them and piping to the subprocess.

Note that the process ID reported in syslog will be that of the logger subprocess.

Instance Method Summary collapse

Constructor Details

#initializeForker

Returns a new instance of Forker.



15
16
17
# File 'lib/syslogify/forker.rb', line 15

def initialize
  @pid = nil
end

Instance Method Details

#restartObject

useful when e.g. the process name changes, and/or after forking



77
78
79
80
# File 'lib/syslogify/forker.rb', line 77

def restart
  stop
  start
end

#startObject

causes standard output and error to be redirected to syslog (through a subprocess)



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/syslogify/forker.rb', line 21

def start
  return if @sink
  
  drain, @sink = IO.pipe
  @old_stdout = STDOUT.dup
  @old_stderr = STDERR.dup

  # Test connection to syslog in the parent process
  Syslog.open(_identity, Syslog::LOG_CONS | Syslog::LOG_NDELAY)
  Syslog.log(Syslog::LOG_NOTICE, 'Diverting logs to syslog')

  # spawn a subprocess which pipes from its standard input to syslog
  pid = fork do
    Process.daemon # otherwise we'll intercept signals
    $PROGRAM_NAME = "#{Syslog.ident}.syslogify"
    STDIN.reopen(drain)
    @sink.close

    while line = STDIN.gets
      Syslog.log(Syslog::LOG_NOTICE, line.force_encoding('binary').gsub('%', '%%'))
    end
    Syslog.log(Syslog::LOG_NOTICE, 'Shutting down')
  end

  Process.detach(pid) # the subprocess will shut down on its own once starved of input
  Syslog.close # the parent does not need syslog access

  # redirect stdout/err to the subprocess
  drain.close
  STDOUT.reopen(@sink)
  STDERR.reopen(@sink)
  STDOUT.sync = STDERR.sync = true
 
  begin
    @old_stderr.puts('Check syslog for further messages')
  rescue Errno::EPIPE
    # this can happen if something else tampered with our @old streams, 
    # e.g. the daemons library
  end
  self
end

#stopObject

cancels the outout redirection



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/syslogify/forker.rb', line 64

def stop
  return unless @sink
  # NOTE: we shouldn't kill the subprocess (which can be shared igqf the parent
  # forked after #start), and it'll shut down on its own anyways.
  STDOUT.reopen(@old_stdout) unless @old_stdout.closed?
  STDERR.reopen(@old_stderr) unless @old_stderr.closed?
  @sink.close unless @sink.closed?
  @old_stdout = @old_stderr = nil
  @sink = nil
  self
end