daemon-kit 0.1.7.4 → 0.1.7.5
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/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
|