droid 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/conf +31 -0
- data/lib/droid.rb +531 -0
- data/lib/droid/sync.rb +0 -0
- data/lib/heroku_droid.rb +86 -0
- data/lib/local_stats.rb +143 -0
- data/lib/memcache_cluster.rb +127 -0
- data/lib/stats.rb +30 -0
- data/lib/utilization.rb +90 -0
- data/speaker/droid_speaker.rb +79 -0
- data/speaker/speak +33 -0
- data/speaker/test.rb +58 -0
- data/test/base.rb +43 -0
- data/test/droid_test.rb +53 -0
- data/test/heroku_droid_test.rb +42 -0
- data/test/wait_for_port_test.rb +23 -0
- data/vendor/logger_client/Rakefile +53 -0
- data/vendor/logger_client/init.rb +1 -0
- data/vendor/logger_client/lib/logger_client.rb +210 -0
- data/vendor/logger_client/test.rb +18 -0
- metadata +115 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../vendor/json_pure-1.1.3/lib'
|
2
|
+
require 'json'
|
3
|
+
require 'drb'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
class DroidSpeaker
|
7
|
+
|
8
|
+
def self.drb_connect(port)
|
9
|
+
DRb.start_service()
|
10
|
+
@drb = DRbObject.new(nil,"druby://localhost:#{port}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.drb_cast(topic, payload, &p)
|
14
|
+
@drb.publish(topic, payload, &p)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.drb_call(topic, payload)
|
18
|
+
## this is the best stupid trick I could think of the force blocking
|
19
|
+
lock = Thread.new { sleep 9999 }
|
20
|
+
@r = nil
|
21
|
+
@drb.publish(topic, payload) do |result|
|
22
|
+
@r = result
|
23
|
+
lock.kill
|
24
|
+
end
|
25
|
+
lock.join
|
26
|
+
@r
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.send(topic, payload, &p)
|
30
|
+
i = new
|
31
|
+
i.send(topic, payload, &p)
|
32
|
+
i.flush
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.start
|
36
|
+
i = new
|
37
|
+
yield(i)
|
38
|
+
i.flush
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@message = nil
|
43
|
+
@callback = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def send(topic, payload, &blk)
|
47
|
+
if defined?(Log) and event_id = Log.default_options[:event_id]
|
48
|
+
payload.merge!(:event_hash => event_id)
|
49
|
+
end
|
50
|
+
|
51
|
+
attrs = { :topic => topic, :payload => payload }
|
52
|
+
if blk # this message should be replied
|
53
|
+
attrs.merge!(:has_reply => true)
|
54
|
+
@callback = blk
|
55
|
+
end
|
56
|
+
@message = attrs
|
57
|
+
end
|
58
|
+
|
59
|
+
class MessageError < RuntimeError; end
|
60
|
+
|
61
|
+
def flush
|
62
|
+
out = ''
|
63
|
+
IO.popen("#{File.dirname(__FILE__)}/../speaker/speak 2>/dev/null", 'w+') do |io|
|
64
|
+
io.puts @message.to_json
|
65
|
+
out = io.read
|
66
|
+
end
|
67
|
+
begin
|
68
|
+
response = JSON.parse(out)
|
69
|
+
response.delete('event_hash')
|
70
|
+
@callback.call(response) if @callback
|
71
|
+
rescue JSON::ParserError
|
72
|
+
if out.include?('Timeout::Error')
|
73
|
+
raise Timeout::Error, "Timed out while waiting for a response for #{@message[:topic]}"
|
74
|
+
else
|
75
|
+
raise MessageError, out
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/speaker/speak
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
$:.unshift '/usr/local/droid/lib'
|
5
|
+
require 'heroku_droid'
|
6
|
+
|
7
|
+
msg = JSON.load(gets)
|
8
|
+
|
9
|
+
Timeout.timeout(10) do
|
10
|
+
HerokuDroid.new('Droid Speaker', :standard_topics => false) do |droid|
|
11
|
+
if msg['has_reply']
|
12
|
+
@event_hash = msg['payload']['event_hash'] ||= Droid::Basic.new(droid).event_hash
|
13
|
+
droid.listen4('event.error') do |d|
|
14
|
+
if d.headers[:event_hash] == @event_hash
|
15
|
+
puts "Message #{msg['topic']} failed: see event #{@event_hash}"
|
16
|
+
Droid.stop_safe
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
droid.publish(msg['topic'], msg['payload']) do |d|
|
21
|
+
puts d.params.to_json
|
22
|
+
Droid.stop_safe
|
23
|
+
end
|
24
|
+
else
|
25
|
+
droid.publish(msg['topic'], msg['payload'])
|
26
|
+
puts({}.to_json)
|
27
|
+
Droid.stop_safe
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
rescue Object => e
|
32
|
+
puts "#{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
33
|
+
end
|
data/speaker/test.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Thread.new do
|
2
|
+
require File.dirname(__FILE__) + '/../lib/heroku_droid'
|
3
|
+
HerokuDroid.new('Droid speaker test') do |droid|
|
4
|
+
droid.listen4('speaker.test') do |msg|
|
5
|
+
if msg['marco'] == 1
|
6
|
+
puts "Got 'marco', returning 'polo'..."
|
7
|
+
msg.reply('polo' => 1)
|
8
|
+
else
|
9
|
+
puts "Bad payload"
|
10
|
+
msg.reply('error' => 1)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
droid.listen4('speaker.raise') do |msg|
|
14
|
+
raise "droid raised exception"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sleep 2
|
20
|
+
|
21
|
+
require File.dirname(__FILE__) + '/droid_speaker'
|
22
|
+
|
23
|
+
puts "\nTest 1: Sending simple message"
|
24
|
+
DroidSpeaker.send('fire.and.forget', 'val' => 1)
|
25
|
+
puts "\tSuccess!"
|
26
|
+
|
27
|
+
puts "\nTest 2: Sending and receiving response"
|
28
|
+
DroidSpeaker.send('speaker.test', 'marco' => 1) do |r|
|
29
|
+
if r['polo'] == 1
|
30
|
+
puts "\tSuccess!"
|
31
|
+
else
|
32
|
+
puts "\tFailed, result: #{r.inspect}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "\nTest 3: Exceptions"
|
37
|
+
begin
|
38
|
+
DroidSpeaker.send('speaker.raise', {}) do |r|
|
39
|
+
puts "\tFailed, expected exception"
|
40
|
+
end
|
41
|
+
rescue DroidSpeaker::MessageError => e
|
42
|
+
if e.message =~ /event \w+/
|
43
|
+
puts "\tSuccess!"
|
44
|
+
else
|
45
|
+
puts "\tFailed, droid speaker raised #{e.message}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
puts "\nTest 4: Timeout"
|
50
|
+
begin
|
51
|
+
DroidSpeaker.send('dont.reply', {}) do |r|
|
52
|
+
puts "\tFailed, didnt expect a response"
|
53
|
+
end
|
54
|
+
rescue Timeout::Error
|
55
|
+
puts "\tSuccess!"
|
56
|
+
rescue Exception => e
|
57
|
+
puts "\tFailed, expected Timeout::Error, got #{e.class.name}"
|
58
|
+
end
|
data/test/base.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rush'
|
2
|
+
|
3
|
+
def publish(message, payload={})
|
4
|
+
Droid.new('Sender', RabbitmqSetup.credentials) do |d|
|
5
|
+
d.publish(message, payload)
|
6
|
+
Droid.stop_safe
|
7
|
+
end
|
8
|
+
sleep(0.1)
|
9
|
+
end
|
10
|
+
|
11
|
+
$exchange = nil
|
12
|
+
$mutex = Mutex.new
|
13
|
+
def exchange
|
14
|
+
$mutex.synchronize { $exchange }
|
15
|
+
end
|
16
|
+
def save_in_exchange(v)
|
17
|
+
$mutex.synchronize { $exchange = v }
|
18
|
+
end
|
19
|
+
|
20
|
+
module RabbitmqSetup
|
21
|
+
extend self
|
22
|
+
|
23
|
+
def credentials
|
24
|
+
{
|
25
|
+
:vhost => '/test',
|
26
|
+
:host => 'localhost',
|
27
|
+
:user => 'test',
|
28
|
+
:pass => 'test'
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_rabbitmqctl(command)
|
33
|
+
Rush::Box.new.bash "rabbitmqctl #{command}"
|
34
|
+
rescue Rush::BashFailed => e
|
35
|
+
raise unless e.message.match(/already_exists/)
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
run_rabbitmqctl("add_vhost #{credentials[:vhost]}")
|
40
|
+
run_rabbitmqctl("add_user #{credentials[:user]} #{credentials[:pass]}")
|
41
|
+
run_rabbitmqctl("map_user_vhost #{credentials[:user]} #{credentials[:vhost]}")
|
42
|
+
end
|
43
|
+
end
|
data/test/droid_test.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/droid'
|
2
|
+
require File.dirname(__FILE__) + '/base'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'thread'
|
6
|
+
require 'bacon'
|
7
|
+
|
8
|
+
RabbitmqSetup.run
|
9
|
+
|
10
|
+
Bacon.summary_on_exit
|
11
|
+
|
12
|
+
Thread.new do
|
13
|
+
Droid.new('Test Droid', RabbitmqSetup.credentials) do |d|
|
14
|
+
d.on_error do |msg, e|
|
15
|
+
save_in_exchange(e)
|
16
|
+
end
|
17
|
+
|
18
|
+
d.before_filter do |msg|
|
19
|
+
if to_save = msg[:save_in_before_filter]
|
20
|
+
save_in_exchange(to_save)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
d.listen4('save.msg') do |msg|
|
25
|
+
save_in_exchange(msg)
|
26
|
+
end
|
27
|
+
|
28
|
+
d.listen4('do.nothing') do |msg|
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
sleep(2) # wait until droid is up
|
34
|
+
describe Droid do
|
35
|
+
before do
|
36
|
+
save_in_exchange(nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sends and receives simple messages" do
|
40
|
+
publish('save.msg')
|
41
|
+
exchange.should.not == nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "sends messages with params" do
|
45
|
+
publish('save.msg', :test => 1)
|
46
|
+
exchange[:test].should == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
it "accepts before filters" do
|
50
|
+
publish('do.nothing', :save_in_before_filter => 42)
|
51
|
+
exchange.should == 42
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/heroku_droid'
|
2
|
+
require File.dirname(__FILE__) + '/base'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'thread'
|
6
|
+
require 'bacon'
|
7
|
+
|
8
|
+
Bacon.summary_on_exit
|
9
|
+
|
10
|
+
Thread.new do
|
11
|
+
HerokuDroid.new('Test Heroku Droid') do |d|
|
12
|
+
d.stats do
|
13
|
+
"some stats"
|
14
|
+
end
|
15
|
+
|
16
|
+
d.listen4('pong') do |msg|
|
17
|
+
save_in_exchange('worked') if msg['notes'] == 'some stats'
|
18
|
+
end
|
19
|
+
|
20
|
+
d.listen4('save.msg') do |msg|
|
21
|
+
save_in_exchange(msg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
sleep(2) # wait until droid is up
|
27
|
+
describe HerokuDroid do
|
28
|
+
before do
|
29
|
+
save_in_exchange(nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sends and receives simple messages" do
|
33
|
+
publish('save.msg')
|
34
|
+
exchange.should.not == nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "responds to ping with a pong message and instances/droid stats filled in" do
|
38
|
+
publish('ping')
|
39
|
+
sleep 3
|
40
|
+
exchange.should == 'worked'
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/droid'
|
2
|
+
require File.dirname(__FILE__) + '/base'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'thread'
|
6
|
+
require 'bacon'
|
7
|
+
|
8
|
+
Bacon.summary_on_exit
|
9
|
+
|
10
|
+
Thread.new do
|
11
|
+
sleep 2
|
12
|
+
TCPServer.new('localhost', 20_001).accept.close
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Droid do
|
16
|
+
it "waits for the rabbitmq server to come up before opening the amqp connection" do
|
17
|
+
start = Time.now
|
18
|
+
Droid.wait_for_tcp_port('localhost', 20_001)
|
19
|
+
finish = Time.now
|
20
|
+
(finish - start).should > 1
|
21
|
+
(finish - start).should < 3
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc "Run all specs"
|
5
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
6
|
+
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
7
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
12
|
+
###
|
13
|
+
|
14
|
+
require 'rake'
|
15
|
+
require 'rake/testtask'
|
16
|
+
require 'rake/clean'
|
17
|
+
require 'rake/gempackagetask'
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
require 'fileutils'
|
20
|
+
|
21
|
+
version = "0.1"
|
22
|
+
name = "logger_client"
|
23
|
+
|
24
|
+
spec = Gem::Specification.new do |s|
|
25
|
+
s.name = name
|
26
|
+
s.version = version
|
27
|
+
s.summary = "Client for Heroku logger"
|
28
|
+
s.author = "Pedro Belo"
|
29
|
+
s.email = "pedro@heroku.com"
|
30
|
+
|
31
|
+
s.platform = Gem::Platform::RUBY
|
32
|
+
s.has_rdoc = false
|
33
|
+
|
34
|
+
s.files = %w(Rakefile init.rb) + Dir.glob("{lib,spec}/**/*")
|
35
|
+
|
36
|
+
s.require_path = "lib"
|
37
|
+
|
38
|
+
s.add_dependency('rest-client', '>=0.6.2')
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::GemPackageTask.new(spec) do |p|
|
42
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
43
|
+
end
|
44
|
+
|
45
|
+
task :install => [ :package ] do
|
46
|
+
sh %{sudo gem install pkg/#{name}-#{version}.gem}
|
47
|
+
end
|
48
|
+
|
49
|
+
task :uninstall => [ :clean ] do
|
50
|
+
sh %{sudo gem uninstall #{name}}
|
51
|
+
end
|
52
|
+
|
53
|
+
CLEAN.include [ 'pkg', '*.gem', '.config' ]
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/logger_client'
|
@@ -0,0 +1,210 @@
|
|
1
|
+
# Logger Client
|
2
|
+
# Use as a gem or Rails plugin. Example configuration:
|
3
|
+
#
|
4
|
+
# Log.configure do |config|
|
5
|
+
# config.component = 'core'
|
6
|
+
# config.instance = 'userapps.123'
|
7
|
+
# config.failsafe = :file
|
8
|
+
# end
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'time'
|
12
|
+
require 'syslog'
|
13
|
+
|
14
|
+
module Log; end
|
15
|
+
|
16
|
+
class Log::InvalidConfiguration < RuntimeError
|
17
|
+
def message
|
18
|
+
"Invalid component. Configure with Log.configure { |c| c.component = 'myComponent' }"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Log::Config
|
23
|
+
def initialize
|
24
|
+
@contents = { :console_log => true }
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(method, value)
|
28
|
+
@contents[method.to_s.gsub(/=$/, '').to_sym] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_hash
|
32
|
+
@contents
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Log
|
37
|
+
extend self
|
38
|
+
|
39
|
+
unless defined? SyslogConvertion
|
40
|
+
SyslogConvertion = {
|
41
|
+
'error' => 3,
|
42
|
+
'warning' => 4,
|
43
|
+
'notice' => 5,
|
44
|
+
'debug' => 7,
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def debug(msg, options={})
|
49
|
+
log msg, options.merge(:level => 'debug')
|
50
|
+
end
|
51
|
+
|
52
|
+
def notice(msg, options={})
|
53
|
+
log msg, options.merge(:level => 'notice')
|
54
|
+
end
|
55
|
+
|
56
|
+
def warning(msg, options={})
|
57
|
+
log msg, options.merge(:level => 'warning')
|
58
|
+
end
|
59
|
+
|
60
|
+
def error(msg, options={})
|
61
|
+
# Fake an exception for error messages with no exception object
|
62
|
+
# so that we get a backtrace.
|
63
|
+
if options[:exception].nil?
|
64
|
+
begin
|
65
|
+
raise StandardError, msg
|
66
|
+
rescue => error
|
67
|
+
error.backtrace.shift
|
68
|
+
options[:exception] = error
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
log msg, options.merge(:level => 'error')
|
73
|
+
end
|
74
|
+
|
75
|
+
##########
|
76
|
+
|
77
|
+
def log(msg, options={})
|
78
|
+
console_log(msg)
|
79
|
+
syslog(msg, options)
|
80
|
+
rescue InvalidConfiguration => e
|
81
|
+
raise e
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_error(e)
|
85
|
+
# avoid backtrace in /usr or vendor if possible
|
86
|
+
system, app = e.backtrace.partition { |b| b =~ /(^\/usr\/|vendor)/ }
|
87
|
+
reordered_backtrace = app + system
|
88
|
+
|
89
|
+
# avoid "/" as the method name (we want the controller action)
|
90
|
+
row = 0
|
91
|
+
row = 1 if reordered_backtrace[row].match(/in `\/'$/)
|
92
|
+
|
93
|
+
# get file and method name
|
94
|
+
begin
|
95
|
+
file, method = reordered_backtrace[row].match(/(.*):in `(.*)'$/)[1..2]
|
96
|
+
file.gsub!(/.*\//, '')
|
97
|
+
self.log "#{e.class} in #{file} #{method}: #{e.message}", :exception => e, :level => 'error'
|
98
|
+
rescue
|
99
|
+
self.log "#{e.class} in #{e.backtrace.first}: #{e.message}", :exception => e, :level => 'error'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def web_error(args)
|
104
|
+
e = args[:exception]
|
105
|
+
summary = "#{e.class} processing #{args[:url]}"
|
106
|
+
|
107
|
+
body = []
|
108
|
+
body << "\tURL: #{args[:url]}"
|
109
|
+
body << "\tParams: #{args[:params].inspect}"
|
110
|
+
body << "\tUser: #{args[:user]}" if args[:user]
|
111
|
+
body << "\tBacktrace:"
|
112
|
+
body << "\t\t#{e.class} (#{e.message}):"
|
113
|
+
body += e.backtrace.map { |l| "\t\t#{l}" }
|
114
|
+
body = body.join("\n")
|
115
|
+
|
116
|
+
log "#{summary}\n#{body}", :level => 'error'
|
117
|
+
end
|
118
|
+
|
119
|
+
def exception(e)
|
120
|
+
msg = "Exception #{e.class} -> #{e.message}\n"
|
121
|
+
msg += filtered_backtrace(e.backtrace)
|
122
|
+
STDERR.puts msg
|
123
|
+
Log.error e.message, :exception => e
|
124
|
+
end
|
125
|
+
|
126
|
+
def filtered_backtrace(backtrace)
|
127
|
+
backtrace.select do |line|
|
128
|
+
!line.match(/^\/usr/)
|
129
|
+
end.map do |line|
|
130
|
+
" #{line}\n"
|
131
|
+
end.join
|
132
|
+
end
|
133
|
+
|
134
|
+
def event(name, options = {})
|
135
|
+
console_log("EVENT: #{name} begins")
|
136
|
+
result = yield
|
137
|
+
console_log("EVENT: #{name} complete")
|
138
|
+
result
|
139
|
+
end
|
140
|
+
|
141
|
+
def context(options)
|
142
|
+
prev_options = default_options.dup
|
143
|
+
default_options.merge!(options)
|
144
|
+
yield
|
145
|
+
@@default_options = prev_options
|
146
|
+
end
|
147
|
+
|
148
|
+
def configure
|
149
|
+
config = Config.new
|
150
|
+
yield(config)
|
151
|
+
set_default_options(config.to_hash)
|
152
|
+
end
|
153
|
+
|
154
|
+
def set_default_options(options)
|
155
|
+
default_options.merge!(options)
|
156
|
+
end
|
157
|
+
|
158
|
+
def default_options
|
159
|
+
@@default_options ||= {}
|
160
|
+
end
|
161
|
+
|
162
|
+
def failsafe(params)
|
163
|
+
case default_options[:failsafe]
|
164
|
+
when :file
|
165
|
+
dir = defined?(RAILS_ROOT) ? RAILS_ROOT : '.'
|
166
|
+
File.open("#{dir}/failsafe.log", "a") do |f|
|
167
|
+
f.puts "#{Time.now} #{params[:log][:level]} : #{params[:log][:message]}"
|
168
|
+
f.puts params[:log][:addendum] if params[:log][:addendum]
|
169
|
+
end
|
170
|
+
when :console, nil
|
171
|
+
console_log(params[:log][:message])
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def console_log(msg)
|
176
|
+
STDERR.puts "#{Time.now.iso8601} #{msg}" if default_options[:console_log]
|
177
|
+
end
|
178
|
+
|
179
|
+
def syslog(msg, opts = {})
|
180
|
+
@retried = false
|
181
|
+
begin
|
182
|
+
level = SyslogConvertion[opts[:level]]
|
183
|
+
if opts[:exception]
|
184
|
+
msg += "\n" + format_syslog_exception(opts[:exception])
|
185
|
+
end
|
186
|
+
syslog_resource.log(level, '%s', msg)
|
187
|
+
rescue Exception => e
|
188
|
+
failsafe(:log => { :level => 'error', :message => "could not log to syslog: #{e.class.name} #{e.message}"})
|
189
|
+
unless @retried
|
190
|
+
@retried = true
|
191
|
+
@@syslog.close rescue nil
|
192
|
+
@@syslog = Syslog.open(default_options[:component]) rescue nil
|
193
|
+
retry
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def format_syslog_exception(e)
|
199
|
+
if e.respond_to?(:backtrace)
|
200
|
+
"\t#{e.class}: #{e.message}\n" + e.backtrace.map { |t| "\t#{t}" }.join("\n")
|
201
|
+
else
|
202
|
+
"\t#{e.class}: #{e.message}"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def syslog_resource
|
207
|
+
@@syslog ||= Syslog.open(default_options[:component].to_s, Syslog::LOG_PID | Syslog::LOG_CONS, default_options[:syslog_facility] || Syslog::LOG_USER)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|