mcollective-client 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mcollective-client might be problematic. Click here for more details.
- data/bin/mc-call-agent +54 -0
- data/bin/mco +27 -0
- data/lib/mcollective.rb +70 -0
- data/lib/mcollective/agents.rb +160 -0
- data/lib/mcollective/application.rb +354 -0
- data/lib/mcollective/applications.rb +145 -0
- data/lib/mcollective/client.rb +292 -0
- data/lib/mcollective/config.rb +202 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +24 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +86 -0
- data/lib/mcollective/log.rb +103 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +73 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +46 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +16 -0
- data/lib/mcollective/matcher/parser.rb +93 -0
- data/lib/mcollective/matcher/scanner.rb +123 -0
- data/lib/mcollective/message.rb +201 -0
- data/lib/mcollective/monkey_patches.rb +104 -0
- data/lib/mcollective/optionparser.rb +164 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +26 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +79 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +59 -0
- data/lib/mcollective/registration.rb +16 -0
- data/lib/mcollective/registration/base.rb +75 -0
- data/lib/mcollective/rpc.rb +188 -0
- data/lib/mcollective/rpc/actionrunner.rb +142 -0
- data/lib/mcollective/rpc/agent.rb +441 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +793 -0
- data/lib/mcollective/rpc/ddl.rb +258 -0
- data/lib/mcollective/rpc/helpers.rb +339 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +61 -0
- data/lib/mcollective/rpc/request.rb +51 -0
- data/lib/mcollective/rpc/result.rb +41 -0
- data/lib/mcollective/rpc/stats.rb +185 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +237 -0
- data/lib/mcollective/shell.rb +87 -0
- data/lib/mcollective/ssl.rb +246 -0
- data/lib/mcollective/unix_daemon.rb +37 -0
- data/lib/mcollective/util.rb +274 -0
- data/lib/mcollective/vendor.rb +41 -0
- data/lib/mcollective/vendor/require_vendored.rb +2 -0
- data/lib/mcollective/windows_daemon.rb +25 -0
- data/spec/Rakefile +16 -0
- data/spec/fixtures/application/test.rb +7 -0
- data/spec/fixtures/test-cert.pem +15 -0
- data/spec/fixtures/test-private.pem +15 -0
- data/spec/fixtures/test-public.pem +6 -0
- data/spec/monkey_patches/instance_variable_defined.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/unit/agents_spec.rb +280 -0
- data/spec/unit/application_spec.rb +636 -0
- data/spec/unit/applications_spec.rb +155 -0
- data/spec/unit/array.rb +30 -0
- data/spec/unit/config_spec.rb +148 -0
- data/spec/unit/facts/base_spec.rb +118 -0
- data/spec/unit/facts_spec.rb +39 -0
- data/spec/unit/log_spec.rb +71 -0
- data/spec/unit/logger/base_spec.rb +110 -0
- data/spec/unit/logger/syslog_logger_spec.rb +86 -0
- data/spec/unit/matcher/parser_spec.rb +106 -0
- data/spec/unit/matcher/scanner_spec.rb +71 -0
- data/spec/unit/message_spec.rb +401 -0
- data/spec/unit/optionparser_spec.rb +113 -0
- data/spec/unit/pluginmanager_spec.rb +173 -0
- data/spec/unit/pluginpackager/agent_definition_spec.rb +130 -0
- data/spec/unit/pluginpackager/standard_definition_spec.rb +75 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +533 -0
- data/spec/unit/plugins/mcollective/connector/stomp/eventlogger_spec.rb +34 -0
- data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +417 -0
- data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +229 -0
- data/spec/unit/plugins/mcollective/security/psk_spec.rb +156 -0
- data/spec/unit/registration/base_spec.rb +77 -0
- data/spec/unit/rpc/actionrunner_spec.rb +213 -0
- data/spec/unit/rpc/agent_spec.rb +155 -0
- data/spec/unit/rpc/client_spec.rb +523 -0
- data/spec/unit/rpc/ddl_spec.rb +388 -0
- data/spec/unit/rpc/helpers_spec.rb +55 -0
- data/spec/unit/rpc/reply_spec.rb +143 -0
- data/spec/unit/rpc/request_spec.rb +115 -0
- data/spec/unit/rpc/result_spec.rb +66 -0
- data/spec/unit/rpc/stats_spec.rb +288 -0
- data/spec/unit/runnerstats_spec.rb +40 -0
- data/spec/unit/security/base_spec.rb +279 -0
- data/spec/unit/shell_spec.rb +144 -0
- data/spec/unit/ssl_spec.rb +244 -0
- data/spec/unit/symbol.rb +11 -0
- data/spec/unit/unix_daemon.rb +41 -0
- data/spec/unit/util_spec.rb +342 -0
- data/spec/unit/vendor_spec.rb +34 -0
- data/spec/unit/windows_daemon.rb +43 -0
- data/spec/windows_spec.opts +1 -0
- metadata +242 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module MCollective
|
2
|
+
# Connectors take care of transporting messages between clients and agents,
|
3
|
+
# the design doesn't your middleware to be very rich in features. All it
|
4
|
+
# really needs is the ability to send and receive messages to named queues/topics.
|
5
|
+
#
|
6
|
+
# At present there are assumptions about the naming of topics and queues that is
|
7
|
+
# compatible with Stomp, ie.
|
8
|
+
#
|
9
|
+
# /topic/foo.bar/baz
|
10
|
+
# /queue/foo.bar/baz
|
11
|
+
#
|
12
|
+
# This is the only naming format that is supported, but you could replace Stomp
|
13
|
+
# with something else that supports the above, see MCollective::Connector::Stomp
|
14
|
+
# for the default connector.
|
15
|
+
module Connector
|
16
|
+
autoload :Base, "mcollective/connector/base"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MCollective
|
2
|
+
# Connector plugins handle the communications with the middleware, you can provide your own to speak
|
3
|
+
# to something other than Stomp, your plugins must inherit from MCollective::Connector::Base and should
|
4
|
+
# provide the following methods:
|
5
|
+
#
|
6
|
+
# connect - Creates a connection to the middleware, no arguments should get its parameters from the config
|
7
|
+
# receive - Receive data from the middleware, should act like a blocking call only returning if/when data
|
8
|
+
# was received. It should get data from all subscribed channels/topics. Individual messages
|
9
|
+
# should be returned as MCollective::Request objects with the payload provided
|
10
|
+
# publish - Takes a target and msg, should send the message to the supplied target topic or destination
|
11
|
+
# subscribe - Adds a subscription to a specific message source
|
12
|
+
# unsubscribe - Removes a subscription to a specific message source
|
13
|
+
# disconnect - Disconnects from the middleware
|
14
|
+
#
|
15
|
+
# These methods are all that's needed for a new connector protocol and should hopefully be simple
|
16
|
+
# enough to not have tied us to Stomp.
|
17
|
+
module Connector
|
18
|
+
class Base
|
19
|
+
def self.inherited(klass)
|
20
|
+
PluginManager << {:type => "connector_plugin", :class => klass.to_s}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MCollective
|
2
|
+
# This is a class that gives access to the configured fact provider
|
3
|
+
# such as MCollectives::Facts::Facter that uses Reductive Labs facter
|
4
|
+
#
|
5
|
+
# The actual provider is pluggable and configurable using the 'factsource'
|
6
|
+
# configuration option.
|
7
|
+
#
|
8
|
+
# To develop a new factsource simply create a class under MCollective::Facts::
|
9
|
+
# and provide the following classes:
|
10
|
+
#
|
11
|
+
# self.get_fact(fact)
|
12
|
+
# self.has_fact?(fact)
|
13
|
+
#
|
14
|
+
# You can also just inherit from MCollective::Facts::Base and provide just the
|
15
|
+
#
|
16
|
+
# self.get_facts
|
17
|
+
#
|
18
|
+
# method that should return a hash of facts.
|
19
|
+
module Facts
|
20
|
+
autoload :Base, "mcollective/facts/base"
|
21
|
+
|
22
|
+
@@config = nil
|
23
|
+
|
24
|
+
# True if we know of a specific fact else false
|
25
|
+
def self.has_fact?(fact, value)
|
26
|
+
PluginManager["facts_plugin"].get_fact(fact) == value ? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get the value of a fact
|
30
|
+
def self.get_fact(fact)
|
31
|
+
PluginManager["facts_plugin"].get_fact(fact)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get the value of a fact
|
35
|
+
def self.[](fact)
|
36
|
+
PluginManager["facts_plugin"].get_fact(fact)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Facts
|
3
|
+
# A base class for fact providers, to make a new fully functional fact provider
|
4
|
+
# inherit from this and simply provide a self.get_facts method that returns a
|
5
|
+
# hash like:
|
6
|
+
#
|
7
|
+
# {"foo" => "bar",
|
8
|
+
# "bar" => "baz"}
|
9
|
+
class Base
|
10
|
+
def initialize
|
11
|
+
@facts = {}
|
12
|
+
@last_good_facts = {}
|
13
|
+
@last_facts_load = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
# Registers new fact sources into the plugin manager
|
17
|
+
def self.inherited(klass)
|
18
|
+
PluginManager << {:type => "facts_plugin", :class => klass.to_s}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the value of a single fact
|
22
|
+
def get_fact(fact=nil)
|
23
|
+
config = Config.instance
|
24
|
+
|
25
|
+
cache_time = config.fact_cache_time || 300
|
26
|
+
|
27
|
+
Thread.exclusive do
|
28
|
+
begin
|
29
|
+
if (Time.now.to_i - @last_facts_load > cache_time.to_i ) || force_reload?
|
30
|
+
Log.debug("Resetting facter cache, now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
|
31
|
+
|
32
|
+
tfacts = load_facts_from_source
|
33
|
+
|
34
|
+
# Force reset to last known good state on empty facts
|
35
|
+
raise "Got empty facts" if tfacts.empty?
|
36
|
+
|
37
|
+
@facts.clear
|
38
|
+
|
39
|
+
tfacts.each_pair do |key,value|
|
40
|
+
@facts[key.to_s] = value.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
@last_good_facts = @facts.clone
|
44
|
+
@last_facts_load = Time.now.to_i
|
45
|
+
else
|
46
|
+
Log.debug("Using cached facts now: #{Time.now.to_i} last-known-good: #{@last_facts_load}")
|
47
|
+
end
|
48
|
+
rescue Exception => e
|
49
|
+
Log.error("Failed to load facts: #{e.class}: #{e}")
|
50
|
+
|
51
|
+
# Avoid loops where failing fact loads cause huge CPU
|
52
|
+
# loops, this way it only retries once every cache_time
|
53
|
+
# seconds
|
54
|
+
@last_facts_load = Time.now.to_i
|
55
|
+
|
56
|
+
# Revert to last known good state
|
57
|
+
@facts = @last_good_facts.clone
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# If you do not supply a specific fact all facts will be returned
|
63
|
+
if fact.nil?
|
64
|
+
return @facts
|
65
|
+
else
|
66
|
+
@facts.include?(fact) ? @facts[fact] : nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns all facts
|
71
|
+
def get_facts
|
72
|
+
get_fact(nil)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns true if we know about a specific fact, false otherwise
|
76
|
+
def has_fact?(fact)
|
77
|
+
get_fact(nil).include?(fact)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Plugins can override this to provide forced fact invalidation
|
81
|
+
def force_reload?
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module MCollective
|
2
|
+
# A simple class that allows logging at various levels.
|
3
|
+
class Log
|
4
|
+
class << self
|
5
|
+
@logger = nil
|
6
|
+
|
7
|
+
# Obtain the class name of the currently configured logger
|
8
|
+
def logger
|
9
|
+
@logger.class
|
10
|
+
end
|
11
|
+
|
12
|
+
# Logs at info level
|
13
|
+
def info(msg)
|
14
|
+
log(:info, msg)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Logs at warn level
|
18
|
+
def warn(msg)
|
19
|
+
log(:warn, msg)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Logs at debug level
|
23
|
+
def debug(msg)
|
24
|
+
log(:debug, msg)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Logs at fatal level
|
28
|
+
def fatal(msg)
|
29
|
+
log(:fatal, msg)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Logs at error level
|
33
|
+
def error(msg)
|
34
|
+
log(:error, msg)
|
35
|
+
end
|
36
|
+
|
37
|
+
# handle old code that relied on this class being a singleton
|
38
|
+
def instance
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# increments the active log level
|
43
|
+
def cycle_level
|
44
|
+
@logger.cycle_level if @configured
|
45
|
+
end
|
46
|
+
|
47
|
+
# logs a message at a certain level
|
48
|
+
def log(level, msg)
|
49
|
+
configure unless @configured
|
50
|
+
|
51
|
+
raise "Unknown log level" unless [:error, :fatal, :debug, :warn, :info].include?(level)
|
52
|
+
|
53
|
+
if @logger
|
54
|
+
@logger.log(level, from, msg)
|
55
|
+
else
|
56
|
+
t = Time.new.strftime("%H:%M:%S")
|
57
|
+
|
58
|
+
STDERR.puts "#{t}: #{level}: #{from}: #{msg}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# sets the logger class to use
|
63
|
+
def set_logger(logger)
|
64
|
+
@logger = logger
|
65
|
+
end
|
66
|
+
|
67
|
+
# configures the logger class, if the config has not yet been loaded
|
68
|
+
# we default to the console logging class and do not set @configured
|
69
|
+
# so that future calls to the log method will keep attempting to configure
|
70
|
+
# the logger till we eventually get a logging preference from the config
|
71
|
+
# module
|
72
|
+
def configure(logger=nil)
|
73
|
+
unless logger
|
74
|
+
logger_type = "console"
|
75
|
+
|
76
|
+
config = Config.instance
|
77
|
+
|
78
|
+
if config.configured
|
79
|
+
logger_type = config.logger_type
|
80
|
+
@configured = true
|
81
|
+
end
|
82
|
+
|
83
|
+
require "mcollective/logger/#{logger_type.downcase}_logger"
|
84
|
+
set_logger(eval("MCollective::Logger::#{logger_type.capitalize}_logger.new"))
|
85
|
+
else
|
86
|
+
set_logger(logger)
|
87
|
+
@configured = true
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
@logger.start
|
92
|
+
rescue Exception => e
|
93
|
+
@configured = false
|
94
|
+
STDERR.puts "Could not start logger: #{e.class} #{e}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# figures out the filename that called us
|
98
|
+
def from
|
99
|
+
from = File.basename(caller[2])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Logger
|
3
|
+
# A base class for logging providers.
|
4
|
+
#
|
5
|
+
# Logging providers should provide the following:
|
6
|
+
#
|
7
|
+
# * start - all you need to do to setup your logging
|
8
|
+
# * set_logging_level - set your logging to :info, :warn, etc
|
9
|
+
# * valid_levels - a hash of maps from :info to your internal level name
|
10
|
+
# * log - what needs to be done to log a specific message
|
11
|
+
class Base
|
12
|
+
attr_reader :active_level
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@known_levels = [:debug, :info, :warn, :error, :fatal]
|
16
|
+
|
17
|
+
# Sanity check the class that impliments the logging
|
18
|
+
@known_levels.each do |lvl|
|
19
|
+
raise "Logger class did not specify a map for #{lvl}" unless valid_levels.include?(lvl)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Figures out the next level and sets it
|
24
|
+
def cycle_level
|
25
|
+
lvl = get_next_level
|
26
|
+
set_level(lvl)
|
27
|
+
|
28
|
+
log(lvl, "", "Logging level is now #{lvl.to_s.upcase}")
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sets a new level and record it in @active_level
|
32
|
+
def set_level(level)
|
33
|
+
set_logging_level(level)
|
34
|
+
@active_level = level.to_sym
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def map_level(level)
|
39
|
+
raise "Logger class do not know how to handle #{level} messages" unless valid_levels.include?(level.to_sym)
|
40
|
+
|
41
|
+
valid_levels[level.to_sym]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets the next level in the list, cycles down to the firt once it reaches the end
|
45
|
+
def get_next_level
|
46
|
+
# if all else fails, always go to debug mode
|
47
|
+
nextlvl = :debug
|
48
|
+
|
49
|
+
if @known_levels.index(@active_level) == (@known_levels.size - 1)
|
50
|
+
nextlvl = @known_levels.first
|
51
|
+
else
|
52
|
+
idx = @known_levels.index(@active_level) + 1
|
53
|
+
nextlvl = @known_levels[idx]
|
54
|
+
end
|
55
|
+
|
56
|
+
nextlvl
|
57
|
+
end
|
58
|
+
|
59
|
+
# Abstract methods to ensure the logging implimentations supply what they should
|
60
|
+
def valid_levels
|
61
|
+
raise "The logging class did not supply a valid_levels method"
|
62
|
+
end
|
63
|
+
|
64
|
+
def log(level, from, msg)
|
65
|
+
raise "The logging class did not supply a log method"
|
66
|
+
end
|
67
|
+
|
68
|
+
def start
|
69
|
+
raise "The logging class did not supply a start method"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Logger
|
3
|
+
# Impliments a syslog based logger using the standard ruby syslog class
|
4
|
+
class Console_logger<Base
|
5
|
+
def start
|
6
|
+
set_level(:info)
|
7
|
+
|
8
|
+
config = Config.instance
|
9
|
+
set_level(config.loglevel.to_sym) if config.configured
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_logging_level(level)
|
13
|
+
# nothing to do here, we ignore high levels when we log
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_levels
|
17
|
+
{:info => :info,
|
18
|
+
:warn => :warning,
|
19
|
+
:debug => :debug,
|
20
|
+
:fatal => :crit,
|
21
|
+
:error => :err}
|
22
|
+
end
|
23
|
+
|
24
|
+
def log(level, from, msg)
|
25
|
+
if @known_levels.index(level) >= @known_levels.index(@active_level)
|
26
|
+
time = Time.new.strftime("%Y/%m/%d %H:%M:%S")
|
27
|
+
lvltxt = colorize(level, level)
|
28
|
+
STDERR.puts("#{lvltxt} #{time}: #{from} #{msg}")
|
29
|
+
end
|
30
|
+
rescue
|
31
|
+
# if this fails we probably cant show the user output at all,
|
32
|
+
# STDERR it as last resort
|
33
|
+
STDERR.puts("#{level}: #{msg}")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set some colors for various logging levels, will honor the
|
37
|
+
# color configuration option and return nothing if its configured
|
38
|
+
# not to
|
39
|
+
def color(level)
|
40
|
+
colorize = Config.instance.color
|
41
|
+
|
42
|
+
colors = {:error => "[31m",
|
43
|
+
:fatal => "[31m",
|
44
|
+
:warn => "[33m",
|
45
|
+
:info => "[32m",
|
46
|
+
:reset => "[0m"}
|
47
|
+
|
48
|
+
if colorize
|
49
|
+
return colors[level] || ""
|
50
|
+
else
|
51
|
+
return ""
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Helper to return a string in specific color
|
56
|
+
def colorize(level, msg)
|
57
|
+
"#{self.color(level)}#{msg}#{self.color(:reset)}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module MCollective
|
4
|
+
module Logger
|
5
|
+
# Impliments a file based logger using the standard ruby logger class
|
6
|
+
#
|
7
|
+
# To configure you should set:
|
8
|
+
#
|
9
|
+
# - config.logfile
|
10
|
+
# - config.keeplogs defaults to 2097152
|
11
|
+
# - config.max_log_size defaults to 5
|
12
|
+
class File_logger<Base
|
13
|
+
def start
|
14
|
+
config = Config.instance
|
15
|
+
|
16
|
+
@logger = ::Logger.new(config.logfile, config.keeplogs, config.max_log_size)
|
17
|
+
@logger.formatter = ::Logger::Formatter.new
|
18
|
+
|
19
|
+
set_level(config.loglevel.to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_logging_level(level)
|
23
|
+
@logger.level = map_level(level)
|
24
|
+
rescue Exception => e
|
25
|
+
@logger.level = ::Logger::DEBUG
|
26
|
+
log(:error, "", "Could not set logging to #{level} using debug instead: #{e.class} #{e}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid_levels
|
30
|
+
{:info => ::Logger::INFO,
|
31
|
+
:warn => ::Logger::WARN,
|
32
|
+
:debug => ::Logger::DEBUG,
|
33
|
+
:fatal => ::Logger::FATAL,
|
34
|
+
:error => ::Logger::ERROR}
|
35
|
+
end
|
36
|
+
|
37
|
+
def log(level, from, msg)
|
38
|
+
@logger.add(map_level(level)) { "#{from} #{msg}" }
|
39
|
+
rescue
|
40
|
+
# if this fails we probably cant show the user output at all,
|
41
|
+
# STDERR it as last resort
|
42
|
+
STDERR.puts("#{level}: #{msg}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|