# class Log

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.

### Public Class Methods

autoflush=(v) click to toggle source

    # File lib/puppet/util/log.rb, line 71
    def Log.autoflush=(v)
      @destinations.each do |type, dest|
        dest.autoflush = v if dest.respond_to?(:autoflush=)
      end
    end

close(destination) click to toggle source

Reset log to basics. Basically just flushes and closes files and undefs other objects.

    # File lib/puppet/util/log.rb, line 49
    def Log.close(destination)
      if @destinations.include?(destination)
        @destinations[destination].flush if @destinations[destination].respond_to?(:flush)
        @destinations[destination].close if @destinations[destination].respond_to?(:close)
        @destinations.delete(destination)
      end
    end

close_all() click to toggle source

    # File lib/puppet/util/log.rb, line 57
    def self.close_all
      destinations.keys.each { |dest|
        close(dest)
      }
      raise Puppet::DevError.new("Log.close_all failed to close #{@destinations.keys.inspect}") if !@destinations.empty?
    end

create(hash) click to toggle source

Create a new log message. The primary role of this method is to avoid creating log messages below the loglevel.

    # File lib/puppet/util/log.rb, line 79
    def Log.create(hash)
      raise Puppet::DevError, "Logs require a level" unless hash.include?(:level)
      raise Puppet::DevError, "Invalid log level #{hash[:level]}" unless @levels.index(hash[:level])
      @levels.index(hash[:level]) >= @loglevel ? Puppet::Util::Log.new(hash) : nil
    end

destinations() click to toggle source

    # File lib/puppet/util/log.rb, line 85
    def Log.destinations
      @destinations
    end

eachlevel() { |level| ... } click to toggle source

Yield each valid level in turn

    # File lib/puppet/util/log.rb, line 90
    def Log.eachlevel
      @levels.each { |level| yield level }
    end

flush() click to toggle source

Flush any log destinations that support such operations.

    # File lib/puppet/util/log.rb, line 65
    def Log.flush
      @destinations.each { |type, dest|
        dest.flush if dest.respond_to?(:flush)
      }
    end

flushqueue() click to toggle source

    # File lib/puppet/util/log.rb, line 165
    def Log.flushqueue
      return unless @destinations.size >= 1
      @queued.each do |msg|
        Log.newmessage(msg)
      end
      @queued.clear
    end

force_flushqueue() click to toggle source

Flush the logging queue. If there are no destinations available,

    adds in a console logger before flushing the queue.

This is mainly intended to be used as a last-resort attempt

    to ensure that logging messages are not thrown away before
    the program is about to exit--most likely in a horrific
    error scenario.

@return nil

    # File lib/puppet/util/log.rb, line 180
    def Log.force_flushqueue()
      if (@destinations.empty? and !(@queued.empty?))
        newdestination(:console)
      end
      flushqueue
    end

level() click to toggle source

Return the current log level.

    # File lib/puppet/util/log.rb, line 95
    def Log.level
      @levels[@loglevel]
    end

level=(level) click to toggle source

Set the current log level.

    # File lib/puppet/util/log.rb, line 100
    def Log.level=(level)
      level = level.intern unless level.is_a?(Symbol)

      raise Puppet::DevError, "Invalid loglevel #{level}" unless @levels.include?(level)

      @loglevel = @levels.index(level)
    end

levels() click to toggle source

    # File lib/puppet/util/log.rb, line 108
    def Log.levels
      @levels.dup
    end

new(args) click to toggle source

    # File lib/puppet/util/log.rb, line 226
    def initialize(args)
      self.level = args[:level]
      self.message = args[:message]
      self.source = args[:source] || "Puppet"

      @time = Time.now

      if tags = args[:tags]
        tags.each { |t| self.tag(t) }
      end

      [:file, :line].each do |attr|
        next unless value = args[attr]
        send(attr.to_s + "=", value)
      end

      Log.newmessage(self)
    end

newdestination(dest) click to toggle source

Create a new log destination.

    # File lib/puppet/util/log.rb, line 113
    def Log.newdestination(dest)
      # Each destination can only occur once.
      if @destinations.find { |name, obj| obj.name == dest }
        return
      end

      name, type = @desttypes.find do |name, klass|
        klass.match?(dest)
      end

      if type.respond_to?(:suitable?) and not type.suitable?(dest)
        return
      end

      raise Puppet::DevError, "Unknown destination type #{dest}" unless type

      begin
        if type.instance_method(:initialize).arity == 1
          @destinations[dest] = type.new(dest)
        else
          @destinations[dest] = type.new
        end
        flushqueue
        @destinations[dest]
      rescue => detail
        Puppet.log_exception(detail)

        # If this was our only destination, then add the console back in.
        newdestination(:console) if @destinations.empty? and (dest != :console and dest != "console")
      end
    end

newdesttype(name, options = {}, &block) click to toggle source

Create a new destination type.

    # File lib/puppet/util/log.rb, line 18
    def self.newdesttype(name, options = {}, &block)

      dest = genclass(
        name,
        :parent     => Puppet::Util::Log::Destination,
        :prefix     => "Dest",
        :block      => block,
        :hash       => @desttypes,
        :attributes => options
      )
      dest.match(dest.name)

      dest
    end

newmessage(msg) click to toggle source

Route the actual message. FIXME There are lots of things this method should do, like caching and 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.

    # File lib/puppet/util/log.rb, line 149
    def Log.newmessage(msg)
      return if @levels.index(msg.level) < @loglevel

      queuemessage(msg) if @destinations.length == 0

      @destinations.each do |name, dest|
        threadlock(dest) do
          dest.handle(msg)
        end
      end
    end

queuemessage(msg) click to toggle source

    # File lib/puppet/util/log.rb, line 161
    def Log.queuemessage(msg)
      @queued.push(msg)
    end

reopen() click to toggle source

Reopen all of our logs.

    # File lib/puppet/util/log.rb, line 192
    def Log.reopen
      Puppet.notice "Reopening log files"
      types = @destinations.keys
      @destinations.each { |type, dest|
        dest.close if dest.respond_to?(:close)
      }
      @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.setup_default
          Puppet.err detail.to_s
        end
      end
    end

sendlevel?(level) click to toggle source

    # File lib/puppet/util/log.rb, line 187
    def Log.sendlevel?(level)
      @levels.index(level) >= @loglevel
    end

setup_default() click to toggle source

    # File lib/puppet/util/log.rb, line 212
    def self.setup_default
      Log.newdestination(
        (Puppet.features.syslog?   ? :syslog   :
        (Puppet.features.eventlog? ? :eventlog : Puppet[:puppetdlog])))
    end

validlevel?(level) click to toggle source

Is the passed level a valid log level?

    # File lib/puppet/util/log.rb, line 219
    def self.validlevel?(level)
      @levels.include?(level)
    end

### Public Instance Methods

level=(level) click to toggle source

    # File lib/puppet/util/log.rb, line 250
    def level=(level)
      raise ArgumentError, "Puppet::Util::Log requires a log level" unless level
      raise ArgumentError, "Puppet::Util::Log requires a symbol or string" unless level.respond_to? "to_sym"
      @level = level.to_sym
      raise ArgumentError, "Invalid log level #{@level}" unless self.class.validlevel?(@level)

      # Tag myself with my log level
      tag(level)
    end

message=(msg) click to toggle source

    # File lib/puppet/util/log.rb, line 245
    def message=(msg)
      raise ArgumentError, "Puppet::Util::Log requires a message" unless msg
      @message = msg.to_s
    end

source=(source) click to toggle source

If they pass a source in to us, we make sure it is a string, and we retrieve any tags we can.

    # File lib/puppet/util/log.rb, line 262
    def source=(source)
      if source.respond_to?(:source_descriptors)
        descriptors = source.source_descriptors
        @source = descriptors[:path]

        descriptors[:tags].each { |t| tag(t) }

        [:file, :line].each do |param|
          next unless descriptors[param]
          send(param.to_s + "=", descriptors[param])
        end
      else
        @source = source.to_s
      end
    end

to_report() click to toggle source

    # File lib/puppet/util/log.rb, line 278
    def to_report
      "#{time} #{source} (#{level}): #{to_s}"
    end

to_s() click to toggle source

    # File lib/puppet/util/log.rb, line 282
    def to_s
      message
    end