class TTY::Logger
Constants
- LOG_TYPES
- VERSION
Public Class Methods
Logger
configuration instance
@api public
# File lib/tty/logger.rb, line 61 def self.config @config ||= Config.new end
Global logger configuration
@api public
# File lib/tty/logger.rb, line 68 def self.configure yield config end
Macro to dynamically define log types
@api private
# File lib/tty/logger.rb, line 34 def self.define_level(name, log_level = nil) const_level = (LOG_TYPES[name.to_sym] || log_level)[:level] loc = caller_locations(0, 1)[0] if loc file, line = loc.path, loc.lineno + 7 else file, line = __FILE__, __LINE__ + 3 end class_eval(<<-EOL, file, line) def #{name}(*msg, &block) log(:#{const_level}, *msg, &block) end EOL end
Create a logger instance
@example
logger = TTY::Logger.new(output: $stdout)
@param [IO] output
the output object, can be stream
@param [Hash] fields
the data fields for each log message
@api public
# File lib/tty/logger.rb, line 91 def initialize(output: nil, fields: {}) @fields = fields @config = if block_given? conf = Config.new yield(conf) conf else self.class.config end @level = @config.level @handlers = @config.handlers @output = output || @config.output @ready_handlers = [] @data_filter = DataFilter.new(@config.filters.data, mask: @config.filters.mask) @types = LOG_TYPES.dup @config.types.each do |name, log_level| add_type(name, log_level) end @handlers.each do |handler| add_handler(handler) end end
Public Instance Methods
Add handler for logging messages
@example
add_handler(:console)
@example
add_handler(:console, styles: { info: { color: :yellow } })
@example
add_handler([:console, message_format: "%-10s"])
@param [Symbol, Handlers] handler
the handler name or class
@api public
# File lib/tty/logger.rb, line 147 def add_handler(handler, **options) h, h_opts = *(handler.is_a?(Array) ? handler : [handler, options]) handler_type = coerce_handler(h) global_opts = { output: @output, config: @config } opts = global_opts.merge(h_opts) ready_handler = handler_type.new(**opts) @ready_handlers << ready_handler end
Add new log type
@example
add_type(:thanks, {level: :info})
@api private
# File lib/tty/logger.rb, line 123 def add_type(name, log_level) if @types.include?(name) raise Error, "Already defined log type #{name.inspect}" end @types[name.to_sym] = log_level self.class.define_level(name, log_level) end
Coerce handler name into object
@example
coerce_handler(:console) # => TTY::Logger::Handlers::Console
@raise [Error] when class cannot be coerced
@return [Class]
@api private
# File lib/tty/logger.rb, line 178 def coerce_handler(name) case name when String, Symbol Handlers.const_get(name.capitalize) when Class name else raise_handler_error end rescue NameError raise_handler_error end
Instance logger configuration
@api public
# File lib/tty/logger.rb, line 75 def configure yield @config end
Copy this logger
@example
logger = TTY::Logger.new child_logger = logger.copy(app: "myenv", env: "prod") child_logger.info("Deploying")
@return [TTY::Logger]
a new copy of this logger
@api public
# File lib/tty/logger.rb, line 209 def copy(new_fields) new_config = @config.to_proc.call(Config.new) if block_given? yield(new_config) end self.class.new(fields: @fields.merge(new_fields), output: @output, &new_config) end
Create a new error instance copy
@param [Exception] error @param [String] message @param [Array,nil] backtrace
@return [Exception]
@api private
# File lib/tty/logger.rb, line 333 def copy_error(error, message, backtrace = nil) new_error = error.exception(message) new_error.set_backtrace(backtrace) new_error end
Filter message parts for any sensitive information and replace with placeholder.
@param [Array] objects
the messages to filter
@return [Array]
the filtered message
@api private
# File lib/tty/logger.rb, line 312 def filter(*objects) objects.map do |obj| case obj when Exception backtrace = Array(obj.backtrace).map { |line| swap_filtered(line) } copy_error(obj, swap_filtered(obj.message), backtrace) else swap_filtered(obj.to_s) end end end
Log a message given the severtiy level
@example
logger.log(:info, "Deployed successfully")
@example
logger.log(:info) { "Deployed successfully" }
@api public
# File lib/tty/logger.rb, line 253 def log(current_level, *msg) scoped_fields = msg.last.is_a?(::Hash) ? msg.pop : {} fields_copy = scoped_fields.dup if msg.empty? && block_given? msg = [] Array[yield].flatten(1).each do |el| el.is_a?(::Hash) ? fields_copy.merge!(el) : msg << el end end top_caller = caller_locations(1, 1)[0] loc = caller_locations(2, 1)[0] || top_caller label = top_caller.label metadata = { level: current_level, time: Time.now, pid: Process.pid, name: @types.include?(label.to_sym) ? label : current_level, path: loc.path, lineno: loc.lineno, method: loc.base_label } event = Event.new(filter(*msg), @data_filter.filter(@fields.merge(fields_copy)), metadata) @ready_handlers.each do |handler| level = handler.respond_to?(:level) ? handler.level : @config.level handler.(event) if log?(level, current_level) end self end
Check current level against another
@return [Symbol]
@api public
# File lib/tty/logger.rb, line 223 def log?(level, other_level) compare_levels(level, other_level) != :gt end
Change current log level for the duration of the block
@example
logger.log_at :debug do logger.debug("logged") end
@param [String] tmp_level
the temporary log level
@api public
# File lib/tty/logger.rb, line 296 def log_at(tmp_level, &block) @ready_handlers.each do |handler| handler.log_at(tmp_level, &block) end end
Raise error when unknown handler name
@api private
# File lib/tty/logger.rb, line 194 def raise_handler_error raise Error, "Handler needs to be a class name or a symbol name" end
Remove log events handler
@example
remove_handler(:console)
@api public
# File lib/tty/logger.rb, line 162 def remove_handler(handler) handler_type = coerce_handler(handler) @ready_handlers.delete_if { |_handler| _handler.is_a?(handler_type) } end
Swap string content for filtered content
@param [String] obj
@api private
# File lib/tty/logger.rb, line 344 def swap_filtered(obj) obj.dup.tap do |obj_copy| @config.filters.message.each do |text| obj_copy.gsub!(text, @config.filters.mask) end end end
Logs streaming output.
@example
logger << "Example output"
@api public
# File lib/tty/logger.rb, line 233 def write(*msg) event = Event.new(filter(*msg)) @ready_handlers.each do |handler| handler.(event) end self end