Class: Foreman::LoggingImpl

Inherits:
Object show all
Defined in:
lib/foreman/logging.rb

Defined Under Namespace

Classes: MultilinePatternLayout, MultilineRequestPatternLayout

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config


8
9
10
# File 'lib/foreman/logging.rb', line 8

def config
  @config
end

#log_directoryObject (readonly)

Returns the value of attribute log_directory


8
9
10
# File 'lib/foreman/logging.rb', line 8

def log_directory
  @log_directory
end

Instance Method Details

#add_logger(logger_name, logger_config) ⇒ Object


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/foreman/logging.rb', line 39

def add_logger(logger_name, logger_config)
  logger = ::Logging.logger[logger_name]
  if logger_config.key?(:enabled)
    if logger_config[:enabled]
      logger.additive = true
      logger.level = logger_config[:level] if logger_config.key?(:level)
    else
      # set high level for disabled logger
      logger.level = :fatal
    end
  end

  # TODO: Remove once only Logging 2.0 is supported
  if logger.respond_to?(:caller_tracing)
    logger.caller_tracing = logger_config[:log_trace] || @config[:log_trace]
  else
    logger.trace = logger_config[:log_trace] || @config[:log_trace]
  end
end

#add_loggers(loggers = {}) ⇒ Object


31
32
33
34
35
36
37
# File 'lib/foreman/logging.rb', line 31

def add_loggers(loggers = {})
  return unless loggers.is_a?(Hash)

  loggers.each do |name, config|
    add_logger(name, config)
  end
end

#blob(message, contents, extra_fields = {}) ⇒ Object


110
111
112
113
114
115
116
117
118
# File 'lib/foreman/logging.rb', line 110

def blob(message, contents, extra_fields = {})
  logger_name = extra_fields[:logger] || 'blob'
  with_fields(extra_fields) do
    logger(logger_name).info do
      message + "\n" + contents
    end
  end
  contents
end

#configure(options = {}) ⇒ Object


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/foreman/logging.rb', line 10

def configure(options = {})
  fail 'logging can be configured only once' if @configured
  @configured = true

  @log_directory = options.fetch(:log_directory, './log')
  ensure_log_directory(@log_directory)

  load_config(options.fetch(:environment), options.fetch(:config_overrides, {}))

  # override via Rails env var
  @config[:type] = 'stdout' if ENV['RAILS_LOG_TO_STDOUT']

  configure_color_scheme
  configure_root_logger(options)
  add_console_appender if @config[:console_inline]

  # we need to postpone loading of the silenced logger
  # to the time the Logging::LEVELS is initialized
  require_dependency File.expand_path('silenced_logger', __dir__)
end

#exception(context_message, exception, options = {}) ⇒ Object

Standard way for logging exceptions to get the most data in the log. The behaviour can be influenced by this options:

* :logger - the name of the logger to put the exception in ('app' by default)
* :level - the logging level (:warn by default)

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/foreman/logging.rb', line 85

def exception(context_message, exception, options = {})
  options.assert_valid_keys :level, :logger
  logger_name = options[:logger] || 'app'
  level = options[:level] || :warn
  backtrace_level = options[:backtrace_level] || :info
  unless ::Logging::LEVELS.key?(level.to_s)
    raise "Unexpected log level #{level}, expected one of #{::Logging::LEVELS.keys}"
  end
  # send class, message and stack as structured fields in addition to message string
  backtrace = exception.backtrace || []
  extra_fields = {
    exception_class: exception.class.name,
    exception_message: exception.message,
    exception_backtrace: backtrace,
  }
  extra_fields[:foreman_code] = exception.code if exception.respond_to?(:code)
  with_fields(extra_fields) do
    logger(logger_name).public_send(level) { context_message }
  end
  # backtrace have its own separate level to prevent flooding logs with backtraces
  logger(logger_name).public_send(backtrace_level) do
    "Backtrace for '#{context_message}' error (#{exception.class}): #{exception.message}\n" + backtrace.join("\n")
  end
end

#logger(name) ⇒ Object


63
64
65
66
# File 'lib/foreman/logging.rb', line 63

def logger(name)
  return Foreman::SilencedLogger.new(::Logging.logger[name]) if ::Logging::Repository.instance.has_logger?(name)
  fail "Trying to use logger #{name} which has not been configured."
end

#logger_level(name) ⇒ Object


68
69
70
71
# File 'lib/foreman/logging.rb', line 68

def logger_level(name)
  level_int = logger(name).level
  ::Logging::LEVELS.find { |n, i| i == level_int }.first
end

#loggersObject


59
60
61
# File 'lib/foreman/logging.rb', line 59

def loggers
  ::Logging::Repository.instance.children('root').map(&:name)
end

#with_fields(fields = {}) ⇒ Object

Structured fields to log in addition to log messages. Every log line created within given block is enriched with these fields. Fields appear in joruand and/or JSON output (hash named 'ndc').


75
76
77
78
79
# File 'lib/foreman/logging.rb', line 75

def with_fields(fields = {})
  ::Logging.ndc.push(fields) do
    yield
  end
end