I have a security tool that sends users their new password through email. The production email module (that I don’t own and don’t want to change) will log the entire html email message body using Log4Net when the threshold is VERBOSE. Since the email contains a domain user’s password in clear text, I would like to remove the password from the log messages before it reaches the appenders.
Is there a way for me to temporary insert an object into the Log4Net stack that would allow me to search the LoggingEvent message and alter it to mask out any passwords that I find? I’d like to insert the object, call the email module, and then remove the object.
You can try intercepting the calls to log4net using the Unity Application Block method interceptor. Or you could write a custom log4net appender.
log4net is open source, you can modify it.
Another kind of solution is to intercept the LoggingEvent before reaching any appender directly from the Logger. One prerequisite is to be able to modify the Root Hierarchy before creating any Logger.
In the sample below, we just recreate a new LoggingEvent, but it's not necessary if you care about intensive memory copy, with reflexion you can access the underlying LoggingEventData(is struct) and set new values to the fields directly.
You just need to call InterceptLoggerFactory.Apply() before any LogManager.GetLogger().
I would probably write a pattern converter. You can find an example here. Your implementation could be like this:
I had a similar problem, and I solved it by inheriting from
ForwardingAppender
and then modifying theLoggingEvent
(using reflection) before passing it on.It's not very pretty, but it works.
Then you need a log4net config that looks something like this
and an implementation of
GetModifiedMessage()
that suits your need, and you are away!This improves upon @jeremy-fizames's, where you don't need to worry about whether the
ILoggerFactory
is set before anyLogManager.GetLogger()
is called. You can use log4net's plugin framework to ensure thisInterceptLoggerFactory
is set before any root logger is assigned. The[assembly:]
attribute ensures that log4net finds and loads the plugin before it sets up any logging.This solution works without modifying how existing appenders are configured, and it works whether you're loading log4net config from XML and/or programmatically at runtime.