class Logrb
Logrb
provides a facility for working with logs in text and json formats. All instances share a single mutex to ensure logging consistency. The following attributes are available:
fields - A hash containing metadata to be included in logs emitted by this
instance.
level - The level filter for the instance. Valid values are :error, :fatal,
:info, :warn, and :debug
format - The format to output logs. Supports :text and :json.
Each instance exposes the following methods, which accepts an arbitrary number of key-value pairs to be included in the logged message:
error
(msg, error=nil, **fields): Outputs an error entry. When `error` is
present, attempts to obtain backtrace information and also includes it to the emitted entry.
fatal
(msg, **fields): Outputs a fatal entry. Calling fatal causes the
current process to exit with a status 1
warn(msg, **fields): Outputs a warning entry. info(msg, **fields): Outputs a informational entry. debug(msg, **fields): Outputs a debug entry. dump
(msg, data=nil): Outputs a given String or Array of bytes using the
same format as `hexdump -C`.
Constants
- BACKGROUNDS
- COLORS
- LEVELS
- VERSION
Attributes
Public Class Methods
Internal: A mutex instance used for synchronizing the usage of the output IO.
# File lib/logrb.rb, line 62 def self.mutex @mutex ||= Mutex.new end
Initializes a new Logger instance that outputs logs to a provided output.
output - an IO-like object that implements a write method. format - Optional. Indicates the format used to output log entries.
Supports :text (default) and :json.
level - Level to filter this logger instance fields - Fields to include in emitted entries
# File lib/logrb.rb, line 73 def initialize(output, format: :text, level: :debug, **fields) @output = output @format = format @fields = fields @level = level end
Public Instance Methods
Public: Dumps a given String or Array in the same format as `hexdump -C`.
# File lib/logrb.rb, line 119 def dump(log, data = nil, **fields) return if LEVELS[@level] > LEVELS[:debug] if data.nil? data = log log = nil end data = data.pack("C*") if data.is_a? Array dump = [] padding = @format == :json ? "" : " " Hexdump.dump(data, output: dump) dump.map! { |line| "#{padding}#{line.chomp}" } dump = dump.join("\n") if @format == :json fields[:dump] = dump dump = nil end wrap(:dump, log || "", nil, fields) write_output("#{dump}\n\n") unless dump.nil? end
Public: Emits an error to the log output. When error is provided, this method attempts to gather a stacktrace to include in the emitted entry.
# File lib/logrb.rb, line 102 def error(msg, error = nil, **fields) return if LEVELS[@level] > LEVELS[:error] wrap(:error, msg, error, fields) nil end
Public: Emits a fatal message to the log output, and invokes Kernel#exit with a non-zero status code. When error is provided, this method attempts to gather a stacktrace to include in the emitted entry. This log entry cannot be filtered, and is always emitted.
# File lib/logrb.rb, line 113 def fatal(msg, error = nil, **fields) wrap(:fatal, msg, error, fields) exit 1 end
Returns a new logger instance using the same output of its parent's, with an optional set of fields to be merged against the parent's fields.
fields - A Hash containing metadata to be included in all output entries
emitted from the returned instance.
# File lib/logrb.rb, line 85 def with_fields(**fields) inst = Logrb.new(@output, format: @format, level: @level) inst.fields = @fields.merge(fields) inst end
Private Instance Methods
Internal: Attempts to obtain a backtrace from a provided object. In case the object does not include backtrace metadata, uses stack_trace
as a fallback.
# File lib/logrb.rb, line 236 def backtrace(from) if from.respond_to?(:backtrace_locations) && !from.backtrace_locations.nil? stack_trace(from.backtrace_locations) else stack_trace end end
Internal: Removes all backtrace frames pointing to the logging facility itself.
# File lib/logrb.rb, line 159 def clean_caller_locations caller_locations.reject { |t| t.absolute_path&.end_with?("logrb.rb") } end
Internal: Formats a given text using the ANSI escape sequences. Notice that this method does not attempt to determine whether the current output supports escape sequences.
# File lib/logrb.rb, line 147 def color(color, text) bg = BACKGROUNDS[color] reset_bg = "" if bg bg = "\e[#{bg}m" reset_bg = "\e[49m" end "#{bg}\e[#{COLORS[color]}m#{text}\e[#{COLORS[:reset]}m#{reset_bg}" end
Internal: Composes a log line with given information. level - The severity of the log message caller_meta - An Array containing the caller's location and name msg - The message to be logged fields - A Hash of fields to be included in the entry
# File lib/logrb.rb, line 196 def compose_line(level, caller_meta, msg, fields) ts = Time.now.strftime("%Y-%m-%dT%H:%M:%S.%L%z") msg = " #{msg}" unless msg.empty? fields_str = if fields.empty? "" else " #{fields}" end level_str = color(level, level.to_s.upcase) "#{ts} #{level_str}: #{caller_meta.last}:#{msg}#{fields_str}" end
Internal: Returns the caller of a function, returning a pair containing its path and base method name.
# File lib/logrb.rb, line 165 def determine_caller c = clean_caller_locations.first [normalize_location(c), c.base_label] end
Internal: Logs a JSON entry to the current output. level - The severity of the message to be logged. msg - The message to be logged error - Either an Exception object or nil. This parameter is used
to provide extra information on the logged entry.
fields - A Hash containing metadata to be included in the logged
entry.
caller_meta - An Array containing the caller's location and name.
# File lib/logrb.rb, line 260 def json(level, msg, error, fields, caller_meta) fields ||= {} fields.merge! @fields data = { level: level, caller: caller_meta.first, msg: msg, ts: Time.now.utc.to_i } data[:stacktrace] = backtrace(error) if level == :error data.merge!(fields) write_output("#{data.to_json}\n") end
Internal: Performs a cleanup for a given backtrace frame.
trace - Trace to be clean. include_function_name - Optional. When true, includes the function name
on the normalized string. Defaults to false.
# File lib/logrb.rb, line 175 def normalize_location(trace, include_function_name: false) path = trace.absolute_path return trace.to_s if path.nil? if (root = Gem.path.find { |p| path.start_with?(p) }) path = "$GEM_PATH#{path[root.length..]}" end "#{path}:#{trace.lineno}#{include_function_name ? " in `#{trace.label}'" : ""}" end
Internal: Returns a string containing a stacktrace of the current invocation.
# File lib/logrb.rb, line 187 def stack_trace(trace = clean_caller_locations) trace.map { |s| normalize_location(s, include_function_name: true) }.join("\n") end
Internal: Logs a text entry to the current output. level - The severity of the message to be logged. msg - The message to be logged error - Either an Exception object or nil. This parameter is used
to provide extra information on the logged entry.
fields - A Hash containing metadata to be included in the logged
entry.
caller_meta - An Array containing the caller's location and name.
# File lib/logrb.rb, line 216 def text(level, msg, error, fields, caller_meta) fields ||= {} fields.merge! @fields write_output(compose_line(level, caller_meta, msg, fields)) if (error_message = error&.message) write_output(": #{error_message}") end write_output("\n") return unless level == :error backtrace_str = backtrace(error) .split("\n") .map { |s| " #{s}" }.join("\n") write_output(backtrace_str) write_output("\n") end
Internal: Writes a given value to the current's output IO. Calls to this method are thread-safe.
# File lib/logrb.rb, line 246 def write_output(text) Logrb.mutex.synchronize do @output.write(text) end end