7e3d774c65ef4255a0af9ceb3b2df14ec1719439
[packages/precise/mcollective.git] / lib / mcollective / log.rb
1 module MCollective
2   # A simple class that allows logging at various levels.
3   class Log
4     class << self
5       @logger = nil
6
7       VALID_LEVELS = [:error, :fatal, :debug, :warn, :info]
8
9       # Obtain the class name of the currently configured logger
10       def logger
11         @logger.class
12       end
13
14       # Logs at info level
15       def info(msg)
16         log(:info, msg)
17       end
18
19       # Logs at warn level
20       def warn(msg)
21         log(:warn, msg)
22       end
23
24       # Logs at debug level
25       def debug(msg)
26         log(:debug, msg)
27       end
28
29       # Logs at fatal level
30       def fatal(msg)
31         log(:fatal, msg)
32       end
33
34       # Logs at error level
35       def error(msg)
36         log(:error, msg)
37       end
38
39       # handle old code that relied on this class being a singleton
40       def instance
41         self
42       end
43
44       # increments the active log level
45       def cycle_level
46         @logger.cycle_level if @configured
47       end
48
49       def config_and_check_level(level)
50         configure unless @configured
51         check_level(level)
52         @logger.should_log?(level)
53       end
54
55       def check_level(level)
56         raise "Unknown log level" unless valid_level?(level)
57       end
58
59       def valid_level?(level)
60         VALID_LEVELS.include?(level)
61       end
62
63       def message_for(msgid, args={})
64         "%s: %s" % [msgid, Util.t(msgid, args)]
65       end
66
67       def logexception(msgid, level, e, backtrace=false, args={})
68         return false unless config_and_check_level(level)
69
70         origin = File.basename(e.backtrace[1])
71
72         if e.is_a?(CodedError)
73           msg = "%s: %s" % [e.code, e.to_s]
74         else
75           error_string = "%s: %s" % [e.class, e.to_s]
76           msg = message_for(msgid, args.merge(:error => error_string))
77         end
78
79         log(level, msg, origin)
80
81         if backtrace
82           e.backtrace.each do |line|
83             log(level, "%s:          %s" % [msgid, line], origin)
84           end
85         end
86       end
87
88       # Logs a message at a certain level, the message must be
89       # a token that will be looked up from the i18n localization
90       # database
91       #
92       # Messages can interprolate strings from the args hash, a
93       # message with "foo %{bar}" in the localization database
94       # will use args[:bar] for the value there, the interprolation
95       # is handled by the i18n library itself
96       def logmsg(msgid, default, level, args={})
97         return false unless config_and_check_level(level)
98
99         msg = message_for(msgid, {:default => default}.merge(args))
100
101         log(level, msg)
102       end
103
104       # logs a message at a certain level
105       def log(level, msg, origin=nil)
106         return unless config_and_check_level(level)
107
108         origin = from unless origin
109
110         if @logger
111           @logger.log(level, origin, msg)
112         else
113           t = Time.new.strftime("%H:%M:%S")
114
115           STDERR.puts "#{t}: #{level}: #{origin}: #{msg}"
116         end
117       end
118
119       # sets the logger class to use
120       def set_logger(logger)
121         @logger = logger
122       end
123
124       # configures the logger class, if the config has not yet been loaded
125       # we default to the console logging class and do not set @configured
126       # so that future calls to the log method will keep attempting to configure
127       # the logger till we eventually get a logging preference from the config
128       # module
129       def configure(logger=nil)
130         unless logger
131           logger_type = "console"
132
133           config = Config.instance
134
135           if config.configured
136             logger_type = config.logger_type
137             @configured = true
138           end
139
140           require "mcollective/logger/%s_logger" % logger_type.downcase
141
142           logger_class = MCollective::Logger.const_get("%s_logger" % logger_type.capitalize)
143
144           set_logger(logger_class.new)
145         else
146           set_logger(logger)
147           @configured = true
148         end
149
150
151         @logger.start
152       rescue Exception => e
153         @configured = false
154         STDERR.puts "Could not start logger: #{e.class} #{e}"
155       end
156
157       def unconfigure
158         @configured = false
159         set_logger(nil)
160       end
161
162       # figures out the filename that called us
163       def from
164         from = File.basename(caller[2])
165       end
166     end
167   end
168 end