Module: VCAP::Logging

Defined in:
lib/vcap/logging.rb,
lib/vcap/logging/error.rb,
lib/vcap/logging/logger.rb,
lib/vcap/logging/version.rb,
lib/vcap/logging/sink_map.rb,
lib/vcap/logging/log_record.rb,
lib/vcap/logging/sink/base_sink.rb,
lib/vcap/logging/formatter/base_formatter.rb

Defined Under Namespace

Modules: Formatter, Sink Classes: LogRecord, Logger, LoggingError, SinkMap

Constant Summary collapse

FORMATTER =
VCAP::Logging::Formatter::DelimitedFormatter.new do
  timestamp '[%F %T]'
  logger_name
  tags
  process_id
  thread_shortid
  fiber_shortid
  log_level
  text '--'
  data
end
LOG_LEVELS =
{
  :off    => 0,
  :fatal  => 1,
  :error  => 5,
  :warn   => 10,
  :info   => 15,
  :debug  => 16,
  :debug1 => 17,
  :debug2 => 18,
}
VERSION =
'0.1.4'

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.default_log_levelObject

Returns the value of attribute default_log_level.



37
38
39
# File 'lib/vcap/logging.rb', line 37

def default_log_level
  @default_log_level
end

Class Method Details

.add_sink(*args) ⇒ Object



119
120
121
# File 'lib/vcap/logging.rb', line 119

def add_sink(*args)
  @sink_map.add_sink(*args)
end

.initObject



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/vcap/logging.rb', line 39

def init
  fail "init() can only be called once" if @initialized
  reset

  # Ideally we would call close() on each sink. Unfortunatley, we can't be sure
  # that close runs last, and that other at_exit handlers aren't attempting to
  # log to a sink. The best we can do is enable autoflushing.
  at_exit do
    @sink_map.each_sink {|s| s.autoflush = true }
  end

  @initialized = true
end

.logger(name) ⇒ Object

Returns the logger associated with name. Creates one if it doesn’t exist. The log level will be inherited from the parent logger.

Parameters:

  • name

    String Logger name



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/vcap/logging.rb', line 104

def logger(name)
  if !@loggers.has_key?(name)
    @loggers[name] = VCAP::Logging::Logger.new(name, @sink_map)
    @loggers[name].log_level = @default_log_level
    for level, regex in @sorted_log_level_filters
      if regex.match(name)
        @loggers[name].log_level = level
        break
      end
    end
  end

  @loggers[name]
end

.resetObject

Exists primarily for testing



54
55
56
57
58
59
60
61
# File 'lib/vcap/logging.rb', line 54

def reset
  VCAP::Logging::Logger.define_log_levels(LOG_LEVELS)
  @default_log_level = pick_default_level(LOG_LEVELS)
  @sink_map = VCAP::Logging::SinkMap.new(LOG_LEVELS)
  @log_level_filters = {}
  @sorted_log_level_filters = []
  @loggers  = {}
end

.set_log_level(path_regex, log_level_name) ⇒ Object

Sets the log level to log_level for every logger whose name matches path_regex. Loggers who were previously set to this level and whose names no longer match path_regex are reset to the default level.

Parameters:

  • path_regex

    String Regular expression to use when matching against the logger name

  • log_level_name

    Symbol Name of the log level to set on all matching loggers

Raises:

  • (ArgumentError)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/vcap/logging.rb', line 129

def set_log_level(path_regex, log_level_name)
  log_level_name = log_level_name.to_sym if log_level_name.kind_of?(String)

  raise ArgumentError, "Unknown log level #{log_level_name}" unless LOG_LEVELS[log_level_name]
  regex = Regexp.new("^#{path_regex}$")

  @log_level_filters[log_level_name] = regex
  @sorted_log_level_filters = @log_level_filters.keys.sort {|a, b| LOG_LEVELS[a] <=> LOG_LEVELS[b] }.map {|lvl| [lvl, @log_level_filters[lvl]] }

  for logger_name, logger in @loggers
    if regex.match(logger_name)
      logger.log_level = log_level_name
    elsif logger.log_level == log_level_name
      # Reset any loggers at the supplied level that no longer match
      logger.log_level = @default_log_level
    end
  end
end

.setup_from_config(config = {}) ⇒ Object

Configures the logging infrastructure using a hash parsed from a config file. The config file is expected to contain a section with the following format: logging:

 level: <default_log_level>
  file: <filename>
syslog: <program name to use with the syslog sink>

This interface is limiting, but it should satisfy the majority of our use cases. I’m imagining usage will be something like:

config = YAML.load(<file>)
...
VCAP::Logging.setup_from_config(config[:logging])


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/vcap/logging.rb', line 81

def setup_from_config(config={})
  level = config[:level] || config['level']
  if level
    level_sym = level.to_sym
    raise ArgumentError, "Unknown level: #{level}" unless LOG_LEVELS[level_sym]
    @default_log_level = level_sym
  end

  logfile = config[:file] || config['file']
  # Undecided as to whether or not we should enable buffering here. For now, don't buffer to stay consistent with the current logger.
  add_sink(nil, nil, VCAP::Logging::Sink::FileSink.new(logfile, FORMATTER)) if logfile

  syslog_name = config[:syslog] || config['syslog']
  add_sink(nil, nil, VCAP::Logging::Sink::SyslogSink.new(syslog_name, :formatter => FORMATTER)) if syslog_name

  # Log to stdout if no other sinks are supplied
  add_sink(nil, nil, VCAP::Logging::Sink::StdioSink.new(STDOUT, FORMATTER)) unless (logfile || syslog_name)
end