Class: RightScale::Log

Inherits:
Object show all
Includes:
RightSupport::Ruby::EasySingleton
Defined in:
lib/right_agent/log.rb

Overview

Logs both to syslog and to local file

Defined Under Namespace

Classes: Formatter

Constant Summary collapse

LEVELS_MAP =

Map of log levels symbols associated with corresponding Logger constant

{:debug => Logger::DEBUG,
:info  => Logger::INFO,
:warn  => Logger::WARN,
:error => Logger::ERROR,
:fatal => Logger::FATAL}
@@inverted_levels_map =
nil

Instance Method Summary collapse

Constructor Details

#initializeLog

Returns a new instance of Log.



117
118
119
120
121
# File 'lib/right_agent/log.rb', line 117

def initialize
  # Was log ever used?
  @initialized = false
  @logger = RightSupport::Log::NullLogger.new  # ensures respond_to? works before init is called
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args) ⇒ Object

Forward all method calls to underlying Logger object created with init Return the result of only the first registered logger to keep the interface consistent with that of a Logger

Parameters

m(Symbol)

Forwarded method name

args(Array)

Forwarded method arguments

Return

(Object)

Result from first registered logger



133
134
135
136
137
# File 'lib/right_agent/log.rb', line 133

def method_missing(m, *args)
  init unless @initialized
  @logger.level = level_from_sym(level) if @level_frozen
  @logger.send(m, *args)
end

Instance Method Details

#add_logger(logger) ⇒ Object

Add new logger to list of multiplexed loggers

Parameters

logger(Object)

Logger that should get log messages

Return

@logger(RightScale::Multiplexer)

Multiplexer logger



259
260
261
262
263
# File 'lib/right_agent/log.rb', line 259

def add_logger(logger)
  init unless @initialized
  logger.level = level_from_sym(Log.instance.level)
  @logger.add(logger)
end

#error(description, exception = nil, backtrace = :caller) ⇒ Object

Log error and optionally append exception information

Parameters

description(String)

Error description

exception(Exception|String)

Associated exception or other parenthetical error information

backtrace(Symbol)

Exception backtrace extent: :no_trace, :caller, or :trace,

defaults to :caller

Return

(Object)

Result from first registered logger



180
181
182
183
# File 'lib/right_agent/log.rb', line 180

def error(description, exception = nil, backtrace = :caller)
  init unless @initialized
  @logger.error(format(description, exception, backtrace))
end

#facility=(facility) ⇒ Object

Sets the syslog facility that will be used when emitting syslog messages. Can only be successfully called before logging is initialized

Parameters

facility(String)

A syslog facility name, e.g. ‘user’ or ‘local0’

Return

program_name(String)

The input string

Raise

RuntimeError

If logger is already initialized



329
330
331
332
# File 'lib/right_agent/log.rb', line 329

def facility=(facility)
  raise 'Logger already initialized' if @initialized
  @facility = facility
end

#force_debugObject

Force log level to debug and disregard any further attempt to change it

Return

true

Always return true



396
397
398
399
# File 'lib/right_agent/log.rb', line 396

def force_debug
  self.level = :debug
  @level_frozen = true
end

#force_logger(logger) ⇒ Object

Force use of given logger and override all defaults

Parameters

logger(Logger)

Logger compatible object

Return

true

Always return true



408
409
410
411
# File 'lib/right_agent/log.rb', line 408

def force_logger(logger)
  @initialized = true
  @logger = logger
end

#format(description, exception = nil, backtrace = :caller) ⇒ Object

Format error information

Parameters

description(String)

Error description

exception(Exception|String)

Associated exception or other parenthetical error information

backtrace(Symbol)

Exception backtrace extent: :no_trace, :caller, or :trace,

defaults to :caller

Return

(Object)

Result from first registered logger



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/right_agent/log.rb', line 195

def format(description, exception = nil, backtrace = :caller)
  if exception
    if exception.respond_to?(:message)
      description += " (#{exception.class}: #{exception.message}"
    else
      description += " (#{exception}"
      backtrace = :no_trace
    end
    case backtrace
    when :no_trace then description += ")"
    when :caller   then description += " in " + exception.backtrace[0] + ")"
    when :trace    then description += " in\n  " + exception.backtrace.join("\n  ") + ")"
    end
  end
  description
end

#init(identity = nil, path = nil, opts = {}) ⇒ Object

Initialize logger

Parameters

identity(String)

Log identity

path(String)

Log directory path

opts(TrueClass|FalseClass)

Whether to re-initialize if logger is already initialized

opts(TrueClass|FalseClass)

Whether to print to STDOUT log destination

Return

logger(RightScale::Multiplexer)

logger instance



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/right_agent/log.rb', line 424

def init(identity=nil, path=nil, opts={})
  if opts[:force] || !@initialized
    @initialized = true
    @level_frozen = false
    logger = nil

    if @log_to_file_only || Platform.windows?
      if path
        file = File.join(path, "#{identity}.log")
      else
        file = STDOUT
      end
      $stderr.puts "Logging to #{file}" if opts[:print]
      logger = Logger.new(file)
      logger.formatter = Formatter.new
      logger.progname = @program_name || identity || 'RightAgent'
      logger.formatter.datetime_format = "%b %d %H:%M:%S"
    else
      $stderr.puts "Logging to syslog" if opts[:print]
      program_name = @program_name || identity || 'RightAgent'
      facility = @facility || 'local0'
      logger = RightSupport::Log::SystemLogger.new(program_name, :facility=>facility)
    end

    @logger = Multiplexer.new(logger)
    self.level = :info
  end
  @logger
end

#initializedObject

Was logger initialized?

Return

true

if logger has been initialized

false

Otherwise



296
297
298
# File 'lib/right_agent/log.rb', line 296

def initialized
  @initialized
end

#levelObject

Current log level

Return

level(Symbol)

One of :debug, :info, :warn, :error or :fatal



372
373
374
375
# File 'lib/right_agent/log.rb', line 372

def level
  init unless @initialized
  level = level_to_sym(@level)
end

#level=(level) ⇒ Object

Sets the level for the Logger by symbol or by Logger constant

Parameters

level(Object)

One of :debug, :info, :warn, :error, :fatal or one of “debug”, “info”, “warn”, “error”, “fatal” or one of Logger::INFO … Logger::FATAL

Return

level(Symbol)

New log level, or current level if frozen



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/right_agent/log.rb', line 343

def level=(level)
  init unless @initialized
  unless @level_frozen
    new_level = case level
    when Symbol then
      level_from_sym(level)
    when String then
      level_from_sym(level.to_sym)
    else
      level
    end
    if new_level != @level
      @logger.info("[setup] Setting log level to #{level_to_sym(new_level).to_s.upcase}")
      if new_level == Logger::DEBUG && !RightScale::Platform.windows?
        @logger.info("[setup] Check syslog configuration to ensure debug messages are not discarded!")
      else
      end
      @logger.level = @level = new_level
    end
    # Notify even if unchanged since don't know when callback was set
    @notify.each { |n| n.call(@level) } if @notify
  end
  level = level_to_sym(@level)
end

#level_from_sym(sym) ⇒ Object

Map symbol log level to Logger constant

Parameters

sym(Symbol)

Log level symbol, one of :debug, :info, :warn, :error or :fatal

Return

lvl(Constant)

One of Logger::DEBUG … Logger::FATAL

Raise

(ArgumentError)

if level symbol is invalid

Raises:

  • (ArgumentError)


222
223
224
225
# File 'lib/right_agent/log.rb', line 222

def level_from_sym(sym)
  raise ArgumentError, "Invalid log level symbol :#{sym}" unless LEVELS_MAP.include?(sym)
  lvl = LEVELS_MAP[sym]
end

#level_to_sym(lvl) ⇒ Object

Map Logger log level constant to symbol

Parameters

lvl(Constant)

Log level constant, one of Logger::DEBUG … Logger::FATAL

Return

sym(Symbol)

One of :debug, :info, :warn, :error or :fatal

Raise

(ArgumentError)

if level is invalid

Raises:

  • (ArgumentError)


237
238
239
240
241
# File 'lib/right_agent/log.rb', line 237

def level_to_sym(lvl)
  @@inverted_levels_map ||= LEVELS_MAP.invert
  raise ArgumentError, "Invalid log level: #{lvl}" unless @@inverted_levels_map.include?(lvl)
  sym = @@inverted_levels_map[lvl]
end

#log_to_file_only(val) ⇒ Object

Set whether syslog should be used or to log to an agent-specific file This should be called before anything else

Parameters

val(Boolean)

Whether syslog should be used (false) or a agent-specific log file (true)

Raise

RuntimeError

If logger is already initialized



286
287
288
289
# File 'lib/right_agent/log.rb', line 286

def log_to_file_only(val)
  raise 'Logger already initialized' if @initialized
  @log_to_file_only = !!val
end

#loggerObject

Read access to internal multiplexer

Return

logger(RightScale::Multiplexer)

Multiplexer logger



247
248
249
250
# File 'lib/right_agent/log.rb', line 247

def logger
  init unless @initialized
  logger = @logger
end

#notify(callback) ⇒ Object

Register callback to be activated when there is a logging configuration change Currently the only logging change reported is log level

Parameters

callback(Proc)

Block to be activated with following parameter when log level changes:

log_level(Symbol)

Current log level

Return

true

Always return true



386
387
388
389
# File 'lib/right_agent/log.rb', line 386

def notify(callback)
  @notify = (@notify ||= []) << callback
  true
end

#program_name=(prog_name) ⇒ Object

Sets the syslog program name that will be reported Can only be successfully called before logging is initialized

Parameters

prog_name(String)

An arbitrary string, or “nil” to use

the default name that is based on the agent's identity

Return

program_name(String)

The input string

Raise

RuntimeError

If logger is already initialized



313
314
315
316
# File 'lib/right_agent/log.rb', line 313

def program_name=(prog_name)
  raise 'Logger already initialized' if @initialized
  @program_name = prog_name
end

#remove_logger(logger) ⇒ Object

Remove logger from list of multiplexed loggers

Parameters

logger(Object)

Logger to be removed

Return

@logger(RightScale::Multiplexer)

Multiplexer logger



272
273
274
275
# File 'lib/right_agent/log.rb', line 272

def remove_logger(logger)
  init unless @initialized
  @logger.remove(logger)
end

#respond_to?(m) ⇒ Boolean

Determine whether this object, or its method_missing proxy, responds to the given method name. This follows the best practice of always overriding #respond_to? whenever one implements dynamic dispatch via #method_missing.

Parameters

m(Symbol)

Forwarded method name

Return

(true|false)

True if this object or its proxy responds to the names method, false otherwise

Returns:

  • (Boolean)


149
150
151
# File 'lib/right_agent/log.rb', line 149

def respond_to?(m)
  super(m) || @logger.respond_to?(m)
end

#warning(description, exception = nil, backtrace = :caller) ⇒ Object Also known as: warn

Log warning and optionally append exception information

Parameters

description(String)

Error description

exception(Exception|String)

Associated exception or other parenthetical error information

backtrace(Symbol)

Exception backtrace extent: :no_trace, :caller, or :trace,

defaults to :caller

Return

(Object)

Result from first registered logger



163
164
165
166
# File 'lib/right_agent/log.rb', line 163

def warning(description, exception = nil, backtrace = :caller)
  init unless @initialized
  @logger.warn(format(description, exception, backtrace))
end