daemon-kit 0.1.7.4 → 0.1.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Configuration.txt +1 -0
- data/Deployment.txt +113 -0
- data/History.txt +9 -1
- data/Logging.txt +92 -0
- data/Manifest.txt +4 -0
- data/README.rdoc +5 -1
- data/lib/daemon_kit.rb +14 -13
- data/lib/daemon_kit/abstract_logger.rb +235 -0
- data/lib/daemon_kit/application.rb +2 -0
- data/lib/daemon_kit/arguments.rb +11 -1
- data/lib/daemon_kit/initializer.rb +16 -18
- data/spec/abstract_logger_spec.rb +126 -0
- metadata +8 -2
data/Configuration.txt
CHANGED
@@ -29,6 +29,7 @@ DaemonKit includes a couple of its own arguments that can be used:
|
|
29
29
|
|
30
30
|
-e ENV (or --env ENV) to set the daemon environment
|
31
31
|
--pid /path/to/pidfile to set the path to a pidfile
|
32
|
+
-l path (or --log path) to set the path for the log file
|
32
33
|
-v shows the DaemonKit version
|
33
34
|
-h shows a useful help message
|
34
35
|
|
data/Deployment.txt
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
= Deploying your daemons
|
2
|
+
|
3
|
+
daemon-kit provides built-in support for
|
4
|
+
Capistrano[http://www.capify.org] deployments, using a customized
|
5
|
+
version of the standard 'deploy' recipe for Ruby on Rails
|
6
|
+
applications.
|
7
|
+
|
8
|
+
User of Vlad[http://hitsquad.rubyforge.org/vlad/]? Get in touch so we
|
9
|
+
can discuss your contribution to daemon-kit ;)
|
10
|
+
|
11
|
+
== Generating capistrano configurations
|
12
|
+
|
13
|
+
When generating a new daemon, you can pass the <em>-d capistrano</em>
|
14
|
+
argument to the <em>daemon_kit</em> command. In case you already have
|
15
|
+
a generated daemon, run the following command inside your project:
|
16
|
+
|
17
|
+
$ ruby script/generate deploy_capistrano
|
18
|
+
|
19
|
+
== Overview of generated configurations
|
20
|
+
|
21
|
+
The generator creates the following files worth noticing:
|
22
|
+
|
23
|
+
config/deploy.rb
|
24
|
+
config/deploy/*.rb
|
25
|
+
|
26
|
+
The generator also creates a new environment for you, a
|
27
|
+
<em>staging</em> environment. Useful for testing your deployments
|
28
|
+
before taking anything into production.
|
29
|
+
|
30
|
+
== Configuring capistrano
|
31
|
+
|
32
|
+
For each environment (staging & production) you only need to specify
|
33
|
+
the target hosts in <em>config/deploy/(staging|production).rb</em>.
|
34
|
+
|
35
|
+
Each of the stub files have example configuration values you can just
|
36
|
+
edit.
|
37
|
+
|
38
|
+
The rest of your configuration generally occurs in
|
39
|
+
<em>config/deploy.rb</em>.
|
40
|
+
|
41
|
+
Everything works exactly like standard capistrano, with the exception
|
42
|
+
of the following directives:
|
43
|
+
|
44
|
+
* :config_files
|
45
|
+
* :shared_children
|
46
|
+
|
47
|
+
=== :config_files
|
48
|
+
|
49
|
+
Since the daemon configuration files will almost always differ between
|
50
|
+
your development environment and your staging/production environment,
|
51
|
+
the deployment recipe makes adequate provision for this.
|
52
|
+
|
53
|
+
Use the :config_files directive to set an array of file names from the
|
54
|
+
<em>config</em> directory that you want replaced with production
|
55
|
+
configuration files found on the server:
|
56
|
+
|
57
|
+
set :config_files, %w{ amqp.yaml }
|
58
|
+
|
59
|
+
On your target server, in the <em>:deploy_to</em> folder, create a
|
60
|
+
<em>config</em> directory and place your configuration files in
|
61
|
+
there. One each deploy, capistrano will rename the files in your
|
62
|
+
deployed configuration directory with a <em>.orig</em> extension, and copy
|
63
|
+
the files from <em>:deploy_to/config</em> into the newly deployed
|
64
|
+
release.
|
65
|
+
|
66
|
+
This makes it easy to keep production configurations out of your
|
67
|
+
working directories or version control systems.
|
68
|
+
|
69
|
+
=== :shared_children
|
70
|
+
|
71
|
+
The original capistrano recipe that daemon-kit's recipe is built from
|
72
|
+
provided support for tracking shared directories between
|
73
|
+
deployments. This works by removing the deployed directory, and
|
74
|
+
creating a symlink from <em>:deploy_to/shared/</em> into the correct
|
75
|
+
location within the deployed release.
|
76
|
+
|
77
|
+
You specify your list of directories with the
|
78
|
+
<em>:shared_children</em>, each being relative to the DAEMON_ROOT.
|
79
|
+
|
80
|
+
set :shared_children, %w{ log }
|
81
|
+
|
82
|
+
The daemon-kit deployment recipe makes no assumptions on shared
|
83
|
+
directories, and gives you full control. The default only includes the
|
84
|
+
log directory, which you can remove if you want separate log
|
85
|
+
directories for each deployed release.
|
86
|
+
|
87
|
+
== Remote dependencies
|
88
|
+
|
89
|
+
By default, the deployment configuration file is configured to check
|
90
|
+
the remote dependencies before updating the code on the target
|
91
|
+
host. You can disable this behaviour by commenting out the following
|
92
|
+
line:
|
93
|
+
|
94
|
+
before "deploy:update_code", "deploy:check"
|
95
|
+
|
96
|
+
The only default remote dependency is the daemon-kit gem, and it will
|
97
|
+
check for the same version you currently have installed (or a later
|
98
|
+
one).
|
99
|
+
|
100
|
+
== More capistrano resources
|
101
|
+
|
102
|
+
To see a list of available commands, please run the following command
|
103
|
+
in the root of your project:
|
104
|
+
|
105
|
+
$ cap -vT
|
106
|
+
|
107
|
+
For more information on capistrano, please refer to the following list
|
108
|
+
of online resources:
|
109
|
+
|
110
|
+
* Capistrano Website[http://www.capify.org]
|
111
|
+
* Capistrano Wiki[http://wiki.capify.org]
|
112
|
+
* Capistrano Group[http://groups.google.com/group/capistrano]
|
113
|
+
* #capistrano on Freenode
|
data/History.txt
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
== 0.1.7.
|
1
|
+
== 0.1.7.5 2009-06-08
|
2
2
|
|
3
|
+
* New AbstractLogger
|
4
|
+
** Default Logger backend
|
5
|
+
** SysLogLogger support
|
6
|
+
* More documentation
|
7
|
+
|
8
|
+
== 0.1.7.4 2009-06-05
|
9
|
+
|
10
|
+
* Fixed bug with control script generator (thanks Sho Fukamachi)
|
3
11
|
* Enhanced deploy.rb template to check for current dk gem verion,
|
4
12
|
unless vendored
|
5
13
|
* Fix bug in capistrano recipe for restarting daemons
|
data/Logging.txt
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= Logging from inside your daemon
|
2
|
+
|
3
|
+
Proper logging inside your daemon process is critical, and daemon-kit
|
4
|
+
provides you with a great logging facility to (ab)use.
|
5
|
+
|
6
|
+
== Logging examples
|
7
|
+
|
8
|
+
From anywhere in your code you can access the
|
9
|
+
<em>DaemonKit.logger</em> instance, which is a configured
|
10
|
+
DaemonKit::AbstractLogger. It is compatible with Ruby's Logger class
|
11
|
+
but is much more verbose to help you gain some insight into your
|
12
|
+
running process.
|
13
|
+
|
14
|
+
DaemonKit.logger.info( "Hello world" )
|
15
|
+
|
16
|
+
This logs a 'Hello world' line to the log file, complete with the
|
17
|
+
calling file name and line number. Log lines look something like this:
|
18
|
+
|
19
|
+
2009-06-07 23:21:30.248575 capd(32513) [INFO] initializer.rb:91: DaemonKit (0.1.7.4) booted, now running capd
|
20
|
+
|
21
|
+
Log as much as you can, but be careful not to abuse the <em>info</em>
|
22
|
+
level since your log files can become huge. For general processing
|
23
|
+
hints, use the <em>debug</em> level.
|
24
|
+
|
25
|
+
To log exceptions, use the special <em>exception</em> helper:
|
26
|
+
|
27
|
+
begin
|
28
|
+
# dangerous operation
|
29
|
+
rescue => e
|
30
|
+
DaemonKit.logger.exception( e )
|
31
|
+
end
|
32
|
+
|
33
|
+
== Controlling logging in a running process
|
34
|
+
|
35
|
+
Logging can be controlled in a running process, either via code or by
|
36
|
+
sending UNIX signals to the running process.
|
37
|
+
|
38
|
+
=== Changing log levels in your code
|
39
|
+
|
40
|
+
Log levels can be toggled with the <em>level=</em> method:
|
41
|
+
|
42
|
+
DaemonKit.logger.level = :info
|
43
|
+
|
44
|
+
Alternatively you can silence all the logging activity for a while
|
45
|
+
using the silence helper:
|
46
|
+
|
47
|
+
DaemonKit.logger.silence do |logger|
|
48
|
+
# logger will only report :error or higher levels
|
49
|
+
end
|
50
|
+
|
51
|
+
=== Changing log levels via UNIX signals
|
52
|
+
|
53
|
+
Send your process the +USR1+ signal to toggle between <em>:debug</em>
|
54
|
+
and <em>:info</em> log levels. Sending a +USR2+ signal will force the
|
55
|
+
logger into <em>:debug</em> mode (+USR1+ will revert).
|
56
|
+
|
57
|
+
== Support for log rotation
|
58
|
+
|
59
|
+
Support for logrotate is baked right into daemon-kit. By sending your
|
60
|
+
daemon a +HUP+ signal all the log files file be closed and re-opened
|
61
|
+
again on first use. Here is an example logrotate configuration:
|
62
|
+
|
63
|
+
/path/to/daemon.log {
|
64
|
+
rotate 5
|
65
|
+
weekly
|
66
|
+
postrotate
|
67
|
+
kill -HUP `cat /path/to/daemon.pid`
|
68
|
+
endscript
|
69
|
+
}
|
70
|
+
|
71
|
+
== Support for syslog logging
|
72
|
+
|
73
|
+
If you have the
|
74
|
+
SyslogLogger[http://seattlerb.rubyforge.org/SyslogLogger/] gem
|
75
|
+
installed, you can have your process log to a UNIX syslog server. You
|
76
|
+
can change the logging to syslog by either updating your
|
77
|
+
<em>environment.rb</em> file like this:
|
78
|
+
|
79
|
+
config.log_path = :syslog
|
80
|
+
|
81
|
+
Or by passing 'syslog' as the logfile argument when starting a daemon
|
82
|
+
|
83
|
+
$ ruby ./bin/daemon start -l syslog
|
84
|
+
|
85
|
+
The SyslogLogger rdoc's provide configuration examples for configuring
|
86
|
+
various UNIX syslog servers.
|
87
|
+
|
88
|
+
== More logging information
|
89
|
+
|
90
|
+
If you're running your daemon in the foreground (with the <em>run</em>
|
91
|
+
command, you'll get copies of all the log messages on STDOUT, and thus
|
92
|
+
voiding the need to tail log files the whole time.
|
data/Manifest.txt
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
Configuration.txt
|
2
|
+
Deployment.txt
|
2
3
|
History.txt
|
4
|
+
Logging.txt
|
3
5
|
Manifest.txt
|
4
6
|
PostInstall.txt
|
5
7
|
README.rdoc
|
@@ -52,6 +54,7 @@ daemon_generators/nanite_agent/templates/config/nanite.yml
|
|
52
54
|
daemon_generators/nanite_agent/templates/lib/actors/sample.rb
|
53
55
|
daemon_generators/nanite_agent/templates/libexec/daemon.rb
|
54
56
|
lib/daemon_kit.rb
|
57
|
+
lib/daemon_kit/abstract_logger.rb
|
55
58
|
lib/daemon_kit/amqp.rb
|
56
59
|
lib/daemon_kit/application.rb
|
57
60
|
lib/daemon_kit/arguments.rb
|
@@ -87,6 +90,7 @@ script/console
|
|
87
90
|
script/destroy
|
88
91
|
script/generate
|
89
92
|
script/txt2html
|
93
|
+
spec/abstract_logger_spec.rb
|
90
94
|
spec/argument_spec.rb
|
91
95
|
spec/config_spec.rb
|
92
96
|
spec/daemon_kit_spec.rb
|
data/README.rdoc
CHANGED
@@ -21,7 +21,6 @@ Supported generators:
|
|
21
21
|
|
22
22
|
* Build it
|
23
23
|
* Review TODO.txt
|
24
|
-
* Review Configuration.txt
|
25
24
|
|
26
25
|
== Synopsis
|
27
26
|
|
@@ -80,6 +79,11 @@ Stable versions, when released are available directly from Rubyforge:
|
|
80
79
|
|
81
80
|
$ gem install daemon-kit
|
82
81
|
|
82
|
+
== Further reading
|
83
|
+
|
84
|
+
* Configuration.txt
|
85
|
+
* Deployment.txt
|
86
|
+
|
83
87
|
== License
|
84
88
|
|
85
89
|
(The MIT License)
|
data/lib/daemon_kit.rb
CHANGED
@@ -7,19 +7,20 @@ $:.unshift( File.dirname(__FILE__).to_absolute_path ) unless
|
|
7
7
|
$:.include?( File.dirname(__FILE__).to_absolute_path )
|
8
8
|
|
9
9
|
module DaemonKit
|
10
|
-
VERSION = '0.1.7.
|
11
|
-
|
12
|
-
autoload :Initializer,
|
13
|
-
autoload :Application,
|
14
|
-
autoload :Arguments,
|
15
|
-
autoload :Config,
|
16
|
-
autoload :Safety,
|
17
|
-
autoload :PidFile,
|
18
|
-
|
19
|
-
|
20
|
-
autoload :
|
21
|
-
autoload :
|
22
|
-
autoload :
|
10
|
+
VERSION = '0.1.7.5'
|
11
|
+
|
12
|
+
autoload :Initializer, 'daemon_kit/initializer'
|
13
|
+
autoload :Application, 'daemon_kit/application'
|
14
|
+
autoload :Arguments, 'daemon_kit/arguments'
|
15
|
+
autoload :Config, 'daemon_kit/config'
|
16
|
+
autoload :Safety, 'daemon_kit/safety'
|
17
|
+
autoload :PidFile, 'daemon_kit/pid_file'
|
18
|
+
autoload :AbstractLogger, 'daemon_kit/abstract_logger'
|
19
|
+
|
20
|
+
autoload :Cron, 'daemon_kit/cron'
|
21
|
+
autoload :Jabber, 'daemon_kit/jabber'
|
22
|
+
autoload :AMQP, 'daemon_kit/amqp'
|
23
|
+
autoload :Nanite, 'daemon_kit/nanite'
|
23
24
|
|
24
25
|
class << self
|
25
26
|
def logger
|
@@ -0,0 +1,235 @@
|
|
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
|
+
def debug( msg )
|
67
|
+
add( :debug, msg )
|
68
|
+
end
|
69
|
+
|
70
|
+
def debug?
|
71
|
+
self.level == :debug
|
72
|
+
end
|
73
|
+
|
74
|
+
def info( msg )
|
75
|
+
add( :info, msg )
|
76
|
+
end
|
77
|
+
|
78
|
+
def info?
|
79
|
+
self.level == :info
|
80
|
+
end
|
81
|
+
|
82
|
+
def warn( msg )
|
83
|
+
add( :warn, msg )
|
84
|
+
end
|
85
|
+
|
86
|
+
def warn?
|
87
|
+
self.level == :warn
|
88
|
+
end
|
89
|
+
|
90
|
+
def error( msg )
|
91
|
+
add( :error, msg )
|
92
|
+
end
|
93
|
+
|
94
|
+
def error?
|
95
|
+
self.level == :error
|
96
|
+
end
|
97
|
+
|
98
|
+
def fatal( msg )
|
99
|
+
add( :fatal, msg )
|
100
|
+
end
|
101
|
+
|
102
|
+
def fatal?
|
103
|
+
self.level == :fatal
|
104
|
+
end
|
105
|
+
|
106
|
+
def unknown( msg )
|
107
|
+
add( :unknown, msg )
|
108
|
+
end
|
109
|
+
|
110
|
+
def unknown?
|
111
|
+
self.level == :unknown
|
112
|
+
end
|
113
|
+
|
114
|
+
def exception( e )
|
115
|
+
message = "EXCEPTION: #{e.message}: #{clean_trace( e.backtrace )}"
|
116
|
+
self.add( :error, message, true )
|
117
|
+
end
|
118
|
+
|
119
|
+
def add( severity, message, skip_caller = false )
|
120
|
+
message = "#{called(caller)}: #{message}" unless skip_caller
|
121
|
+
|
122
|
+
self.logger.add( self.class.severities[ severity ] ) { message }
|
123
|
+
|
124
|
+
STDOUT.puts( message ) if self.copy_to_stdout
|
125
|
+
end
|
126
|
+
|
127
|
+
def level
|
128
|
+
self.class.severities.invert[ @logger.level ]
|
129
|
+
end
|
130
|
+
|
131
|
+
def level=( level )
|
132
|
+
level = ( Symbol === level ? self.class.severities[ level ] : level )
|
133
|
+
self.logger.level = level
|
134
|
+
end
|
135
|
+
|
136
|
+
def logger
|
137
|
+
@logger ||= create_logger
|
138
|
+
end
|
139
|
+
|
140
|
+
def logger=( logger )
|
141
|
+
if logger.is_a?( Symbol )
|
142
|
+
@backend = logger
|
143
|
+
@logger.close rescue nil
|
144
|
+
@logger = create_logger
|
145
|
+
else
|
146
|
+
@logger.close rescue nil
|
147
|
+
@logger = logger
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def clean_trace( trace )
|
152
|
+
trace = trace.map { |l| l.gsub(DAEMON_ROOT, '') }
|
153
|
+
trace = trace.reject { |l| l =~ /gems\/daemon[\-_]kit/ }
|
154
|
+
trace = trace.reject { |l| l =~ /vendor\/daemon[\-_]kit/ }
|
155
|
+
trace
|
156
|
+
end
|
157
|
+
|
158
|
+
def close
|
159
|
+
case @backend
|
160
|
+
when :logger
|
161
|
+
self.logger.close
|
162
|
+
@logger = nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def called( trace )
|
169
|
+
l = trace.detect('unknown:0') { |l| l.index('abstract_logger.rb').nil? }
|
170
|
+
file, num, _ = l.split(':')
|
171
|
+
|
172
|
+
[ File.basename(file), num ].join(':')
|
173
|
+
end
|
174
|
+
|
175
|
+
def create_logger
|
176
|
+
case @backend
|
177
|
+
when :logger
|
178
|
+
create_standard_logger
|
179
|
+
when :syslog
|
180
|
+
create_syslog_logger
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def create_standard_logger
|
185
|
+
log_path = File.dirname( @logger_file )
|
186
|
+
unless File.directory?( log_path )
|
187
|
+
begin
|
188
|
+
FileUtils.mkdir_p( log_path )
|
189
|
+
rescue
|
190
|
+
STDERR.puts "#{log_path} not writable, using STDERR for logging"
|
191
|
+
@logger_file = STDERR
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
l = Logger.new( @logger_file )
|
196
|
+
l.formatter = Formatter.new
|
197
|
+
l.progname = if DaemonKit.configuration
|
198
|
+
DaemonKit.configuration.daemon_name
|
199
|
+
else
|
200
|
+
File.basename($0)
|
201
|
+
end
|
202
|
+
l
|
203
|
+
end
|
204
|
+
|
205
|
+
def create_syslog_logger
|
206
|
+
begin
|
207
|
+
require 'syslog_logger'
|
208
|
+
SyslogLogger.new( DaemonKit.configuration ? DaemonKit.configuration.daemon_name : File.basename($0) )
|
209
|
+
rescue LoadError
|
210
|
+
self.logger = :logger
|
211
|
+
self.error( "Couldn't load syslog_logger gem, reverting to standard logger" )
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class Formatter
|
216
|
+
|
217
|
+
# YYYY:MM:DD HH:MM:SS.MS daemon_name(pid) level: message
|
218
|
+
@format = "%s %s(%d) [%s] %s\n"
|
219
|
+
|
220
|
+
class << self
|
221
|
+
attr_accessor :format
|
222
|
+
end
|
223
|
+
|
224
|
+
def call(severity, time, progname, msg)
|
225
|
+
self.class.format % [ format_time( time ), progname, $$, severity, msg.to_s ]
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
def format_time( time )
|
231
|
+
time.strftime( "%Y-%m-%d %H:%M:%S." ) + time.usec.to_s
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
data/lib/daemon_kit/arguments.rb
CHANGED
@@ -58,6 +58,7 @@ module DaemonKit
|
|
58
58
|
#
|
59
59
|
# -e value or --env value => environment
|
60
60
|
# --pid pidfile => pid_file
|
61
|
+
# -l path or --log path => /path/to/log/file
|
61
62
|
#
|
62
63
|
def configuration( argv )
|
63
64
|
configs = []
|
@@ -74,6 +75,11 @@ module DaemonKit
|
|
74
75
|
configs << "environment=#{argv.delete_at(i)}"
|
75
76
|
end
|
76
77
|
|
78
|
+
if argv[i] == "-l" || argv[i] == "--log"
|
79
|
+
argv.delete_at( i )
|
80
|
+
configs << "log_path=#{argv.delete_at(i)}"
|
81
|
+
end
|
82
|
+
|
77
83
|
if argv[i] == "--pid"
|
78
84
|
argv.delete_at( i )
|
79
85
|
configs << "pid_file=#{argv.delete_at(i)}"
|
@@ -92,7 +98,7 @@ module DaemonKit
|
|
92
98
|
end
|
93
99
|
|
94
100
|
attr_reader :options
|
95
|
-
|
101
|
+
|
96
102
|
def initialize
|
97
103
|
@options = {}
|
98
104
|
|
@@ -121,6 +127,10 @@ module DaemonKit
|
|
121
127
|
# Nothing, just here for show
|
122
128
|
end
|
123
129
|
|
130
|
+
opts.on("-l", "--log /path/to/logfile", "Path to the log file", "Defaults to log/[environment].log") do
|
131
|
+
# Nothing, just here for show
|
132
|
+
end
|
133
|
+
|
124
134
|
opts.separator ""
|
125
135
|
opts.separator "Advanced configurations:"
|
126
136
|
opts.on("--config ATTRIBUTE=VALUE",
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'logger'
|
2
1
|
require 'pathname'
|
3
2
|
|
4
3
|
DAEMON_ENV = (ENV['DAEMON_ENV'] || 'development').dup unless defined?(DAEMON_ENV)
|
@@ -135,8 +134,9 @@ module DaemonKit
|
|
135
134
|
return if DaemonKit.logger
|
136
135
|
|
137
136
|
unless logger = configuration.logger
|
138
|
-
logger =
|
137
|
+
logger = AbstractLogger.new( configuration.log_path )
|
139
138
|
logger.level = configuration.log_level
|
139
|
+
logger.copy_to_stdout = configuration.log_stdout
|
140
140
|
end
|
141
141
|
|
142
142
|
DaemonKit.logger = logger
|
@@ -144,13 +144,16 @@ module DaemonKit
|
|
144
144
|
DaemonKit.logger.info "DaemonKit (#{DaemonKit::VERSION}) booting in #{DAEMON_ENV} mode"
|
145
145
|
|
146
146
|
configuration.trap("USR1") {
|
147
|
-
DaemonKit.logger.level = DaemonKit.logger.debug? ?
|
147
|
+
DaemonKit.logger.level = DaemonKit.logger.debug? ? :info : :debug
|
148
148
|
DaemonKit.logger.info "Log level changed to #{DaemonKit.logger.debug? ? 'DEBUG' : 'INFO' }"
|
149
149
|
}
|
150
150
|
configuration.trap("USR2") {
|
151
|
-
DaemonKit.logger.level =
|
151
|
+
DaemonKit.logger.level = :debug
|
152
152
|
DaemonKit.logger.info "Log level changed to DEBUG"
|
153
153
|
}
|
154
|
+
configuration.trap("HUP") {
|
155
|
+
DaemonKit.logger.close
|
156
|
+
}
|
154
157
|
end
|
155
158
|
|
156
159
|
def initialize_signal_traps
|
@@ -178,14 +181,17 @@ module DaemonKit
|
|
178
181
|
# List of load paths
|
179
182
|
attr_accessor :load_paths
|
180
183
|
|
184
|
+
# Custom logger instance to use
|
185
|
+
attr_accessor :logger
|
186
|
+
|
181
187
|
# The log level to use, defaults to DEBUG
|
182
188
|
attr_accessor :log_level
|
183
189
|
|
184
190
|
# Path to the log file, defaults to 'log/<environment>.log'
|
185
191
|
attr_accessor :log_path
|
186
192
|
|
187
|
-
#
|
188
|
-
attr_accessor :
|
193
|
+
# Duplicate log data to stdout
|
194
|
+
attr_accessor :log_stdout
|
189
195
|
|
190
196
|
# Path to the pid file, defaults to 'log/<daemon_name>.pid'
|
191
197
|
attr_accessor :pid_file
|
@@ -209,8 +215,8 @@ module DaemonKit
|
|
209
215
|
set_daemon_defaults!
|
210
216
|
|
211
217
|
self.load_paths = default_load_paths
|
212
|
-
self.log_level
|
213
|
-
self.log_path
|
218
|
+
self.log_level ||= default_log_level
|
219
|
+
self.log_path ||= default_log_path
|
214
220
|
|
215
221
|
self.force_kill_wait = false
|
216
222
|
|
@@ -299,21 +305,13 @@ module DaemonKit
|
|
299
305
|
raise "DAEMON_ROOT is not a directory" unless File.directory?(::DAEMON_ROOT)
|
300
306
|
|
301
307
|
@root_path = ::DAEMON_ROOT.to_absolute_path
|
302
|
-
# Pathname is incompatible with Windows, but Windows doesn't have
|
303
|
-
# real symlinks so File.expand_path is safe.
|
304
|
-
#if RUBY_PLATFORM =~ /(:?mswin|mingw)/
|
305
|
-
# File.expand_path(::DAEMON_ROOT)
|
306
|
-
|
307
|
-
# Otherwise use Pathname#realpath which respects symlinks.
|
308
|
-
#else
|
309
|
-
# File.expand_path( Pathname.new(::DAEMON_ROOT).realpath.to_s )
|
310
|
-
#end
|
311
308
|
|
312
309
|
Object.const_set(:RELATIVE_DAEMON_ROOT, ::DAEMON_ROOT.dup) unless defined?(::RELATIVE_DAEMON_ROOT)
|
313
310
|
::DAEMON_ROOT.replace @root_path
|
314
311
|
end
|
315
312
|
|
316
313
|
def set_daemon_defaults!
|
314
|
+
self.log_stdout = false
|
317
315
|
end
|
318
316
|
|
319
317
|
def default_load_paths
|
@@ -325,7 +323,7 @@ module DaemonKit
|
|
325
323
|
end
|
326
324
|
|
327
325
|
def default_log_level
|
328
|
-
environment == 'production' ?
|
326
|
+
environment == 'production' ? :info : :debug
|
329
327
|
end
|
330
328
|
|
331
329
|
def error( msg )
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe DaemonKit::AbstractLogger do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@log_file = "#{DAEMON_ROOT}/log/spec.log"
|
7
|
+
@logger = DaemonKit::AbstractLogger.new( @log_file )
|
8
|
+
@logger.level = :debug
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have a log level" do
|
12
|
+
@logger.level.should == :debug
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a backend logger" do
|
16
|
+
@logger.logger.should_not be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should accept a different backend" do
|
20
|
+
l = Logger.new('/dev/null')
|
21
|
+
@logger.logger = l
|
22
|
+
@logger.logger.should == l
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be able to log to STDOUT as well" do
|
26
|
+
@logger.copy_to_stdout = true
|
27
|
+
|
28
|
+
STDOUT.expects(:puts).with(regexp_matches(/test/))
|
29
|
+
|
30
|
+
@logger.debug "test"
|
31
|
+
IO.readlines( @log_file ).last.should match(/test/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should log debug level messages" do
|
35
|
+
@logger.debug( "Debug test" )
|
36
|
+
|
37
|
+
IO.readlines( @log_file ).last.should match(/\[DEBUG\].*Debug test/)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should log info level messages" do
|
41
|
+
@logger.info( "Info test" )
|
42
|
+
|
43
|
+
IO.readlines( @log_file ).last.should match(/\[INFO\].*Info test/)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should log warn level messages" do
|
47
|
+
@logger.warn( "Warn test" )
|
48
|
+
|
49
|
+
IO.readlines( @log_file ).last.should match(/\[WARN\].*Warn test/)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should log error level messages" do
|
53
|
+
@logger.error( "Err test" )
|
54
|
+
|
55
|
+
IO.readlines( @log_file ).last.should match(/\[ERROR\].*Err test/)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should log fatal level messages" do
|
59
|
+
@logger.fatal( "Fatal test" )
|
60
|
+
|
61
|
+
IO.readlines( @log_file ).last.should match(/\[FATAL\].*Fatal test/)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should log unknown level messages" do
|
65
|
+
@logger.unknown( "Unknown test" )
|
66
|
+
|
67
|
+
IO.readlines( @log_file ).last.should match(/\[ANY\].*Unknown test/)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should log the caller file and line number" do
|
71
|
+
f = File.basename(__FILE__)
|
72
|
+
l = __LINE__ + 2
|
73
|
+
|
74
|
+
@logger.info( "Caller test" )
|
75
|
+
|
76
|
+
IO.readlines( @log_file ).last.should match(/#{f}:#{l}:/)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should log exceptions with daemon traces" do
|
80
|
+
fake_trace = [
|
81
|
+
"/home/kenneth/daemon/libexec/daemon-daemon.rb:1:in `foo'",
|
82
|
+
"/usr/lib/ruby/gems/1.8/gems/daemon-kit-0.0.1/lib/daemon_kit/abstract_logger.rb:49: in `info'"
|
83
|
+
]
|
84
|
+
|
85
|
+
e = RuntimeError.new( 'Test error' )
|
86
|
+
e.set_backtrace( fake_trace )
|
87
|
+
|
88
|
+
@logger.exception( e )
|
89
|
+
|
90
|
+
IO.readlines( @log_file ).last.should match(/EXCEPTION: Test error/)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should log exceptions without framework traces" do
|
94
|
+
fake_trace = [
|
95
|
+
"/home/kenneth/daemon/libexec/daemon-daemon.rb:1:in `foo'",
|
96
|
+
"/usr/lib/ruby/gems/1.8/gems/daemon-kit-0.0.1/lib/daemon_kit/abstract_logger.rb:49: in `info'"
|
97
|
+
]
|
98
|
+
|
99
|
+
clean_trace = @logger.clean_trace( fake_trace )
|
100
|
+
|
101
|
+
clean_trace.should include("/home/kenneth/daemon/libexec/daemon-daemon.rb:1:in `foo'")
|
102
|
+
clean_trace.should_not include("/usr/lib/ruby/gems/1.8/gems/daemon-kit-0.0.1/lib/daemon_kit/abstract_logger.rb:49: in `info'")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should support reopening log files" do
|
106
|
+
@logger.close
|
107
|
+
|
108
|
+
FileUtils.rm( @log_file )
|
109
|
+
|
110
|
+
@logger.info( 'Reopen')
|
111
|
+
IO.readlines( @log_file ).last.should match(/Reopen/)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should support silencing" do
|
115
|
+
@logger.silence do |logger|
|
116
|
+
logger.info "This should never be logged"
|
117
|
+
end
|
118
|
+
|
119
|
+
@logger.info "This should be logged"
|
120
|
+
|
121
|
+
log = IO.readlines( @log_file )
|
122
|
+
|
123
|
+
log.detect { |l| l =~ /This should never be logged/ }.should be_nil
|
124
|
+
log.detect { |l| l =~ /This should be logged/ }.should_not be_nil
|
125
|
+
end
|
126
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daemon-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.7.
|
4
|
+
version: 0.1.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenneth Kalmer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-08 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -51,14 +51,18 @@ extensions: []
|
|
51
51
|
|
52
52
|
extra_rdoc_files:
|
53
53
|
- Configuration.txt
|
54
|
+
- Deployment.txt
|
54
55
|
- History.txt
|
56
|
+
- Logging.txt
|
55
57
|
- Manifest.txt
|
56
58
|
- PostInstall.txt
|
57
59
|
- README.rdoc
|
58
60
|
- TODO.txt
|
59
61
|
files:
|
60
62
|
- Configuration.txt
|
63
|
+
- Deployment.txt
|
61
64
|
- History.txt
|
65
|
+
- Logging.txt
|
62
66
|
- Manifest.txt
|
63
67
|
- PostInstall.txt
|
64
68
|
- README.rdoc
|
@@ -111,6 +115,7 @@ files:
|
|
111
115
|
- daemon_generators/nanite_agent/templates/lib/actors/sample.rb
|
112
116
|
- daemon_generators/nanite_agent/templates/libexec/daemon.rb
|
113
117
|
- lib/daemon_kit.rb
|
118
|
+
- lib/daemon_kit/abstract_logger.rb
|
114
119
|
- lib/daemon_kit/amqp.rb
|
115
120
|
- lib/daemon_kit/application.rb
|
116
121
|
- lib/daemon_kit/arguments.rb
|
@@ -146,6 +151,7 @@ files:
|
|
146
151
|
- script/destroy
|
147
152
|
- script/generate
|
148
153
|
- script/txt2html
|
154
|
+
- spec/abstract_logger_spec.rb
|
149
155
|
- spec/argument_spec.rb
|
150
156
|
- spec/config_spec.rb
|
151
157
|
- spec/daemon_kit_spec.rb
|