Class: Puppet::Util::Log

Inherits:
Object show all
Extended by:
Puppet::Util, ClassGen
Includes:
Network::FormatSupport, Puppet::Util, Tagging
Defined in:
lib/puppet/util/log.rb

Overview

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.

Defined Under Namespace

Classes: Destination, RateLimitedLogger

Constant Summary

Constants included from Puppet::Util

AbsolutePathPosix, AbsolutePathWindows, DEFAULT_POSIX_MODE, DEFAULT_WINDOWS_MODE

Constants included from POSIX

POSIX::LOCALE_ENV_VARS, POSIX::USER_ENV_VARS

Constants included from SymbolicFileMode

SymbolicFileMode::SetGIDBit, SymbolicFileMode::SetUIDBit, SymbolicFileMode::StickyBit, SymbolicFileMode::SymbolicMode, SymbolicFileMode::SymbolicSpecialToBit

Constants included from Tagging

Tagging::ValidTagRegex

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Puppet::Util

absolute_path?, activerecord_version, benchmark, binread, chuser, classproxy, deterministic_rand, execfail, execpipe, execute, exit_on_fail, logmethods, memory, path_to_uri, pretty_backtrace, proxy, replace_file, safe_posix_fork, symbolizehash, thinmark, uri_to_path, which, withenv, withumask

Methods included from POSIX

#get_posix_field, #gid, #idfield, #methodbyid, #methodbyname, #search_posix_field, #uid

Methods included from SymbolicFileMode

#normalize_symbolic_mode, #symbolic_mode_to_int, #valid_symbolic_mode?

Methods included from ClassGen

genclass, genmodule, rmclass

Methods included from MethodHelper

#requiredopts, #set_options, #symbolize_options

Methods included from Network::FormatSupport

included, #mime, #render, #support_format?, #to_msgpack

Methods included from Tagging

#raw_tagged?, #tag, #tagged?, #tags, #tags=

Constructor Details

#initialize(args) ⇒ Log

Returns a new instance of Log.



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/puppet/util/log.rb', line 250

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

Class Attribute Details

.desttypesObject (readonly)



46
47
48
# File 'lib/puppet/util/log.rb', line 46

def desttypes
  @desttypes
end

Instance Attribute Details

#fileObject



247
248
249
# File 'lib/puppet/util/log.rb', line 247

def file
  @file
end

#levelObject



248
249
250
# File 'lib/puppet/util/log.rb', line 248

def level
  @level
end

#lineObject



247
248
249
# File 'lib/puppet/util/log.rb', line 247

def line
  @line
end

#messageObject



248
249
250
# File 'lib/puppet/util/log.rb', line 248

def message
  @message
end

#remoteObject



247
248
249
# File 'lib/puppet/util/log.rb', line 247

def remote
  @remote
end

#sourceObject



247
248
249
# File 'lib/puppet/util/log.rb', line 247

def source
  @source
end

#timeObject



247
248
249
# File 'lib/puppet/util/log.rb', line 247

def time
  @time
end

Class Method Details

.autoflush=(v) ⇒ Object



73
74
75
76
77
# File 'lib/puppet/util/log.rb', line 73

def Log.autoflush=(v)
  @destinations.each do |type, dest|
    dest.autoflush = v if dest.respond_to?(:autoflush=)
  end
end

.close(destination) ⇒ Object

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



51
52
53
54
55
56
57
# File 'lib/puppet/util/log.rb', line 51

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_allObject

Raises:



59
60
61
62
63
64
# File 'lib/puppet/util/log.rb', line 59

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) ⇒ Object

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

Raises:



81
82
83
84
85
# File 'lib/puppet/util/log.rb', line 81

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

.destinationsObject



87
88
89
# File 'lib/puppet/util/log.rb', line 87

def Log.destinations
  @destinations
end

.eachlevelObject

Yield each valid level in turn



92
93
94
# File 'lib/puppet/util/log.rb', line 92

def Log.eachlevel
  @levels.each { |level| yield level }
end

.flushObject

Flush any log destinations that support such operations.



67
68
69
70
71
# File 'lib/puppet/util/log.rb', line 67

def Log.flush
  @destinations.each { |type, dest|
    dest.flush if dest.respond_to?(:flush)
  }
end

.flushqueueObject



178
179
180
181
182
183
184
# File 'lib/puppet/util/log.rb', line 178

def Log.flushqueue
  return unless @destinations.size >= 1
  @queued.each do |msg|
    Log.newmessage(msg)
  end
  @queued.clear
end

.force_flushqueueObject

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.

Returns:

  • nil



193
194
195
196
197
198
# File 'lib/puppet/util/log.rb', line 193

def Log.force_flushqueue()
  if (@destinations.empty? and !(@queued.empty?))
    newdestination(:console)
  end
  flushqueue
end

.from_data_hash(data) ⇒ Object



236
237
238
239
240
# File 'lib/puppet/util/log.rb', line 236

def self.from_data_hash(data)
  obj = allocate
  obj.initialize_from_hash(data)
  obj
end

.from_pson(data) ⇒ Object



242
243
244
245
# File 'lib/puppet/util/log.rb', line 242

def self.from_pson(data)
  Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
  self.from_data_hash(data)
end

.levelObject

Return the current log level.



97
98
99
# File 'lib/puppet/util/log.rb', line 97

def Log.level
  @levels[@loglevel]
end

.level=(level) ⇒ Object

Set the current log level.

Raises:



102
103
104
105
106
107
108
# File 'lib/puppet/util/log.rb', line 102

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

.levelsObject



110
111
112
# File 'lib/puppet/util/log.rb', line 110

def Log.levels
  @levels.dup
end

.newdestination(dest) ⇒ Object

Create a new log destination.

Raises:



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/puppet/util/log.rb', line 115

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) ⇒ Object

Create a new destination type.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/puppet/util/log.rb', line 20

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) ⇒ Object

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.



164
165
166
167
168
169
170
171
172
# File 'lib/puppet/util/log.rb', line 164

def Log.newmessage(msg)
  return if @levels.index(msg.level) < @loglevel

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

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

.queuemessage(msg) ⇒ Object



174
175
176
# File 'lib/puppet/util/log.rb', line 174

def Log.queuemessage(msg)
  @queued.push(msg)
end

.reopenObject

Reopen all of our logs.



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/puppet/util/log.rb', line 205

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) ⇒ Boolean

Returns:

  • (Boolean)


200
201
202
# File 'lib/puppet/util/log.rb', line 200

def Log.sendlevel?(level)
  @levels.index(level) >= @loglevel
end

.setup_defaultObject



225
226
227
228
229
# File 'lib/puppet/util/log.rb', line 225

def self.setup_default
  Log.newdestination(
    (Puppet.features.syslog?   ? :syslog   :
    (Puppet.features.eventlog? ? :eventlog : Puppet[:puppetdlog])))
end

.validlevel?(level) ⇒ Boolean

Is the passed level a valid log level?

Returns:

  • (Boolean)


232
233
234
# File 'lib/puppet/util/log.rb', line 232

def self.validlevel?(level)
  @levels.include?(level)
end

.with_destination(destination, &block) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/puppet/util/log.rb', line 147

def Log.with_destination(destination, &block)
  if @destinations.include?(destination)
    yield
  else
    newdestination(destination)
    begin
      yield
    ensure
      close(destination)
    end
  end
end

Instance Method Details

#initialize_from_hash(data) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/puppet/util/log.rb', line 269

def initialize_from_hash(data)
  @level = data['level'].intern
  @message = data['message']
  @source = data['source']
  @tags = Puppet::Util::TagSet.new(data['tags'])
  @time = data['time']
  if @time.is_a? String
    @time = Time.parse(@time)
  end
  @file = data['file'] if data['file']
  @line = data['line'] if data['line']
end

#to_data_hashObject



286
287
288
289
290
291
292
293
294
295
296
# File 'lib/puppet/util/log.rb', line 286

def to_data_hash
  {
    'level' => @level,
    'message' => @message,
    'source' => @source,
    'tags' => @tags,
    'time' => @time.iso8601(9),
    'file' => @file,
    'line' => @line,
  }
end

#to_hashObject



282
283
284
# File 'lib/puppet/util/log.rb', line 282

def to_hash
  self.to_data_hash
end

#to_pson(*args) ⇒ Object



298
299
300
# File 'lib/puppet/util/log.rb', line 298

def to_pson(*args)
  to_data_hash.to_pson(*args)
end

#to_reportObject



330
331
332
# File 'lib/puppet/util/log.rb', line 330

def to_report
  "#{time} #{source} (#{level}): #{to_s}"
end

#to_sObject



334
335
336
# File 'lib/puppet/util/log.rb', line 334

def to_s
  message
end