protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
string msg = loggingEvent.RenderedMessage;
// remove the password if there is any
writer.Write(msg);
}
using System.Reflection;
using log4net.Appender;
using log4net.Core;
class MessageModifyingForwardingAppender : ForwardingAppender
{
private static FieldInfo _loggingEventm_dataFieldInfo;
public MessageModifyingForwardingAppender()
{
_loggingEventm_dataFieldInfo = typeof(LoggingEvent).GetField("m_data", BindingFlags.Instance | BindingFlags.NonPublic);
}
protected override void Append(LoggingEvent loggingEvent)
{
var originalRenderedMessage = loggingEvent.RenderedMessage;
var newMessage = GetModifiedMessage(originalRenderedMessage);
if (originalRenderedMessage != newMessage)
SetMessageOnLoggingEvent(loggingEvent, newMessage);
base.Append(loggingEvent);
}
/// <summary>
/// I couldn't figure out how to 'naturally' change the log message, so use reflection to change the underlying storage of the message data
/// </summary>
private static void SetMessageOnLoggingEvent(LoggingEvent loggingEvent, string newMessage)
{
var loggingEventData = (LoggingEventData)_loggingEventm_dataFieldInfo.GetValue(loggingEvent);
loggingEventData.Message = newMessage;
_loggingEventm_dataFieldInfo.SetValue(loggingEvent, loggingEventData);
}
private static string GetModifiedMessage(string originalMessage)
{
// TODO modification implementation
return originalMessage;
}
}
public class InterceptLoggerFactory : ILoggerFactory
{
public static void Apply() => Apply((Hierarchy)LogManager.GetRepository());
public static void Apply(Hierarchy h) => h.LoggerFactory = new InterceptLoggerFactory();
public Logger CreateLogger(ILoggerRepository repository, string name)
{
if (name == null) return new InterceptRootLogger(repository.LevelMap.LookupWithDefault(Level.Debug));
return new InterceptLogger(name);
}
class InterceptLogger : Logger
{
public InterceptLogger(string name) : base(name)
{
}
protected override void CallAppenders(LoggingEvent loggingEvent)
{
// Implement interception of property on loggingEvent before any call to any appender (execution is sync).
/*
* var loggingEventData = loggingEvent.GetLoggingEventData();
* loggingEventData.Message = [EncryptMessage](loggingEventData.Message);
* var newLoggingEvent = new LoggingEvent(loggingEventData);
* base.CallAppenders(newLoggingEvent);
* */
base.CallAppenders(loggingEvent);
}
}
class InterceptRootLogger : RootLogger
{
public InterceptRootLogger(Level level) : base(level)
{
}
protected override void CallAppenders(LoggingEvent loggingEvent)
{
// Implement interception of property on loggingEvent before any call to any appender (execution is sync).
base.CallAppenders(loggingEvent);
}
}
}
6 回答
我可能会写一个模式转换器 . 你可以找到一个例子here . 您的实现可能是这样的:
我有一个类似的问题,我通过继承
ForwardingAppender
然后在传递之前修改LoggingEvent
(使用反射)来解决它 .它不是很漂亮,但它有效 .
然后你需要一个看起来像这样的log4net配置
以及适合您需求的
GetModifiedMessage()
实施,您就不在了!Chris Priest解决方案的一个小改进:继承你的appender不是来自ForwardingAppender,而是来自基类AppenderSkeleton . 它使配置更简单 - 您不需要从您的配置中引用其他appender并立即将其轻松应用于不同的 Logger
用法
您可以尝试使用Unity Application Block method interceptor拦截对log4net的调用 . 或者您可以编写自定义log4net appender .
另一种解决方案是在直接从Logger到达任何appender之前拦截LoggingEvent . 一个先决条件是能够在创建任何Logger之前修改根层次结构 .
在下面的示例中,我们只是重新创建一个新的LoggingEvent,但如果您关心密集的内存复制则没有必要,通过反射,您可以访问底层的LoggingEventData(是struct)并直接为字段设置新值 .
您只需要在任何LogManager.GetLogger()之前调用InterceptLoggerFactory.Apply() .
log4net是开源的,你可以修改它 .