daemons 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abe00f3deb97e3699634ffe4b3af947172f0cd36
4
- data.tar.gz: 30102dbdc48a16069b4fd453da56136edd078a0b
3
+ metadata.gz: 860b58ef469300cda2269a45f189796af8f36bcb
4
+ data.tar.gz: 29894094754c8013a9901f918f9e9ca2d700258f
5
5
  SHA512:
6
- metadata.gz: ce63a715f88dc69e06c8057f65c3e59b9f0478341cc78330c7eea82de5cd455cd44608c46bc26c5f949f07f8f5bea7e29cd1dca8fdbb4a1916be8e355d81327b
7
- data.tar.gz: d12066f4d7de22b1709cdca8d667d74d97b874ab0b56bef7d88738ede719e5c0be1d787c7b710f93ff2d5416967fdee4bd6c9ffc3fbe2862dbca3e60d558f349
6
+ metadata.gz: cd7e03dbc97d7dcaa21b582b868cea9b5610e52b975737b8c8309ce71f803647d3a87444e04a79b63feb2da895b0ee5ab8624985540c4a5dfba0be916f23d55a
7
+ data.tar.gz: c42a97021220ffbbe114349c8fe2ebeff0894b265cd4c2a960cf9efbdce5b0bcf873d92dd393b54fdde336b4d53c8ea4c53d827f567d0313829fd0f4f23c7cdb
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2015 Thomas Uehlinger, 2014-2015 Aaron Stone
1
+ Copyright (c) 2005-2016 Thomas Uehlinger, 2014-2016 Aaron Stone
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  Ruby Daemons
2
2
  ============
3
+ [![Code Climate](https://codeclimate.com/github/acuppy/daemons/badges/gpa.svg)](https://codeclimate.com/github/acuppy/daemons)[![Test Coverage](https://circleci.com/gh/acuppy/daemons.svg?style=shield&circle-token=a4f96fd41f7682661d6543e30207427ac8870c0d)](https://circleci.com/gh/acuppy/daemons)
3
4
 
4
5
  Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server)
5
6
  to be _run as a daemon_ and to be _controlled by simple start/stop/restart commands_.
@@ -203,4 +204,4 @@ Daemons.run('myserver.rb', { show_status_callback: :custom_show_status })
203
204
  Author
204
205
  ------
205
206
 
206
- Written 2005-2015 by Thomas Uehlinger <thomas.uehlinger@gmail.com>, 2014-2015 by Aaron Stone <aaron@serendipity.cx>.
207
+ Written 2005-2016 by Thomas Uehlinger, 2014-2016 by Aaron Stone.
data/Releases CHANGED
@@ -1,5 +1,11 @@
1
1
  = Daemons Release History
2
2
 
3
+ == Release 1.2.4: August 1, 2016
4
+
5
+ * add :shush option
6
+ * add :monitor_interval option
7
+ * add :log_output_syslog option
8
+
3
9
  == Release 1.2.3: June 25, 2015
4
10
 
5
11
  * fix: ApplicationGroup now waits on subprocesses in start_all (thanks to tobithiel)
@@ -27,12 +33,12 @@
27
33
 
28
34
  == Release 1.1.9: August 10, 2012
29
35
 
30
- * daemonize.rb: do srand in the forked child process both in daemonize and call_as_daemon
36
+ * daemonize.rb: do srand in the forked child process both in daemonize and call_as_daemon
31
37
  (thanks to Andrew Havens).
32
38
 
33
39
  == Release 1.1.8: February 7, 2012
34
40
 
35
- * rename to daemonization.rb to daemonize.rb (and Daemonization to Daemonize) to
41
+ * rename to daemonization.rb to daemonize.rb (and Daemonization to Daemonize) to
36
42
  ensure compatibility.
37
43
 
38
44
  == Release 1.1.7: February 6, 2012
@@ -46,57 +52,57 @@
46
52
 
47
53
  == Release 1.1.5: December 19, 2011
48
54
 
49
- * Catch the case where the pidfile is empty but not deleted
55
+ * Catch the case where the pidfile is empty but not deleted
50
56
  and restart the app (thanks to Rich Healey)
51
57
 
52
58
  == Release 1.1.4: June 17, 2011
53
59
 
54
- * Do not change the umask to 0000 when daemonizing anymore, just leave it as it
60
+ * Do not change the umask to 0000 when daemonizing anymore, just leave it as it
55
61
  was (thanks to Jon Botelho).
56
62
 
57
63
  == Release 1.1.3: April 14, 2011
58
64
 
59
65
  * Fixed a bug in Application.stop: the cached pid number needs to
60
66
  be used to check for the status of a killed process (thanks to Jimmy Sieben).
61
-
67
+
62
68
  == Release 1.1.2: March 29, 2011
63
69
 
64
70
  * Fixed gemspec to include all needed files.
65
-
71
+
66
72
  == Release 1.1.1: March 29, 2011
67
73
 
68
- * Make the logging facilities work in :mode => :none (i.e. when calling
74
+ * Make the logging facilities work in :mode => :none (i.e. when calling
69
75
  Daemons.daemonize) (thanks to the input from Peter Hegedus).
70
-
76
+
71
77
  == Release 1.1.0: June 20, 2010
72
78
 
73
79
  * Honour the options[:app_name] in Daemons.daemonize (thanks to Ryan Tecco).
74
- * Included a new option :stop_proc to specify a proc that will be called when a
80
+ * Included a new option :stop_proc to specify a proc that will be called when a
75
81
  daemonized process receives a request to stop (thanks to Dave Dupre).
76
82
  * Only delete the pidfile if the current pid is the original pid (ghazel).
77
83
  * Start when restart but no application running (pcreux).
78
84
  * Silently continue if there is no pidfile (ghazel).
79
85
  * We now per default wait for processes to stop and
80
- kill them automatically it if they do not stop within a given time
81
- (force_kill_waittime). Use the option --no_wait to not wait for processes to
86
+ kill them automatically it if they do not stop within a given time
87
+ (force_kill_waittime). Use the option --no_wait to not wait for processes to
82
88
  stop.
83
89
  * Set log files mode to 0644 (mikehale).
84
90
  * Set pid file permissions to 0644 (mikehale).
85
91
  * Added ability to change process uid/gid (mikehale).
86
- * Fix for: If you happen to start a daemon from a process that has open file
87
- descriptors these will stay open. As it is daemonize.rb only closes ruby IO
92
+ * Fix for: If you happen to start a daemon from a process that has open file
93
+ descriptors these will stay open. As it is daemonize.rb only closes ruby IO
88
94
  objects (thanks to Han Holl).
89
95
  * New reload command (SIGHUP) (thanks to Michael Schuerig).
90
96
 
91
97
  == Release 1.0.10: March 21, 2008
92
98
 
93
- * By default, we now delete stray pid-files (i.e. pid-files which result for
94
- example from a killed daemon) automatically. This function can be deactivated
99
+ * By default, we now delete stray pid-files (i.e. pid-files which result for
100
+ example from a killed daemon) automatically. This function can be deactivated
95
101
  by passing :keep_pid_files => true as an option.
96
- * All pid files of :multiple daemons new get deleted correctly upon exit of the
102
+ * All pid files of :multiple daemons new get deleted correctly upon exit of the
97
103
  daemons (reported by Han Holl).
98
104
  * Use the signal 'KILL' instead of 'TERM' on Windows platforms.
99
- * Use exit! in trap('TERM') instead of exit when option :hard_exit is given
105
+ * Use exit! in trap('TERM') instead of exit when option :hard_exit is given
100
106
  (thanks to Han Holl).
101
107
  * Did some clarification on the exception log.
102
108
 
@@ -107,12 +113,12 @@
107
113
 
108
114
  == Release 1.0.8: September 24, 2007
109
115
 
110
- * new Pid.running? function. Checking whether a process exists by sending
116
+ * new Pid.running? function. Checking whether a process exists by sending
111
117
  signal '0' (thanks to Dru Nelson).
112
118
 
113
119
  == Release 1.0.7: July 7, 2007
114
120
 
115
- * Patch to fix wrong ARGV when using :exec (in def start_exec:
121
+ * Patch to fix wrong ARGV when using :exec (in def start_exec:
116
122
  Kernel.exec(script(), *(@app_argv || []))) (thanks to Alex McGuire).
117
123
 
118
124
  == Release 1.0.6: Mai 8, 2007
@@ -122,7 +128,7 @@
122
128
 
123
129
  == Release 1.0.5: February 24, 2007
124
130
 
125
- * Applied patch that makes daemons to use '/var/log' as logfile
131
+ * Applied patch that makes daemons to use '/var/log' as logfile
126
132
  directory if you use :dir_mode = :system (thanks to Han Holl).
127
133
  * Daemons should now work with Ruby 1.9 (at least the basic features).
128
134
 
@@ -130,7 +136,7 @@
130
136
 
131
137
  * Document the :log_output option (thanks to Andrew Kuklewicz).
132
138
  * Set STDOUT.sync = true when redirecting to a logfile (thanks to Andrew Kuklewicz).
133
- * Should now run also correctly when there is no working 'ps ax' on the system
139
+ * Should now run also correctly when there is no working 'ps ax' on the system
134
140
  (thanks to Daniel Kehoe).
135
141
 
136
142
  == Release 1.0.3: November 1, 2006
@@ -142,7 +148,7 @@
142
148
  * Changed the 'ps -ax' call back to 'ps ax'.
143
149
  * Fixed the documentation for the :normal :dir_mode.
144
150
  * As a default for Daemons.run_proc, the pid file is now saved in the current directory.
145
- * In :ontop mode for running a proc (this is equal to calling something like 'ruby ctrl_proc.rb run'),
151
+ * In :ontop mode for running a proc (this is equal to calling something like 'ruby ctrl_proc.rb run'),
146
152
  the proc now runs directly in the calling script, not in a forked process anymore (thanks to Paul Butcher).
147
153
  * Set $0 to app_name in the daemons (thanks to Ilya Novoselov).
148
154
 
@@ -156,7 +162,7 @@
156
162
 
157
163
  == Release 0.4.4: February 14, 2006
158
164
 
159
- * Several fixes that allow us to use the Daemons::Controller
165
+ * Several fixes that allow us to use the Daemons::Controller
160
166
  with a proc instead of wrapping a script file. This gives us all the
161
167
  PID file management, monitoring, command line options, etc. without having
162
168
  to specify a path to our script which can be tricky, especially when using
@@ -168,7 +174,7 @@
168
174
  on calling Daemons.run. This will be used to contruct the name of the pid files
169
175
  and log files. Defaults to the basename of the script. (thanks to Stephen R. Veit)
170
176
 
171
- * Bugfix: Handle the case where no controller options are given when calling Daemons,
177
+ * Bugfix: Handle the case where no controller options are given when calling Daemons,
172
178
  just options after "--". (thanks to Stephen R. Veit)
173
179
 
174
180
 
@@ -28,7 +28,7 @@ class MyApp < Logger::Application
28
28
  def run
29
29
  Daemons.run_proc('myapp', :ARGV => @args, :ontop => !@options.daemonize) do
30
30
  puts "@options.daemonize: #{@options.daemonize}"
31
- STDOUT.sync = true
31
+ $stdout.sync = true
32
32
  loop do
33
33
  print '.'
34
34
  sleep(2)
@@ -47,7 +47,7 @@ require 'daemons/controller'
47
47
  # the potential of acquiring a controlling terminal.
48
48
  # 4. Changes the current working directory to "/".
49
49
  # 5. Clears the file creation mask (sets +umask+ to 0000).
50
- # 6. Closes file descriptors (reopens +STDOUT+ and +STDERR+ to point to a logfile if
50
+ # 6. Closes file descriptors (reopens +$stdout+ and +$stderr+ to point to a logfile if
51
51
  # possible).
52
52
  #
53
53
  # So what does this mean for your daemons:
@@ -101,17 +101,20 @@ module Daemons
101
101
  # same time
102
102
  # <tt>:ontop</tt>:: When given (i.e. set to true), stay on top, i.e. do not daemonize the application
103
103
  # (but the pid-file and other things are written as usual)
104
+ # <tt>:shush</tt>:: When given (i.e. set to true), turn on silent mode (no output to the terminal)
104
105
  # <tt>:mode</tt>:: <tt>:load</tt> Load the script with <tt>Kernel.load</tt>;
105
106
  # note that :stop_proc only works for the :load (and :proc) mode.
106
107
  # <tt>:exec</tt> Execute the script file with <tt>Kernel.exec</tt>
107
108
  # <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
108
109
  # pid-file directory if the application exits due to an uncaught exception
109
110
  # <tt>:monitor</tt>:: Monitor the programs and restart crashed instances
111
+ # <tt>:monitor_interval</tt>:: Interval in sesconds at which to check whether the instances are still running
110
112
  # <tt>:log_dir</tt>:: A specific directory to put the log files into (when not given, resort to the default
111
113
  # location as derived from the :dir_mode and :dir options
112
114
  # <tt>:logfilename</tt>:: Specifiy a custom log file name
113
- # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named '[app_name].output' (or as given in :output_logfilename) in the pid-file directory
115
+ # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both $stdout and $stderr to a logfile named '[app_name].output' (or as given in :output_logfilename) in the pid-file directory
114
116
  # <tt>:output_logfilename</tt>:: Specifiy a custom output redirection file name
117
+ # <tt>:log_output_syslog</tt>:: When set to true, redirect output into SYSLOG instead of the file. This overrides log_output setting.
115
118
  # <tt>:keep_pid_files</tt>:: When given do not delete lingering pid-files (files for which the process is no longer running).
116
119
  # <tt>:hard_exit</tt>:: When given use exit! to end a daemons instead of exit (this will for example
117
120
  # not call at_exit handlers).
@@ -127,6 +130,7 @@ module Daemons
127
130
  # :dir => 'pids',
128
131
  # :multiple => true,
129
132
  # :ontop => true,
133
+ # :shush => false,
130
134
  # :mode => :exec,
131
135
  # :backtrace => true,
132
136
  # :monitor => true,
@@ -210,6 +214,8 @@ module Daemons
210
214
  # === Options:
211
215
  # <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
212
216
  # same time
217
+ # <tt>:monitor</tt>:: Monitor the programs and restart crashed instances
218
+ # <tt>:monitor_interval</tt>:: Interval in sesconds at which to check whether the instances are still running
213
219
  # <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
214
220
  # <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
215
221
  # pid-file directory if the application exits due to an uncaught exception
@@ -271,7 +277,8 @@ module Daemons
271
277
  # <tt>:dir</tt>:: Used in combination with <tt>:dir_mode</tt> (description above)
272
278
  # <tt>:log_dir</tt>:: A specific directory to put the log files into (when not given, resort to the default
273
279
  # location as derived from the :dir_mode and :dir options
274
- # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named '[app_name].output' in the pid-file directory
280
+ # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both $stdout and $stdout to a logfile named '[app_name].output' in the pid-file directory
281
+ # <tt>:log_output_syslog</tt>:: When set to true, redirect output into SYSLOG instead of the file. This overrides log_output setting.
275
282
  # -----
276
283
  #
277
284
  # === Example:
@@ -3,6 +3,7 @@ require 'daemons/pidmem'
3
3
  require 'daemons/change_privilege'
4
4
  require 'daemons/daemonize'
5
5
  require 'daemons/exceptions'
6
+ require 'daemons/reporter'
6
7
 
7
8
  require 'timeout'
8
9
 
@@ -33,6 +34,8 @@ module Daemons
33
34
 
34
35
  @show_status_callback = method(:default_show_status)
35
36
 
37
+ @report = Reporter.new(@options)
38
+
36
39
  unless @pid = pid
37
40
  if @options[:no_pidfiles]
38
41
  @pid = PidMem.new
@@ -51,47 +54,45 @@ module Daemons
51
54
  def change_privilege
52
55
  user = options[:user]
53
56
  group = options[:group]
54
- CurrentProcess.change_privilege(user, group) if user
57
+ if user
58
+ @report.changing_process_privilege(user, group)
59
+ CurrentProcess.change_privilege(user, group)
60
+ end
55
61
  end
56
62
 
57
63
  def script
58
- @script || @group.script
64
+ @script or group.script
59
65
  end
60
66
 
61
67
  def pidfile_dir
62
- Pid.dir(@dir_mode || @group.dir_mode, @dir || @group.dir, @script || @group.script)
68
+ Pid.dir dir_mode, dir, script
63
69
  end
64
70
 
65
71
  def logdir
66
- logdir = options[:log_dir]
67
- unless logdir
68
- logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
69
- end
70
- logdir
72
+ options[:log_dir] or
73
+ options[:dir_mode] == :system ? '/var/log' : pidfile_dir
71
74
  end
72
75
 
73
76
  def output_logfilename
74
- filename = options[:output_logfilename]
75
- unless filename
76
- filename = @group.app_name + '.output'
77
- end
78
- filename
77
+ options[:output_logfilename] or "#{@group.app_name}.output"
79
78
  end
80
-
79
+
81
80
  def output_logfile
82
- (options[:log_output] && logdir) ? File.join(logdir, output_logfilename) : nil
81
+ if log_output_syslog?
82
+ 'SYSLOG'
83
+ elsif log_output?
84
+ File.join logdir, output_logfilename
85
+ end
83
86
  end
84
87
 
85
88
  def logfilename
86
- filename = options[:logfilename]
87
- unless filename
88
- filename = @group.app_name + '.log'
89
- end
90
- filename
89
+ options[:logfilename] or "#{@group.app_name}.log"
91
90
  end
92
-
91
+
93
92
  def logfile
94
- logdir ? File.join(logdir, logfilename) : nil
93
+ if logdir
94
+ File.join logdir, logfilename
95
+ end
95
96
  end
96
97
 
97
98
  # this function is only used to daemonize the currently running process (Daemons.daemonize)
@@ -139,7 +140,7 @@ module Daemons
139
140
 
140
141
  def start_exec
141
142
  if options[:backtrace]
142
- puts 'option :backtrace is not supported with :mode => :exec, ignoring'
143
+ @report.backtrace_not_supported
143
144
  end
144
145
 
145
146
  unless options[:ontop]
@@ -152,7 +153,7 @@ module Daemons
152
153
  @pid.pid = Process.pid
153
154
 
154
155
  ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
155
-
156
+
156
157
  started
157
158
  Kernel.exec(script, *(@app_argv || []))
158
159
  end
@@ -300,8 +301,7 @@ module Daemons
300
301
 
301
302
  def started
302
303
  if pid = @pid.pid
303
- puts "#{group.app_name}: process with pid #{pid} started."
304
- STDOUT.flush
304
+ @report.process_started(group.app_name, pid)
305
305
  end
306
306
  end
307
307
 
@@ -324,7 +324,7 @@ module Daemons
324
324
  # one cannot catch exceptions that are thrown in threads other than the main
325
325
  # thread.
326
326
  #
327
- # This function searches for all exceptions in memory and outputs them to STDERR
327
+ # This function searches for all exceptions in memory and outputs them to $stderr
328
328
  # (if it is connected) and to a log file in the pid-file directory.
329
329
  #
330
330
  def exception_log
@@ -373,14 +373,14 @@ module Daemons
373
373
  begin
374
374
  Process.kill(SIGNAL, pid)
375
375
  rescue Errno::ESRCH => e
376
- puts "#{e} #{pid}"
377
- puts 'deleting pid-file.'
376
+ @report.output_message("#{e} #{pid}")
377
+ @report.output_message('deleting pid-file.')
378
378
  end
379
379
 
380
380
  unless no_wait
381
381
  if @force_kill_waittime > 0
382
- puts "#{group.app_name}: trying to stop process with pid #{pid}..."
383
- STDOUT.flush
382
+ @report.stopping_process(group.app_name, pid)
383
+ $stdout.flush
384
384
 
385
385
  begin
386
386
  Timeout.timeout(@force_kill_waittime, TimeoutError) do
@@ -389,8 +389,8 @@ module Daemons
389
389
  end
390
390
  end
391
391
  rescue TimeoutError
392
- puts "#{group.app_name}: process with pid #{pid} won't stop, we forcefully kill it..."
393
- STDOUT.flush
392
+ @report.forcefully_stopping_process(group.app_name, pid)
393
+ $stdout.flush
394
394
 
395
395
  begin
396
396
  Process.kill('KILL', pid)
@@ -404,8 +404,8 @@ module Daemons
404
404
  end
405
405
  end
406
406
  rescue TimeoutError
407
- puts "#{group.app_name}: unable to forcefully kill process with pid #{pid}."
408
- STDOUT.flush
407
+ @report.cannot_stop_process(group.app_name, pid)
408
+ $stdout.flush
409
409
  end
410
410
  end
411
411
  end
@@ -418,8 +418,8 @@ module Daemons
418
418
  # didn't clean it up.
419
419
  begin; @pid.cleanup; rescue ::Exception; end
420
420
 
421
- puts "#{group.app_name}: process with pid #{pid} successfully stopped."
422
- STDOUT.flush
421
+ @report.stopped_process(group.app_name, pid)
422
+ $stdout.flush
423
423
  end
424
424
  end
425
425
 
@@ -438,7 +438,7 @@ module Daemons
438
438
  def default_show_status(daemon = self)
439
439
  running = daemon.running?
440
440
 
441
- puts "#{group.app_name}: #{running ? '' : 'not '}running#{(running and daemon.pid.exist?) ? ' [pid ' + daemon.pid.pid.to_s + ']' : ''}#{(daemon.pid.exist? and not running) ? ' (but pid-file exists: ' + daemon.pid.pid.to_s + ')' : ''}"
441
+ @report.status(group.app_name, running, daemon.pid.exist?, daemon.pid.pid.to_s)
442
442
  end
443
443
 
444
444
  # This function implements a (probably too simle) method to detect
@@ -449,11 +449,25 @@ module Daemons
449
449
  # system.
450
450
  #
451
451
  def running?
452
- if @pid.exist?
453
- return Pid.running?(@pid.pid)
454
- end
452
+ @pid.exist? and Pid.running? @pid.pid
453
+ end
454
+
455
+ private
456
+
457
+ def log_output?
458
+ options[:log_output] && logdir
459
+ end
460
+
461
+ def log_output_syslog?
462
+ options[:log_output_syslog]
463
+ end
464
+
465
+ def dir_mode
466
+ @dir_mode or group.dir_mode
467
+ end
455
468
 
456
- false
469
+ def dir
470
+ @dir or group.dir
457
471
  end
458
472
  end
459
473
  end
@@ -69,7 +69,7 @@ module Daemons
69
69
  if x && x.chomp!
70
70
  processes = x.split(/\n/).compact
71
71
  processes = processes.delete_if do |p|
72
- pid, name, add = p.split(/\s/)
72
+ _pid, name, add = p.split(/\s/)
73
73
  # We want to make sure that the first part of the process name matches
74
74
  # so that app_name matches app_name_22
75
75
 
@@ -90,7 +90,11 @@ module Daemons
90
90
  def find_applications_by_pidfiles(dir)
91
91
  @monitor = Monitor.find(dir, app_name + '_monitor')
92
92
 
93
- pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
93
+ reporter = Reporter.new(options)
94
+ pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files) do |pid, file|
95
+ reporter.deleted_found_pidfile(pid, file)
96
+ end
97
+
94
98
  pid_files.map do |f|
95
99
  app = Application.new(self, {}, PidFile.existing(f))
96
100
  setup_app(app)
@@ -137,7 +141,9 @@ module Daemons
137
141
  end
138
142
 
139
143
  if options[:monitor]
140
- @monitor = Monitor.new(an_app)
144
+ opt = {}
145
+ opt[:monitor_interval] = options[:monitor_interval] if options[:monitor_interval]
146
+ @monitor = Monitor.new(an_app, opt)
141
147
  @monitor.start(self)
142
148
  end
143
149
  end
@@ -186,12 +192,12 @@ module Daemons
186
192
  def show_status
187
193
  @applications.each { |a| a.show_status }
188
194
  end
189
-
195
+
190
196
  # Check whether at least one of the applications in the group is running. If yes, return true.
191
197
  def running?
192
198
  @applications.each { |a| return true if a.running? }
193
199
  return false
194
200
  end
195
-
201
+
196
202
  end
197
203
  end
@@ -2,8 +2,6 @@ require 'daemons/etc_extension'
2
2
 
3
3
  class CurrentProcess
4
4
  def self.change_privilege(user, group = user)
5
- puts "Changing process privilege to #{user}:#{group}"
6
-
7
5
  uid, gid = Process.euid, Process.egid
8
6
  target_uid = Etc.getpwnam(user).uid
9
7
  target_gid = Etc.getgrnam(group).gid
@@ -12,6 +12,10 @@ module Daemons
12
12
  opts.on('-t', '--ontop', 'Stay on top (does not daemonize)') do |t|
13
13
  @options[:ontop] = t
14
14
  end
15
+
16
+ opts.on('-s', '--shush', 'Silent mode (no output to the terminal)') do |t|
17
+ @options[:shush] = t
18
+ end
15
19
 
16
20
  opts.on('-f', '--force', 'Force operation') do |t|
17
21
  @options[:force] = t
@@ -19,7 +19,7 @@ module Daemonize
19
19
  module_function :safefork
20
20
 
21
21
  # Simulate the daemonization process (:ontop mode)
22
- # NOTE: STDOUT and STDERR will not be redirected to the logfile,
22
+ # NOTE: $stdout and $stderr will not be redirected to the logfile,
23
23
  # because in :ontop mode, we normally want to see the output
24
24
  def simulate(logfile_name = nil, app_name = nil)
25
25
  $0 = app_name if app_name
@@ -29,8 +29,8 @@ module Daemonize
29
29
 
30
30
  close_io
31
31
 
32
- # Free STDIN and point it to somewhere sensible
33
- begin; STDIN.reopen '/dev/null'; rescue ::Exception; end
32
+ # Free $stdin and point it to somewhere sensible
33
+ begin; $stdin.reopen '/dev/null'; rescue ::Exception; end
34
34
 
35
35
  # Split rand streams between spawning and daemonized process
36
36
  srand
@@ -58,7 +58,7 @@ module Daemonize
58
58
  rd.close
59
59
 
60
60
  # Detach from the controlling terminal
61
- unless sess_id = Process.setsid
61
+ unless Process.setsid
62
62
  fail Daemons.RuntimeException.new('cannot detach from controlling terminal')
63
63
  end
64
64
 
@@ -100,7 +100,7 @@ module Daemonize
100
100
 
101
101
  # Prevent the possibility of acquiring a controlling terminal
102
102
  trap 'SIGHUP', 'IGNORE'
103
- exit if pid = safefork
103
+ exit if safefork
104
104
 
105
105
  $0 = app_name if app_name
106
106
 
@@ -120,40 +120,49 @@ module Daemonize
120
120
 
121
121
  def close_io
122
122
  # Make sure all input/output streams are closed
123
- # Part I: close all IO objects (except for STDIN/STDOUT/STDERR)
123
+ # Part I: close all IO objects (except for $stdin/$stdout/$stderr)
124
124
  ObjectSpace.each_object(IO) do |io|
125
- unless [STDIN, STDOUT, STDERR].include?(io)
125
+ unless [$stdin, $stdout, $stderr].include?(io)
126
126
  io.close rescue nil
127
127
  end
128
128
  end
129
129
 
130
130
  # Make sure all input/output streams are closed
131
- # Part II: close all file decriptors (except for STDIN/STDOUT/STDERR)
131
+ # Part II: close all file decriptors (except for $stdin/$stdout/$stderr)
132
132
  3.upto(8192) do |i|
133
133
  IO.for_fd(i).close rescue nil
134
134
  end
135
135
  end
136
136
  module_function :close_io
137
137
 
138
- # Free STDIN/STDOUT/STDERR file descriptors and
138
+ # Free $stdin/$stdout/$stderr file descriptors and
139
139
  # point them somewhere sensible
140
140
  def redirect_io(logfile_name)
141
- begin; STDIN.reopen '/dev/null'; rescue ::Exception; end
141
+ begin; $stdin.reopen '/dev/null'; rescue ::Exception; end
142
142
 
143
- if logfile_name
143
+ if logfile_name == 'SYSLOG'
144
+ # attempt to use syslog via syslogio
144
145
  begin
145
- STDOUT.reopen logfile_name, 'a'
146
- File.chmod(0644, logfile_name)
147
- STDOUT.sync = true
146
+ require 'syslogio'
147
+ $stdout = ::Daemons::SyslogIO.new($0, :local0, :info, $stdout)
148
+ $stderr = ::Daemons::SyslogIO.new($0, :local0, :err, $stderr)
149
+ # error out early so we can fallback to null
150
+ $stdout.puts "no logfile provided, output redirected to syslog"
148
151
  rescue ::Exception
149
- begin; STDOUT.reopen '/dev/null'; rescue ::Exception; end
152
+ # on unsupported platforms simply reopen /dev/null
153
+ begin; $stdout.reopen '/dev/null'; rescue ::Exception; end
154
+ begin; $stderr.reopen '/dev/null'; rescue ::Exception; end
150
155
  end
156
+ elsif logfile_name
157
+ $stdout.reopen logfile_name, 'a'
158
+ File.chmod(0644, logfile_name)
159
+ $stdout.sync = true
160
+ begin; $stderr.reopen $stdout; rescue ::Exception; end
161
+ $stderr.sync = true
151
162
  else
152
- begin; STDOUT.reopen '/dev/null'; rescue ::Exception; end
163
+ begin; $stdout.reopen '/dev/null'; rescue ::Exception; end
164
+ begin; $stderr.reopen '/dev/null'; rescue ::Exception; end
153
165
  end
154
-
155
- begin; STDERR.reopen STDOUT; rescue ::Exception; end
156
- STDERR.sync = true
157
166
  end
158
167
  module_function :redirect_io
159
168
  end
@@ -3,11 +3,9 @@ require 'etc'
3
3
  Etc.instance_eval do
4
4
  def groupname(gid)
5
5
  Etc.group { |e| return e.name if gid == e.gid }
6
- nil
7
6
  end
8
7
 
9
8
  def username(uid)
10
9
  Etc.passwd { |e| return e.name if uid == e.uid }
11
- nil
12
10
  end
13
11
  end
@@ -1,6 +1,5 @@
1
-
2
1
  module Daemons
3
- class Exception < ::RuntimeError
2
+ class Exception < RuntimeError
4
3
  end
5
4
 
6
5
  class RuntimeException < Exception
@@ -25,9 +25,10 @@ module Daemons
25
25
  nil
26
26
  end
27
27
 
28
- def initialize(an_app)
28
+ def initialize(an_app, options = {})
29
29
  @app = an_app
30
30
  @app_name = an_app.group.app_name + '_monitor'
31
+ @monitor_interval = options[:monitor_interval] || 30
31
32
 
32
33
  if an_app.pidfile_dir
33
34
  @pid = PidFile.new(an_app.pidfile_dir, @app_name, false)
@@ -46,13 +47,13 @@ module Daemons
46
47
 
47
48
  sleep(1)
48
49
 
49
- Process.detach(fork { a.start(restart = true) })
50
+ Process.detach(fork { a.start(true) })
50
51
 
51
52
  sleep(5)
52
53
  end
53
54
  end
54
55
 
55
- sleep(30)
56
+ sleep(@monitor_interval)
56
57
  end
57
58
  end
58
59
  private :watch
@@ -105,8 +106,8 @@ module Daemons
105
106
  end
106
107
  end
107
108
  rescue ::Exception => e
108
- puts "exception while trying to stop monitor process #{pid}: #{e}"
109
- puts 'deleting pid-file.'
109
+ $stderr.puts "exception while trying to stop monitor process #{pid}: #{e}"
110
+ $stderr.puts 'deleting pid-file.'
110
111
  end
111
112
 
112
113
  # We try to remove the pid-files by ourselves, in case the monitor
@@ -40,8 +40,8 @@ module Daemons
40
40
  pid = File.open(f) { |h| h.read }.to_i
41
41
  rsl = !Pid.running?(pid)
42
42
  if rsl
43
- puts "pid-file for killed process #{pid} found (#{f}), deleting."
44
43
  begin; File.unlink(f); rescue ::Exception; end
44
+ yield(pid, f) if block_given?
45
45
  end
46
46
  rsl
47
47
  end
@@ -0,0 +1,55 @@
1
+ module Daemons
2
+ class Reporter
3
+ attr_reader :options
4
+
5
+ def initialize(options)
6
+ @options = options
7
+
8
+ if !options[:shush]
9
+ $stdout.sync = true
10
+ end
11
+ end
12
+
13
+ def output_message(message)
14
+ if !options[:shush]
15
+ puts message
16
+ end
17
+ end
18
+
19
+ def changing_process_privilege(user, group = user)
20
+ output_message "Changing process privilege to #{user}:#{group}"
21
+ end
22
+
23
+ def deleted_found_pidfile(pid, f)
24
+ output_message "pid-file for killed process #{pid} found (#{f}), deleting."
25
+ end
26
+
27
+ def process_started(app_name, pid)
28
+ output_message "#{app_name}: process with pid #{pid} started."
29
+ end
30
+
31
+ def backtrace_not_supported
32
+ output_message 'option :backtrace is not supported with :mode => :exec, ignoring'
33
+ end
34
+
35
+ def stopping_process(app_name, pid)
36
+ output_message "#{app_name}: trying to stop process with pid #{pid}..."
37
+ end
38
+
39
+ def forcefully_stopping_process(app_name, pid)
40
+ output_message "#{app_name}: process with pid #{pid} won't stop, we forcefully kill it..."
41
+ end
42
+
43
+ def cannot_stop_process(app_name, pid)
44
+ output_message "#{app_name}: unable to forcefully kill process with pid #{pid}."
45
+ end
46
+
47
+ def stopped_process(app_name, pid)
48
+ output_message "#{app_name}: process with pid #{pid} successfully stopped."
49
+ end
50
+
51
+ def status(app_name, running, pid_exists, pid)
52
+ output_message "#{app_name}: #{running ? '' : 'not '}running#{(running and pid_exists) ? ' [pid ' + pid.to_s + ']' : ''}#{(pid_exists and not running) ? ' (but pid-file exists: ' + pid.to_s + ')' : ''}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,240 @@
1
+ # This is a simple class meant to allow using syslog through an IO-like object. Code
2
+ # borrowed from https://github.com/phemmer/ruby-syslogio
3
+ #
4
+ # The usage is simple:
5
+ #
6
+ # require 'syslogio'
7
+ # $stdout = SyslogIO.new("myapp", :local0, :info, $stdout)
8
+ # $stderr = SyslogIO.new("myapp", :local0, :err, $stderr)
9
+ # $stdout.puts "This is a message"
10
+ # $stderr.puts "This is an error"
11
+ # raise StandardError, 'This will get written through the SyslogIO for $stderr'
12
+
13
+ class Daemons::SyslogIO
14
+ require 'syslog'
15
+
16
+ # Indicates whether synchonous IO is enabled.
17
+ # @return [Boolean]
18
+ attr_reader :sync
19
+
20
+ # @!visibility private
21
+ def self.syslog_constant_sym(option)
22
+ return unless option.is_a?(Symbol) or option.is_a?(String)
23
+ option = option.to_s.upcase
24
+ option = "LOG_#{option}" unless option[0..4] == 'LOG_'
25
+ option = option.to_sym
26
+ option
27
+ end
28
+ # @!visibility private
29
+ def self.syslog_constant(option)
30
+ return unless option = syslog_constant_sym(option)
31
+ return Syslog.constants.include?(option) ? Syslog.const_get(option) : nil
32
+ end
33
+ # @!visibility private
34
+ def self.syslog_facility(option)
35
+ return unless option = syslog_constant_sym(option)
36
+ return Syslog::Facility.constants.include?(option) ? Syslog.const_get(option) : nil
37
+ end
38
+ # @!visibility private
39
+ def self.syslog_level(option)
40
+ return unless option = syslog_constant_sym(option)
41
+ return Syslog::Level.constants.include?(option) ? Syslog.const_get(option) : nil
42
+ end
43
+ # @!visibility private
44
+ def self.syslog_option(option)
45
+ return unless option = syslog_constant_sym(option)
46
+ return Syslog::Option.constants.include?(option) ? Syslog.const_get(option) : nil
47
+ end
48
+
49
+ # Creates a new object.
50
+ # You can have as many SyslogIO objects as you like. However because they all share the same syslog connection, some parameters are shared. The identifier shared among all SyslogIO objects, and is set to the value of the last one created. The Syslog options are merged together as a combination of all objects. The facility and level are distinct between each though.
51
+ # If an IO object is provided as an argument, any text written to the SyslogIO object will also be passed through to that IO object.
52
+ #
53
+ # @param identifier [String] Identifier
54
+ # @param facility [Fixnum<Syslog::Facility>] Syslog facility
55
+ # @param level [Fixnum<Syslog::Level>] Syslog level
56
+ # @param option [Fixnum<Syslog::Options>] Syslog option
57
+ # @param passthrough [IO] IO passthrough
58
+ def initialize(*options)
59
+ options.each do |option|
60
+ if option.is_a?(String)
61
+ @ident = option
62
+ elsif value = self.class.syslog_facility(option)
63
+ @facility = value
64
+ elsif value = self.class.syslog_level(option)
65
+ @level = value
66
+ elsif value = self.class.syslog_option(option)
67
+ @options = 0 if @options.nil?
68
+ @options |= value
69
+ elsif option.is_a?(IO)
70
+ @out = option
71
+ else
72
+ raise ArgumentError, "Unknown argument #{option.inspect}"
73
+ end
74
+ end
75
+
76
+ @options ||= 0
77
+ @ident ||= $0.sub(/.*\//, '')
78
+ @facility ||= Syslog::LOG_USER
79
+ @level ||= Syslog::LOG_INFO
80
+
81
+ if Syslog.opened? then
82
+ options = Syslog.options | @options
83
+ @syslog = Syslog.reopen(@ident, options, @facility)
84
+ else
85
+ @syslog = Syslog.open(@ident, @options, @facility)
86
+ end
87
+
88
+ @subs = []
89
+ @sync = false
90
+ @buffer = ''
91
+
92
+ at_exit { flush }
93
+ end
94
+
95
+ # Add a substitution rule
96
+ #
97
+ # These substitutions will be applied to each line before it is logged. This can be useful if some other gem is generating log content and you want to change the formatting.
98
+ # @param regex [Regex]
99
+ def sub_add(regex, replacement)
100
+ @subs << [regex, replacement]
101
+ end
102
+
103
+ # Enable or disable synchronous IO (buffering).
104
+ #
105
+ # When false (default), output will be line buffered. For syslog this is optimal so the log entries are complete lines.
106
+ def sync=(sync)
107
+ if sync != true and sync != false then
108
+ raise ArgumentError, "sync must be true or false"
109
+ end
110
+ @sync = sync
111
+ if sync == true then
112
+ flush
113
+ end
114
+ end
115
+
116
+ # Write to syslog respecting the behavior of the {#sync} setting.
117
+ def write(text)
118
+ if @sync then
119
+ syswrite(text)
120
+ else
121
+ text.split(/(\n)/).each do |line|
122
+ @buffer = @buffer + line.to_s
123
+ if line == "\n" then
124
+ flush
125
+ end
126
+ end
127
+ end
128
+ end
129
+ alias_method :<<, :write
130
+
131
+ # Write to syslog directly, bypassing buffering if enabled.
132
+ def syswrite(text)
133
+ begin
134
+ @out.syswrite(text) if @out and !@out.closed?
135
+ rescue SystemCallError => e
136
+ end
137
+
138
+ text.split(/\n/).each do |line|
139
+ @subs.each do |sub|
140
+ line.sub!(sub[0], sub[1])
141
+ end
142
+ if line == '' or line.match(/^\s*$/) then
143
+ next
144
+ end
145
+ Syslog.log(@facility | @level, line)
146
+ end
147
+ nil
148
+ end
149
+
150
+ # Immediately flush any buffered data
151
+ def flush
152
+ syswrite(@buffer)
153
+ @buffer = ''
154
+ end
155
+
156
+ # Log at the debug level
157
+ #
158
+ # Shorthand for {#log}(text, Syslog::LOG_DEBUG)
159
+ def debug(text)
160
+ log(text, Syslog::LOG_DEBUG)
161
+ end
162
+
163
+ # Log at the info level
164
+ #
165
+ # Shorthand for {#log}(text, Syslog::LOG_INFO)
166
+ def info(text)
167
+ log(text, Syslog::LOG_INFO)
168
+ end
169
+
170
+ # Log at the notice level
171
+ #
172
+ # Shorthand for {#log}(text, Syslog::LOG_NOTICE)
173
+ def notice(text)
174
+ log(text, Syslog::LOG_NOTICE)
175
+ end
176
+ alias_method :notify, :notice
177
+
178
+ # Log at the warning level
179
+ #
180
+ # Shorthand for {#log}(text, Syslog::LOG_WARNING)
181
+ def warn(text)
182
+ log(text, Syslog::LOG_WARNING)
183
+ end
184
+
185
+ # Log at the error level
186
+ #
187
+ # Shorthand for {#log}(text, Syslog::LOG_ERR)
188
+ def error(text)
189
+ log(text, Syslog::LOG_ERR)
190
+ end
191
+
192
+ # Log at the critical level
193
+ #
194
+ # Shorthand for {#log}(text, Syslog::LOG_CRIT)
195
+ def crit(text)
196
+ log(text, Syslog::LOG_CRIT)
197
+ end
198
+ alias_method :fatal, :crit
199
+
200
+ # Log at the emergency level
201
+ #
202
+ # Shorthand for {#log}(text, Syslog::LOG_EMERG)
203
+ def emerg(text)
204
+ log(text, Syslog::LOG_EMERG)
205
+ end
206
+
207
+ # Log a complete line
208
+ #
209
+ # Similar to {#write} but appends a newline if not present.
210
+ def puts(*texts)
211
+ texts.each do |text|
212
+ write(text.chomp + "\n")
213
+ end
214
+ end
215
+
216
+ # Write a complete line at the specified log level
217
+ #
218
+ # Similar to {#puts} but allows changing the log level for just this one message
219
+ def log(text, level = nil)
220
+ if priority.nil? then
221
+ write(text.chomp + "\n")
222
+ else
223
+ priority_bkup = @priority
224
+ #TODO fix this to be less ugly. Temporarily setting an instance variable is evil
225
+ @priority = priority
226
+ write(text.chomp + "\n")
227
+ @priority = priority_bkup
228
+ end
229
+ end
230
+
231
+ # @!visibility private
232
+ def noop(*args)
233
+ end
234
+ alias_method :reopen, :noop
235
+
236
+ # false
237
+ def isatty
238
+ false
239
+ end
240
+ end
@@ -1,3 +1,3 @@
1
1
  module Daemons
2
- VERSION = '1.2.3'
2
+ VERSION = '1.2.4'
3
3
  end
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daemons
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Uehlinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-08 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2016-08-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  description: |2
14
70
  Daemons provides an easy way to wrap existing ruby scripts (for example a
15
71
  self-written server) to be run as a daemon and to be controlled by simple
@@ -68,6 +124,8 @@ files:
68
124
  - lib/daemons/pid.rb
69
125
  - lib/daemons/pidfile.rb
70
126
  - lib/daemons/pidmem.rb
127
+ - lib/daemons/reporter.rb
128
+ - lib/daemons/syslogio.rb
71
129
  - lib/daemons/version.rb
72
130
  homepage: https://github.com/thuehlinger/daemons
73
131
  licenses: