diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2005-10-28 05:39:59 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2005-10-28 05:39:59 +0000 |
commit | b6c63f6924250a14e998f4256e81c30e950fed99 (patch) | |
tree | 8915ec8881f2389b208dfda27a12d11f69730398 /lib/puppet/log.rb | |
parent | 0ae5e3392597452acf6a2e9f0d4ac976b8ec9846 (diff) | |
download | puppet-b6c63f6924250a14e998f4256e81c30e950fed99.tar.gz puppet-b6c63f6924250a14e998f4256e81c30e950fed99.tar.xz puppet-b6c63f6924250a14e998f4256e81c30e950fed99.zip |
Central logging now works, although there appear to be a few kinks to work out.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@732 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/log.rb')
-rw-r--r-- | lib/puppet/log.rb | 257 |
1 files changed, 158 insertions, 99 deletions
diff --git a/lib/puppet/log.rb b/lib/puppet/log.rb index 885260f2e..ab2670f13 100644 --- a/lib/puppet/log.rb +++ b/lib/puppet/log.rb @@ -1,12 +1,9 @@ -# $Id$ - require 'syslog' -module Puppet - #------------------------------------------------------------ - # provide feedback of various types to the user - # modeled after syslog messages - # each level of message prints in a different color +module Puppet # :nodoc: + # Pass feedback to the user. Log levels are modeled after syslog's, and it is + # expected that that will be the most common log destination. Supports + # multiple destinations, one of which is a remote server. class Log PINK="[0;31m" GREEN="[0;32m" @@ -16,13 +13,10 @@ module Puppet BLUE="[0;36m" RESET="[0m" - @@messages = Array.new + @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit] + @loglevel = 2 - @@levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit] - @@loglevel = 2 - @@logdest = :console - - @@colors = { + @colors = { :debug => SLATE, :info => GREEN, :notice => PINK, @@ -33,52 +27,91 @@ module Puppet :crit => RESET } - def Log.close - if defined? @@logfile - @@logfile.close - @@logfile = nil - end + @destinations = {:syslog => Syslog.open("puppet")} - if defined? @@syslog - @@syslog = nil + # Reset all logs to basics. Basically just closes all files and undefs + # all of the other objects. + def Log.close(dest = nil) + if dest + if @destinations.include?(dest) + Puppet.warning "Closing %s" % dest + if @destinations.respond_to?(:close) + @destinations[dest].close + end + @destinations.delete(dest) + end + else + @destinations.each { |type, dest| + if dest.respond_to?(:flush) + dest.flush + end + if dest.respond_to?(:close) + dest.close + end + } + @destinations = {} end + + Puppet.info "closed" end + # Flush any log destinations that support such operations. def Log.flush - if defined? @@logfile - @@logfile.flush - end + @destinations.each { |type, dest| + if dest.respond_to?(:flush) + dest.flush + end + } end + # Create a new log message. The primary role of this method is to + # avoid creating log messages below the loglevel. def Log.create(hash) - if @@levels.index(hash[:level]) >= @@loglevel + if @levels.index(hash[:level]) >= @loglevel return Puppet::Log.new(hash) else return nil end end - def Log.levels - return @@levels.dup + # Yield each valid level in turn + def Log.eachlevel + @levels.each { |level| yield level } end - def Log.destination - return @@logdest + # Return the current log level. + def Log.level + return @levels[@loglevel] end - def Log.destination=(dest) - if dest == "syslog" or dest == :syslog - unless defined? @@syslog - @@syslog = Syslog.open("puppet") - end - @@logdest = :syslog - elsif dest =~ /^\// - if defined? @@logfile and @@logfile - @@logfile.close - end + # Set the current log level. + def Log.level=(level) + unless level.is_a?(Symbol) + level = level.intern + end - @@logpath = dest + unless @levels.include?(level) + raise Puppet::DevError, "Invalid loglevel %s" % level + end + + @loglevel = @levels.index(level) + end + # Create a new log destination. + def Log.newdestination(dest) + # Each destination can only occur once. + if @destinations.include?(dest) + return + end + + case dest + when "syslog", :syslog + if Syslog.opened? + Syslog.close + end + @destinations[:syslog] = Syslog.open("puppet") + when /^\// # files + Puppet.info "opening %s as a log" % dest # first make sure the directory exists unless FileTest.exist?(File.dirname(dest)) begin @@ -93,80 +126,114 @@ module Puppet end end - Puppet[:logfile] = dest begin # create the log file, if it doesn't already exist - @@logfile = File.open(dest,File::WRONLY|File::CREAT|File::APPEND) + file = File.open(dest,File::WRONLY|File::CREAT|File::APPEND) rescue => detail Log.destination = :console Puppet.err "Could not create log file: %s" % detail return end - @@logdest = :file + @destinations[dest] = file + when "console", :console + @destinations[:console] = :console + when Puppet::Server::Logger + @destinations[dest] = dest else - unless @@logdest == :console or @@logdest == "console" - Puppet.notice "Invalid log setting %s; setting log destination to 'console'" % @@logdest + Puppet.info "Treating %s as a hostname" % dest + args = {} + if dest =~ /:(\d+)/ + args[:Port] = $1 + args[:Server] = dest.sub(/:\d+/, '') + else + args[:Server] = dest end - @@logdest = :console - end - end - - def Log.level - return @@levels[@@loglevel] - end - - def Log.level=(level) - unless level.is_a?(Symbol) - level = level.intern - end - - unless @@levels.include?(level) - raise Puppet::DevError, "Invalid loglevel %s" % level + @destinations[dest] = Puppet::Client::LogClient.new(args) end - - @@loglevel = @@levels.index(level) end + # Route the actual message. FIXME There are lots of things this method should + # do, like caching, storing messages when there are not yet destinations, + # a bit more. + # It's worth noting that there's a potential for a loop here, if + # the machine somehow gets the destination set as itself. def Log.newmessage(msg) - case @@logdest - when :syslog: - if msg.source == "Puppet" - @@syslog.send(msg.level,msg.to_s) + @destinations.each { |type, dest| + case dest + when Module # This is the Syslog module + next if msg.remote + if msg.source == "Puppet" + dest.send(msg.level,msg.to_s) + else + dest.send(msg.level,"(%s) %s" % [msg.source,msg.to_s]) + end + when File: + dest.puts("%s %s (%s): %s" % + [msg.time,msg.source,msg.level,msg.to_s]) + when :console + if msg.source == "Puppet" + puts @colors[msg.level] + "%s: %s" % [ + msg.level, msg.to_s + ] + RESET + else + puts @colors[msg.level] + "%s (%s): %s" % [ + msg.source, msg.level, msg.to_s + ] + RESET + end + when Puppet::Client::LogClient + # For now, to avoid a loop, don't send remote messages + unless msg.is_a?(String) or msg.remote + begin + #puts "would have sent %s" % msg + #puts "would have sent %s" % + # CGI.escape(Marshal::dump(msg)) + dest.addlog(CGI.escape(Marshal::dump(msg))) + #dest.addlog(msg.to_s) + sleep(0.5) + rescue => detail + Puppet.err detail + @destinations.delete(type) + end + end else - @@syslog.send(msg.level,"(%s) %s" % [msg.source,msg.to_s]) + #raise Puppet::Error, "Invalid log destination %s" % dest + puts "Invalid log destination %s" % dest.inspect end - when :file: - unless defined? @@logfile - raise Puppet::DevError, - "Log file must be defined before we can log to it" + } + end + + # Reopen all of our logs. + def Log.reopen + types = @destinations.keys + @destinations.each { |type, dest| + if dest.respond_to?(:close) + dest.close end - @@logfile.puts("%s %s (%s): %s" % - [msg.time,msg.source,msg.level,msg.to_s]) - else - if msg.source == "Puppet" - puts @@colors[msg.level] + "%s: %s" % [ - msg.level, msg.to_s - ] + RESET - else - puts @@colors[msg.level] + "%s (%s): %s" % [ - msg.source, msg.level, msg.to_s - ] + RESET + } + @destinations.clear + # We need to make sure we always end up with some kind of destination + begin + types.each { |type| + Log.newdestination(type) + } + rescue => detail + if @destinations.empty? + Log.newdestination(:syslog) + Puppet.err detail.to_s end end end - def Log.reopen - if @@logfile - Log.destination = @@logpath - end + # Is the passed level a valid log level? + def self.validlevel?(level) + @levels.include?(level) end - attr_accessor :level, :message, :source, :time, :tags, :path + attr_accessor :level, :message, :source, :time, :tags, :path, :remote def initialize(args) - unless args.include?(:level) && args.include?(:message) && - args.include?(:source) + unless args.include?(:level) && args.include?(:message) raise Puppet::DevError, "Puppet::Log called incorrectly" end @@ -182,7 +249,7 @@ module Puppet @time = Time.now # this should include the host name, and probly lots of other # stuff, at some point - unless @@levels.include?(level) + unless self.class.validlevel?(level) raise Puppet::DevError, "Invalid message level #{level}" end @@ -215,17 +282,9 @@ module Puppet end def to_s - # this probably won't stay, but until this leaves the console, - # i'm going to use coloring... - #return "#{@time} #{@source} (#{@level}): #{@message}" - #return @@colors[@level] + "%s %s (%s): %s" % [ - # @time, @source, @level, @message - #] + RESET return @message - #return @@colors[@level] + "%s (%s): %s" % [ - # @source, @level, @message - #] + RESET end end - #------------------------------------------------------------ end + +# $Id$ |