Skip to content
Snippets Groups Projects
Commit d0ede97d authored by Dominik Honnef's avatar Dominik Honnef
Browse files

Implement log filtering

Log filters take log messages as input and return modified messages.
Additionally, they can drop messages by returning nil.

This allows for filtering passwords or other information from log
messages.

Closes gh-194
parent 9de65b9c
No related branches found
No related tags found
No related merge requests found
......@@ -49,6 +49,41 @@ This will set all loggers to the `:debug` level (which actually is the
default already) and the first logger (which is the default STDOUT
logger) to `:info`.
# Log filtering
Sometimes it is undesirable to log a message unchanged. For example
when identifying to the network, passwords might be sent in plain
text. To prevent such information from appearing in logs, {Cinch::LogFilter log filters}
can be employed.
Log filters take a log message as input and return a new message. This
allows removing/masking out passwords or other undesired information.
Additionally, messages can be dropped entirely by returning nil.
It is possible to use more than one filter, in which case they will be
called in order, each acting on the previous filter's output.
Filters can be installed by adding them to {Cinch::LoggerList#filters}.
An example (and very simple) password filter might look like this:
class PasswordFilter
def initialize(bot)
@bot = bot
end
def filter(message, event)
message.gsub(@bot.config.password, "*" * @bot.config.password.size)
end
end
This filter will replace the password in all log messages (except for
exceptions). It could further discriminate by looking at `event` and
only modify outgoing IRC messages. It could also use the
{Cinch::Message} class to parse the message and only operate on the
actual message component, not channel names and similar. How fancy
your filtering needs to be depends on you.
# Writing your own logger
This section will follow soon. For now just look at the code of
......
module Cinch
# LogFilter describes an interface for filtering log messages before
# they're printed.
#
# @abstract
# @since 2.3.0
class LogFilter
# filter is called for each log message, except for exceptions. It
# returns a new string, which is the one that should be printed, or
# further filtered by other filters. Returning nil will drop the
# message.
#
# @param [String] message The message that is to be logged
# @param [:debug, :incoming, :outgoing, :info, :warn, :exception,
# :error, :fatal] event The kind of message
# @return [String, nil] The modified message, as it should be
# logged, or nil if the message shouldn't be logged at all
def filter(message, event)
end
end
end
......@@ -9,6 +9,17 @@ module Cinch
# @attr_writer level
# @since 2.0.0
class LoggerList < Array
# A list of log filters that will be applied before emitting a log
# message.
#
# @return [Array<LogFilter>]
# @since 2.3.0
attr_accessor :filters
def initialize(*args)
@filters = []
super
end
# (see Logger#level=)
def level=(level)
each {|l| l.level = level}
......@@ -16,47 +27,64 @@ module Cinch
# (see Logger#log)
def log(messages, event = :debug, level = event)
each {|l| l.log(messages, event, level)}
do_log(messages, event, level)
end
# (see Logger#debug)
def debug(message)
each {|l| l.debug(message)}
do_log(message, :debug)
end
# (see Logger#error)
def error(message)
each {|l| l.error(message)}
do_log(message, :error)
end
# (see Logger#error)
def fatal(message)
each {|l| l.fatal(message)}
do_log(message, :fatal)
end
# (see Logger#info)
def info(message)
each {|l| l.info(message)}
do_log(message, :info)
end
# (see Logger#warn)
def warn(message)
each {|l| l.warn(message)}
do_log(message, :warn)
end
# (see Logger#incoming)
def incoming(message)
each {|l| l.incoming(message)}
do_log(message, :incoming, :log)
end
# (see Logger#outgoing)
def outgoing(message)
each {|l| l.outgoing(message)}
do_log(message, :outgoing, :log)
end
# (see Logger#exception)
def exception(e)
each {|l| l.exception(e)}
do_log(e, :exception, :error)
end
private
def do_log(messages, event, level = event)
messages = Array(messages)
if event != :exception
messages.map! { |m|
@filters.each do |f|
m = f.filter(m, event)
if m.nil?
break
end
end
m
}.compact
end
each {|l| l.log(messages, event, level)}
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment