textgoeshere-daemon-kit 0.1.8rc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Configuration.txt +110 -0
- data/Deployment.txt +113 -0
- data/History.txt +124 -0
- data/Logging.txt +96 -0
- data/PostInstall.txt +6 -0
- data/README.rdoc +128 -0
- data/Rakefile +29 -0
- data/RuoteParticipants.txt +113 -0
- data/TODO.txt +27 -0
- data/bin/daemon-kit +18 -0
- data/config/website.yml +2 -0
- data/daemon-kit.gemspec +265 -0
- data/lib/daemon_kit/abstract_logger.rb +249 -0
- data/lib/daemon_kit/amqp.rb +39 -0
- data/lib/daemon_kit/application.rb +230 -0
- data/lib/daemon_kit/arguments.rb +165 -0
- data/lib/daemon_kit/commands/console.rb +38 -0
- data/lib/daemon_kit/commands/destroy.rb +10 -0
- data/lib/daemon_kit/commands/generate.rb +10 -0
- data/lib/daemon_kit/config.rb +113 -0
- data/lib/daemon_kit/console_daemon.rb +2 -0
- data/lib/daemon_kit/core_ext/configurable.rb +96 -0
- data/lib/daemon_kit/core_ext/string.rb +22 -0
- data/lib/daemon_kit/core_ext.rb +1 -0
- data/lib/daemon_kit/cron.rb +48 -0
- data/lib/daemon_kit/cucumber/world.rb +38 -0
- data/lib/daemon_kit/deployment/capistrano.rb +516 -0
- data/lib/daemon_kit/em.rb +43 -0
- data/lib/daemon_kit/error_handlers/base.rb +32 -0
- data/lib/daemon_kit/error_handlers/hoptoad.rb +180 -0
- data/lib/daemon_kit/exceptions.rb +15 -0
- data/lib/daemon_kit/generators/base.rb +60 -0
- data/lib/daemon_kit/generators.rb +67 -0
- data/lib/daemon_kit/initializer.rb +453 -0
- data/lib/daemon_kit/jabber.rb +171 -0
- data/lib/daemon_kit/nanite/agent.rb +77 -0
- data/lib/daemon_kit/nanite.rb +7 -0
- data/lib/daemon_kit/pid_file.rb +61 -0
- data/lib/daemon_kit/ruote_participants.rb +125 -0
- data/lib/daemon_kit/ruote_pseudo_participant.rb +68 -0
- data/lib/daemon_kit/ruote_workitem.rb +187 -0
- data/lib/daemon_kit/safety.rb +84 -0
- data/lib/daemon_kit/tasks/environment.rake +10 -0
- data/lib/daemon_kit/tasks/framework.rake +123 -0
- data/lib/daemon_kit/tasks/god.rake +62 -0
- data/lib/daemon_kit/tasks/log.rake +8 -0
- data/lib/daemon_kit/tasks/monit.rake +29 -0
- data/lib/daemon_kit/tasks.rb +2 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/CHANGELOG.rdoc +89 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/LICENSE +20 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/README.rdoc +297 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/Thorfile +69 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/create_file.rb +103 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/directory.rb +91 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/empty_directory.rb +134 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/file_manipulation.rb +223 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions/inject_into_file.rb +104 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/actions.rb +296 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/base.rb +540 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/error.rb +30 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/group.rb +271 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/invocation.rb +180 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/argument.rb +67 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/arguments.rb +150 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/option.rb +128 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser/options.rb +169 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/parser.rb +4 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/rake_compat.rb +66 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/runner.rb +314 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell/basic.rb +239 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell/color.rb +108 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/shell.rb +83 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/task.rb +102 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/util.rb +224 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor/version.rb +3 -0
- data/lib/daemon_kit/vendor/thor-0.13.6/lib/thor.rb +244 -0
- data/lib/daemon_kit/xmpp.rb +100 -0
- data/lib/daemon_kit.rb +59 -0
- data/lib/generators/daemon_kit/amqp/USAGE +5 -0
- data/lib/generators/daemon_kit/amqp/amqp_generator.rb +24 -0
- data/lib/generators/daemon_kit/amqp/templates/config/amqp.yml +28 -0
- data/lib/generators/daemon_kit/amqp/templates/config/pre-daemonize/amqp.rb +7 -0
- data/lib/generators/daemon_kit/amqp/templates/libexec/%app_name%-daemon.rb +37 -0
- data/lib/generators/daemon_kit/app/USAGE +7 -0
- data/lib/generators/daemon_kit/app/app_generator.rb +140 -0
- data/lib/generators/daemon_kit/app/templates/Gemfile +8 -0
- data/lib/generators/daemon_kit/app/templates/README.tt +58 -0
- data/lib/generators/daemon_kit/app/templates/Rakefile +6 -0
- data/lib/generators/daemon_kit/app/templates/bin/daemon.tt +7 -0
- data/lib/generators/daemon_kit/app/templates/config/arguments.rb +12 -0
- data/lib/generators/daemon_kit/app/templates/config/boot.rb +70 -0
- data/lib/generators/daemon_kit/app/templates/config/environment.rb.tt +26 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/development.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/production.rb +5 -0
- data/lib/generators/daemon_kit/app/templates/config/environments/test.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/config/post-daemonize/readme +5 -0
- data/lib/generators/daemon_kit/app/templates/config/pre-daemonize/readme +12 -0
- data/lib/generators/daemon_kit/app/templates/lib/%app_name%.rb +2 -0
- data/lib/generators/daemon_kit/app/templates/libexec/%app_name%-daemon.rb +18 -0
- data/lib/generators/daemon_kit/app/templates/script/console +3 -0
- data/lib/generators/daemon_kit/app/templates/script/destroy +3 -0
- data/lib/generators/daemon_kit/app/templates/script/generate +3 -0
- data/lib/generators/daemon_kit/capistrano/capistrano_generator.rb +26 -0
- data/lib/generators/daemon_kit/capistrano/templates/Capfile +10 -0
- data/lib/generators/daemon_kit/capistrano/templates/USAGE +10 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/logrotate.erb +13 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/production.rb.tt +6 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy/staging.rb.tt +6 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/deploy.rb.tt +67 -0
- data/lib/generators/daemon_kit/capistrano/templates/config/environments/staging.rb +0 -0
- data/lib/generators/daemon_kit/cron/USAGE +5 -0
- data/lib/generators/daemon_kit/cron/cron_generator.rb +24 -0
- data/lib/generators/daemon_kit/cron/templates/config/pre-daemonize/cron.rb +11 -0
- data/lib/generators/daemon_kit/cron/templates/libexec/%app_name%-daemon.rb +43 -0
- data/lib/generators/daemon_kit/cucumber/USAGE +11 -0
- data/lib/generators/daemon_kit/cucumber/cucumber_generator.rb +45 -0
- data/lib/generators/daemon_kit/cucumber/templates/config/environments/cucumber.rb +2 -0
- data/lib/generators/daemon_kit/cucumber/templates/features/step_definitions/.empty_directory +0 -0
- data/lib/generators/daemon_kit/cucumber/templates/features/support/env.rb +7 -0
- data/lib/generators/daemon_kit/cucumber/templates/script/cucumber +7 -0
- data/lib/generators/daemon_kit/cucumber/templates/tasks/cucumber.rake +13 -0
- data/lib/generators/daemon_kit/nanite_agent/USAGE +5 -0
- data/lib/generators/daemon_kit/nanite_agent/nanite_agent_generator.rb +29 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/config/nanite.yml +35 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/config/pre-daemonize/nanite_agent.rb +6 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/lib/actors/sample.rb +11 -0
- data/lib/generators/daemon_kit/nanite_agent/templates/libexec/%app_name%-daemon.rb +31 -0
- data/lib/generators/daemon_kit/rspec/USAGE +5 -0
- data/lib/generators/daemon_kit/rspec/rspec_generator.rb +20 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/%app_name%_spec.rb +11 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/spec.opts +1 -0
- data/lib/generators/daemon_kit/rspec/templates/spec/spec_helper.rb +23 -0
- data/lib/generators/daemon_kit/rspec/templates/tasks/rspec.rake +19 -0
- data/lib/generators/daemon_kit/ruote/USAGE +5 -0
- data/lib/generators/daemon_kit/ruote/ruote_generator.rb +29 -0
- data/lib/generators/daemon_kit/ruote/templates/config/amqp.yml +30 -0
- data/lib/generators/daemon_kit/ruote/templates/config/pre-daemonize/ruote.rb +13 -0
- data/lib/generators/daemon_kit/ruote/templates/config/ruote.yml +23 -0
- data/lib/generators/daemon_kit/ruote/templates/lib/%app_name%.rb +4 -0
- data/lib/generators/daemon_kit/ruote/templates/lib/sample.rb +26 -0
- data/lib/generators/daemon_kit/ruote/templates/libexec/%app_name%-daemon.rb +33 -0
- data/lib/generators/daemon_kit/test_unit/USAGE +5 -0
- data/lib/generators/daemon_kit/test_unit/templates/tasks/test_unit.rake +7 -0
- data/lib/generators/daemon_kit/test_unit/templates/test/%app_name%_test.rb.tt +9 -0
- data/lib/generators/daemon_kit/test_unit/templates/test/test_helper.rb +6 -0
- data/lib/generators/daemon_kit/test_unit/test_unit_generator.rb +20 -0
- data/lib/generators/daemon_kit/xmpp/templates/config/pre-daemonize/xmpp.rb +6 -0
- data/lib/generators/daemon_kit/xmpp/templates/config/xmpp.yml +29 -0
- data/lib/generators/daemon_kit/xmpp/templates/libexec/%app_name%-daemon.rb +27 -0
- data/lib/generators/daemon_kit/xmpp/xmpp_generator.rb +24 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/abstract_logger_spec.rb +126 -0
- data/spec/argument_spec.rb +70 -0
- data/spec/config_spec.rb +83 -0
- data/spec/configurable_spec.rb +56 -0
- data/spec/daemon_kit_spec.rb +7 -0
- data/spec/error_handlers_spec.rb +23 -0
- data/spec/fixtures/env.yml +15 -0
- data/spec/fixtures/noenv.yml +4 -0
- data/spec/initializer_spec.rb +26 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +27 -0
- data/tasks/cucumber.rake +13 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/tests.rake +6 -0
- data/templates/god/god.erb +69 -0
- data/templates/monit/monit.erb +14 -0
- data/test/test_amqp_generator.rb +48 -0
- data/test/test_cron_generator.rb +45 -0
- data/test/test_daemon-kit_generator.rb +84 -0
- data/test/test_daemon_kit_config.rb +28 -0
- data/test/test_deploy_capistrano_generator.rb +48 -0
- data/test/test_generator_helper.rb +29 -0
- data/test/test_helper.rb +7 -0
- data/test/test_nanite_agent_generator.rb +49 -0
- data/test/test_ruote_generator.rb +51 -0
- data/test/test_test_unit_generator.rb +46 -0
- metadata +325 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module DaemonKit
|
|
4
|
+
# One of the key parts of succesful background processes is adequate
|
|
5
|
+
# logging. The AbstractLogger aims to simplify logging from inside
|
|
6
|
+
# daemon processes by providing additional useful information with
|
|
7
|
+
# each log line, including calling file name and line number and
|
|
8
|
+
# support for cleanly logging exceptions.
|
|
9
|
+
#
|
|
10
|
+
# The logger can be accessed through #DaemonKit.logger.
|
|
11
|
+
#
|
|
12
|
+
# AbstractLogger provides an interface that is fully compatible with
|
|
13
|
+
# the Logger class provided by Ruby's Standard Library, and is
|
|
14
|
+
# extended with some additional conveniences.
|
|
15
|
+
#
|
|
16
|
+
# The AbstractLogger supports different backends, by default it uses
|
|
17
|
+
# a Logger instance, but can by swapped out for a SysLogLogger
|
|
18
|
+
# logger as well.
|
|
19
|
+
class AbstractLogger
|
|
20
|
+
|
|
21
|
+
attr_accessor :copy_to_stdout
|
|
22
|
+
|
|
23
|
+
@severities = {
|
|
24
|
+
:debug => Logger::DEBUG,
|
|
25
|
+
:info => Logger::INFO,
|
|
26
|
+
:warn => Logger::WARN,
|
|
27
|
+
:error => Logger::ERROR,
|
|
28
|
+
:fatal => Logger::FATAL,
|
|
29
|
+
:unknown => Logger::UNKNOWN
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@silencer = true
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
attr_reader :severities
|
|
36
|
+
attr_accessor :silencer
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Optional log path, defaults to
|
|
40
|
+
# <em>DAEMON_ROOT/log/DAEMON_ENV.log</em>
|
|
41
|
+
def initialize( log_path = nil )
|
|
42
|
+
if log_path.to_s == "syslog"
|
|
43
|
+
@backend = :syslog
|
|
44
|
+
else
|
|
45
|
+
@logger_file = log_path || "#{DAEMON_ROOT}/log/#{DAEMON_ENV}.log"
|
|
46
|
+
@backend = :logger
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@copy_to_stdout = false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Silence the logger for the duration of the block.
|
|
53
|
+
def silence( temporary_level = :error )
|
|
54
|
+
if self.class.silencer
|
|
55
|
+
begin
|
|
56
|
+
old_level, self.level = self.level, temporary_level
|
|
57
|
+
yield self
|
|
58
|
+
ensure
|
|
59
|
+
self.level = old_level
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
yield self
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Write unformatted message to logging device, mostly useful for Logger interface
|
|
67
|
+
# compatibility and debugging soap4r (possibly others)
|
|
68
|
+
def <<( msg ) #:nodoc:
|
|
69
|
+
self.logger.write( msg ) if self.logger && self.logger.respond_to?( :write )
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def debug( msg = nil, &block )
|
|
73
|
+
add( :debug, msg, &block )
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def debug?
|
|
77
|
+
self.level == :debug
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def info( msg = nil, &block )
|
|
81
|
+
add( :info, msg, &block )
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def info?
|
|
85
|
+
self.level == :info
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def warn( msg = nil, &block )
|
|
89
|
+
add( :warn, msg, &block )
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def warn?
|
|
93
|
+
self.level == :warn
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def error( msg = nil, &block )
|
|
97
|
+
add( :error, msg, &block )
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def error?
|
|
101
|
+
self.level == :error
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def fatal( msg = nil, &block )
|
|
105
|
+
add( :fatal, msg, &block )
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def fatal?
|
|
109
|
+
self.level == :fatal
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def unknown( msg = nil, &block )
|
|
113
|
+
add( :unknown, msg, &block )
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def unknown?
|
|
117
|
+
self.level == :unknown
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Conveniently log an exception and the backtrace
|
|
121
|
+
def exception( e )
|
|
122
|
+
message = "EXCEPTION: #{e.message}: #{clean_trace( e.backtrace )}"
|
|
123
|
+
self.add( :error, message, true )
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def add( severity, message = nil, skip_caller = false, &block )
|
|
127
|
+
message = yield if block_given?
|
|
128
|
+
|
|
129
|
+
message = "#{called(caller)}: #{message}" unless skip_caller
|
|
130
|
+
|
|
131
|
+
self.logger.add( self.class.severities[ severity ] ) { message }
|
|
132
|
+
|
|
133
|
+
STDOUT.puts( message ) if self.copy_to_stdout
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def level
|
|
137
|
+
self.class.severities.invert[ @logger.level ]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def level=( level )
|
|
141
|
+
level = ( Symbol === level ? self.class.severities[ level ] : level )
|
|
142
|
+
self.logger.level = level
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def logger
|
|
146
|
+
@logger ||= create_logger
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def logger=( logger )
|
|
150
|
+
if logger.is_a?( Symbol )
|
|
151
|
+
@backend = logger
|
|
152
|
+
@logger.close rescue nil
|
|
153
|
+
@logger = create_logger
|
|
154
|
+
else
|
|
155
|
+
@logger.close rescue nil
|
|
156
|
+
@logger = logger
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def clean_trace( trace )
|
|
161
|
+
trace = trace.map { |l| l.gsub(DAEMON_ROOT, '') }
|
|
162
|
+
trace = trace.reject { |l| l =~ /gems\/daemon[\-_]kit/ }
|
|
163
|
+
trace = trace.reject { |l| l =~ /vendor\/daemon[\-_]kit/ }
|
|
164
|
+
trace
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def close
|
|
168
|
+
case @backend
|
|
169
|
+
when :logger
|
|
170
|
+
self.logger.close
|
|
171
|
+
@logger = nil
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
private
|
|
176
|
+
|
|
177
|
+
def called( trace )
|
|
178
|
+
l = trace.detect('unknown:0') { |l| l.index('abstract_logger.rb').nil? }
|
|
179
|
+
file, num, _ = l.split(':')
|
|
180
|
+
|
|
181
|
+
if file =~ /daemon[\-_]kit/
|
|
182
|
+
"[daemon-kit]"
|
|
183
|
+
|
|
184
|
+
else
|
|
185
|
+
[ File.basename(file), num ].join(':')
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def create_logger
|
|
190
|
+
case @backend
|
|
191
|
+
when :logger
|
|
192
|
+
create_standard_logger
|
|
193
|
+
when :syslog
|
|
194
|
+
create_syslog_logger
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def create_standard_logger
|
|
199
|
+
log_path = File.dirname( @logger_file )
|
|
200
|
+
unless File.directory?( log_path )
|
|
201
|
+
begin
|
|
202
|
+
FileUtils.mkdir_p( log_path )
|
|
203
|
+
rescue
|
|
204
|
+
STDERR.puts "#{log_path} not writable, using STDERR for logging"
|
|
205
|
+
@logger_file = STDERR
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
l = Logger.new( @logger_file )
|
|
210
|
+
l.formatter = Formatter.new
|
|
211
|
+
l.progname = if DaemonKit.configuration
|
|
212
|
+
DaemonKit.configuration.daemon_name
|
|
213
|
+
else
|
|
214
|
+
File.basename($0)
|
|
215
|
+
end
|
|
216
|
+
l
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def create_syslog_logger
|
|
220
|
+
begin
|
|
221
|
+
require 'syslog_logger'
|
|
222
|
+
SyslogLogger.new( DaemonKit.configuration ? DaemonKit.configuration.daemon_name : File.basename($0) )
|
|
223
|
+
rescue LoadError
|
|
224
|
+
self.logger = :logger
|
|
225
|
+
self.error( "Couldn't load syslog_logger gem, reverting to standard logger" )
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
class Formatter
|
|
230
|
+
|
|
231
|
+
# YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
|
|
232
|
+
@format = "%s %s(%d) [%s] %s\n"
|
|
233
|
+
|
|
234
|
+
class << self
|
|
235
|
+
attr_accessor :format
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def call(severity, time, progname, msg)
|
|
239
|
+
self.class.format % [ format_time( time ), progname, $$, severity, msg.to_s ]
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
private
|
|
243
|
+
|
|
244
|
+
def format_time( time )
|
|
245
|
+
time.strftime( "%Y-%m-%d %H:%M:%S." ) + time.usec.to_s
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'mq'
|
|
3
|
+
|
|
4
|
+
module DaemonKit
|
|
5
|
+
# Thin wrapper around the amqp gem, specifically designed to ease
|
|
6
|
+
# configuration of a AMQP consumer daemon and provide some added
|
|
7
|
+
# simplicity
|
|
8
|
+
class AMQP
|
|
9
|
+
|
|
10
|
+
@@instance = nil
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
|
|
14
|
+
def instance
|
|
15
|
+
@instance ||= new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private :new
|
|
19
|
+
|
|
20
|
+
def run(&block)
|
|
21
|
+
instance.run(&block)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def initialize( config = {} )
|
|
26
|
+
@config = DaemonKit::Config.load('amqp').to_h( true )
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run(&block)
|
|
30
|
+
# Ensure graceful shutdown of the connection to the broker
|
|
31
|
+
DaemonKit.trap('INT') { ::AMQP.stop { ::EM.stop } }
|
|
32
|
+
DaemonKit.trap('TERM') { ::AMQP.stop { ::EM.stop } }
|
|
33
|
+
|
|
34
|
+
# Start our event loop and AMQP client
|
|
35
|
+
DaemonKit.logger.debug("AMQP.start(#{@config.inspect})")
|
|
36
|
+
::AMQP.start(@config, &block)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
module DaemonKit
|
|
4
|
+
|
|
5
|
+
# Class responsible for making the daemons run and keep them running.
|
|
6
|
+
class Application
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
|
|
10
|
+
# Run the specified file as a daemon process.
|
|
11
|
+
def exec( file )
|
|
12
|
+
raise DaemonNotFound.new( file ) unless File.exist?( file )
|
|
13
|
+
|
|
14
|
+
DaemonKit.configuration.daemon_name ||= File.basename( file )
|
|
15
|
+
|
|
16
|
+
command, configs, args = Arguments.parse( ARGV )
|
|
17
|
+
|
|
18
|
+
case command
|
|
19
|
+
when :run
|
|
20
|
+
parse_arguments( args )
|
|
21
|
+
run( file )
|
|
22
|
+
when :start
|
|
23
|
+
parse_arguments( args )
|
|
24
|
+
start( file )
|
|
25
|
+
when :stop
|
|
26
|
+
stop
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Run the daemon in the foreground without daemonizing
|
|
31
|
+
def run( file )
|
|
32
|
+
self.chroot
|
|
33
|
+
self.clean_fd
|
|
34
|
+
self.redirect_io( true )
|
|
35
|
+
|
|
36
|
+
DaemonKit.configuration.log_stdout = true
|
|
37
|
+
|
|
38
|
+
require file
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Run our file properly
|
|
42
|
+
def start( file )
|
|
43
|
+
self.drop_privileges
|
|
44
|
+
self.daemonize
|
|
45
|
+
self.chroot
|
|
46
|
+
self.clean_fd
|
|
47
|
+
self.redirect_io
|
|
48
|
+
|
|
49
|
+
require file
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def stop
|
|
53
|
+
@pid_file = PidFile.new( DaemonKit.configuration.pid_file )
|
|
54
|
+
|
|
55
|
+
unless @pid_file.running?
|
|
56
|
+
@pid_file.cleanup
|
|
57
|
+
puts "Nothing to stop"
|
|
58
|
+
exit
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
target_pid = @pid_file.pid
|
|
62
|
+
|
|
63
|
+
puts "Sending TERM to #{target_pid}"
|
|
64
|
+
Process.kill( 'TERM', target_pid )
|
|
65
|
+
|
|
66
|
+
if seconds = DaemonKit.configuration.force_kill_wait
|
|
67
|
+
begin
|
|
68
|
+
Timeout::timeout( seconds ) do
|
|
69
|
+
loop do
|
|
70
|
+
puts "Waiting #{seconds} seconds for #{target_pid} before sending KILL"
|
|
71
|
+
|
|
72
|
+
break unless @pid_file.running?
|
|
73
|
+
|
|
74
|
+
seconds -= 1
|
|
75
|
+
sleep 1
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
rescue Timeout::Error
|
|
79
|
+
Process.kill( 'KILL', target_pid )
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if @pid_file.running?
|
|
84
|
+
puts "Process still running, leaving pidfile behind! Consider using configuration.force_kill_wait."
|
|
85
|
+
else
|
|
86
|
+
@pid_file.cleanup
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Call this from inside a daemonized process to complete the
|
|
91
|
+
# initialization process
|
|
92
|
+
def running!
|
|
93
|
+
Initializer.continue!
|
|
94
|
+
|
|
95
|
+
yield DaemonKit.configuration if block_given?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Exit the daemon
|
|
99
|
+
# TODO: Make configurable callback chain
|
|
100
|
+
# TODO: Hook into at_exit()
|
|
101
|
+
def exit!( code = 0 )
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# http://gist.github.com/304739
|
|
105
|
+
#
|
|
106
|
+
# Stolen from Unicorn::Util
|
|
107
|
+
#
|
|
108
|
+
# This reopens ALL logfiles in the process that have been rotated
|
|
109
|
+
# using logrotate(8) (without copytruncate) or similar tools.
|
|
110
|
+
# A +File+ object is considered for reopening if it is:
|
|
111
|
+
# 1) opened with the O_APPEND and O_WRONLY flags
|
|
112
|
+
# 2) opened with an absolute path (starts with "/")
|
|
113
|
+
# 3) the current open file handle does not match its original open path
|
|
114
|
+
# 4) unbuffered (as far as userspace buffering goes, not O_SYNC)
|
|
115
|
+
# Returns the number of files reopened
|
|
116
|
+
def reopen_logs
|
|
117
|
+
nr = 0
|
|
118
|
+
append_flags = File::WRONLY | File::APPEND
|
|
119
|
+
DaemonKit.logger.info "Rotating logs" if DaemonKit.logger
|
|
120
|
+
|
|
121
|
+
#logs = [STDOUT, STDERR]
|
|
122
|
+
#logs.each do |fp|
|
|
123
|
+
ObjectSpace.each_object(File) do |fp|
|
|
124
|
+
next if fp.closed?
|
|
125
|
+
next unless (fp.sync && fp.path[0..0] == "/")
|
|
126
|
+
next unless (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags
|
|
127
|
+
|
|
128
|
+
begin
|
|
129
|
+
a, b = fp.stat, File.stat(fp.path)
|
|
130
|
+
next if a.ino == b.ino && a.dev == b.dev
|
|
131
|
+
rescue Errno::ENOENT
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
open_arg = 'a'
|
|
135
|
+
if fp.respond_to?(:external_encoding) && enc = fp.external_encoding
|
|
136
|
+
open_arg << ":#{enc.to_s}"
|
|
137
|
+
enc = fp.internal_encoding and open_arg << ":#{enc.to_s}"
|
|
138
|
+
end
|
|
139
|
+
DaemonKit.logger.info "Rotating path: #{fp.path}" if DaemonKit.logger
|
|
140
|
+
fp.reopen(fp.path, open_arg)
|
|
141
|
+
fp.sync = true
|
|
142
|
+
nr += 1
|
|
143
|
+
end # each_object
|
|
144
|
+
nr
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
protected
|
|
148
|
+
|
|
149
|
+
def parse_arguments( args )
|
|
150
|
+
DaemonKit.arguments = Arguments.new
|
|
151
|
+
DaemonKit.arguments.parse( args )
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Daemonize the process
|
|
155
|
+
def daemonize
|
|
156
|
+
@pid_file = PidFile.new( DaemonKit.configuration.pid_file )
|
|
157
|
+
@pid_file.ensure_stopped!
|
|
158
|
+
|
|
159
|
+
if RUBY_VERSION < "1.9"
|
|
160
|
+
exit if fork
|
|
161
|
+
Process.setsid
|
|
162
|
+
exit if fork
|
|
163
|
+
else
|
|
164
|
+
Process.daemon( true, true )
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
@pid_file.write!
|
|
168
|
+
|
|
169
|
+
# TODO: Convert into shutdown hook
|
|
170
|
+
at_exit { @pid_file.cleanup }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Release the old working directory and insure a sensible umask
|
|
174
|
+
# TODO: Make chroot directory configurable
|
|
175
|
+
def chroot
|
|
176
|
+
Dir.chdir '/'
|
|
177
|
+
File.umask 0000
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Make sure all file descriptors are closed (with the exception
|
|
181
|
+
# of STDIN, STDOUT & STDERR)
|
|
182
|
+
def clean_fd
|
|
183
|
+
ObjectSpace.each_object(IO) do |io|
|
|
184
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
|
185
|
+
begin
|
|
186
|
+
unless io.closed?
|
|
187
|
+
io.close
|
|
188
|
+
end
|
|
189
|
+
rescue ::Exception
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Redirect our IO
|
|
196
|
+
# TODO: make this configurable
|
|
197
|
+
def redirect_io( simulate = false )
|
|
198
|
+
begin
|
|
199
|
+
STDIN.reopen '/dev/null'
|
|
200
|
+
rescue ::Exception
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
unless simulate
|
|
204
|
+
STDOUT.reopen '/dev/null', 'a'
|
|
205
|
+
STDERR.reopen '/dev/null', 'a'
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def drop_privileges
|
|
210
|
+
if DaemonKit.configuration.group
|
|
211
|
+
begin
|
|
212
|
+
group = Etc.getgrnam( DaemonKit.configuration.group )
|
|
213
|
+
Process::Sys.setgid( group.gid.to_i )
|
|
214
|
+
rescue => e
|
|
215
|
+
$stderr.puts "Caught exception while trying to drop group privileges: #{e.message}"
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
if DaemonKit.configuration.user
|
|
219
|
+
begin
|
|
220
|
+
user = Etc.getpwnam( DaemonKit.configuration.user )
|
|
221
|
+
Process::Sys.setuid( user.uid.to_i )
|
|
222
|
+
rescue => e
|
|
223
|
+
$stderr.puts "Caught exception while trying to drop user privileges: #{e.message}"
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
end
|
|
230
|
+
end
|