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



263
264
265
266
267
# File 'lib/right_agent/log.rb', line 263

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



333
334
335
336
# File 'lib/right_agent/log.rb', line 333

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



400
401
402
403
# File 'lib/right_agent/log.rb', line 400

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



412
413
414
415
# File 'lib/right_agent/log.rb', line 412

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
211
212
213
214
# 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
    if exception.respond_to?(:backtrace) && exception.backtrace
      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
    else
      description += ")"
    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



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
453
454
455
456
# File 'lib/right_agent/log.rb', line 428

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



300
301
302
# File 'lib/right_agent/log.rb', line 300

def initialized
  @initialized
end

#levelObject

Current log level

Return

level(Symbol)

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



376
377
378
379
# File 'lib/right_agent/log.rb', line 376

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



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/right_agent/log.rb', line 347

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)


226
227
228
229
# File 'lib/right_agent/log.rb', line 226

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)


241
242
243
244
245
# File 'lib/right_agent/log.rb', line 241

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



290
291
292
293
# File 'lib/right_agent/log.rb', line 290

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



251
252
253
254
# File 'lib/right_agent/log.rb', line 251

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



390
391
392
393
# File 'lib/right_agent/log.rb', line 390

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



317
318
319
320
# File 'lib/right_agent/log.rb', line 317

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



276
277
278
279
# File 'lib/right_agent/log.rb', line 276

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

#respond_to?(m, *args) ⇒ 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, *args)
  super(m, *args) || @logger.respond_to?(m, *args)
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