class Lorekeeper::JSONLogger
The JSONLogger
provides a logger which will output messages in JSON format
Constants
- BLACKLISTED_FINGERPRINT
- DATA
- DATE_FORMAT
- EXCEPTION
- LEVEL
- MESSAGE
- STACK
- THREAD_KEY
- TIMESTAMP
Public Class Methods
new(file)
click to toggle source
Calls superclass method
Lorekeeper::FastLogger::new
# File lib/lorekeeper/json_logger.rb, line 9 def initialize(file) reset_state @base_fields = { MESSAGE => '', TIMESTAMP => '', LEVEL => '' } @backtrace_cleaner = set_backtrace_cleaner super(file) end
Public Instance Methods
add_fields(fields)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 53 def add_fields(fields) remove_invalid_fields(fields) state.fetch(:base_fields).merge!(fields) end
add_thread_unsafe_fields(fields)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 40 def add_thread_unsafe_fields(fields) remove_invalid_fields(fields) @base_fields.merge!(fields) reset_state # Forcing to recreate the thread safe information end
current_fields()
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 16 def current_fields state[:base_fields] end
exception(exception, custom_message = nil, custom_data = nil, custom_level = :error, message: nil, data: nil, level: nil)
click to toggle source
@param exception: instance of a class inheriting from Exception By default message comes from exception.message Optional and named parameters to overwrite message, level and add data
# File lib/lorekeeper/json_logger.rb, line 67 def exception(exception, custom_message = nil, custom_data = nil, custom_level = :error, message: nil, data: nil, level: nil) # Backwards compatible named params param_level = level || custom_level param_data = data || custom_data param_message = message || custom_message log_level = METHOD_SEVERITY_MAP[param_level] || ERROR if exception.is_a?(Exception) backtrace = clean_backtrace(exception.backtrace || []) exception_fields = { EXCEPTION => "#{exception.class}: #{exception.message}", STACK => backtrace } exception_fields[DATA] = param_data if param_data message = param_message || exception.message with_extra_fields(exception_fields) { log_data(log_level, message) } else log_data(METHOD_SEVERITY_MAP[:warn], 'Logger exception called without exception class.') message = "#{exception.class}: #{exception.inspect} #{param_message}" with_extra_fields(DATA => (param_data || {})) { log_data(log_level, message) } end end
inspect()
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 93 def inspect "Lorekeeper JSON logger. IO: #{@file.inspect}" end
remove_fields(fields)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 58 def remove_fields(fields) [*fields].each do |field| state.fetch(:base_fields).delete(field) end end
remove_thread_unsafe_fields(fields)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 46 def remove_thread_unsafe_fields(fields) [*fields].each do |field| @base_fields.delete(field) end reset_state end
reset_state()
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 24 def reset_state Thread.current[THREAD_KEY] = nil end
state()
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 20 def state Thread.current[THREAD_KEY] ||= { base_fields: @base_fields.dup, extra_fields: {} } end
Private Instance Methods
clean_backtrace(backtrace)
click to toggle source
Some instrumentation libraries pollute the stacktrace and create a large output which may cause problems with certain logging backends. Hardcording newrelic and active_support/callbacks now here. In the future if this list grows, we may make it configurable.
# File lib/lorekeeper/json_logger.rb, line 103 def clean_backtrace(backtrace) @backtrace_cleaner&.clean(backtrace) || backtrace end
log_data(severity, message)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 138 def log_data(severity, message) current_state = state # Accessing state is slow. Do it only once per call. # merging is slow, we do not want to merge with empty hash if possible fields_to_log = if current_state[:extra_fields].empty? current_state[:base_fields] else current_state[:base_fields].merge(current_state[:extra_fields]) end fields_to_log[MESSAGE] = message fields_to_log[TIMESTAMP] = Time.now.utc.strftime(DATE_FORMAT) fields_to_log[LEVEL] = SEVERITY_NAMES_MAP[severity] @iodevice.write(Oj.dump(fields_to_log) << "\n") end
remove_invalid_fields(fields)
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 132 def remove_invalid_fields(fields) fields.delete_if do |_, v| v.nil? || v.respond_to?(:empty?) && v.empty? end end
set_backtrace_cleaner()
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 107 def set_backtrace_cleaner return nil unless defined?(ActiveSupport::BacktraceCleaner) cleaner = ActiveSupport::BacktraceCleaner.new cleaner.remove_silencers! cleaner.add_silencer { |line| line.match?(BLACKLISTED_FINGERPRINT) } cleaner end
with_extra_fields(fields) { || ... }
click to toggle source
# File lib/lorekeeper/json_logger.rb, line 126 def with_extra_fields(fields) state[:extra_fields] = fields yield state[:extra_fields] = {} end