2010-10-05 17 views
2

我有一個安全工具,通過電子郵件向用戶發送新密碼。當閾值爲VERBOSE時,生產電子郵件模塊(我不擁有並且不想更改)將使用Log4Net記錄整個HTML電子郵件消息體。由於電子郵件以明文形式包含域用戶的密碼,因此我想在日誌消息到達appender之前從其中刪除密碼。在到達appenders之前編輯Log4Net消息

有沒有辦法讓我臨時插入一個對象到Log4Net堆棧中,這將允許我搜索LoggingEvent消息並修改它以屏蔽掉我找到的任何密碼?我想插入該對象,調用電子郵件模塊,然後刪除該對象。

回答

2

我可能會寫一個模式轉換器。你可以找到一個例子here。您的實現可能是這樣的:

protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) 
{ 
    string msg = loggingEvent.RenderedMessage; 
    // remove the password if there is any 
    writer.Write(msg); 
} 
-3

log4net是開源的,你可以修改它。

3

我也有類似的問題,我從ForwardingAppender繼承,然後將它傳遞出去之前修改LoggingEvent(使用反射)解決了這個問題。

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; 
    } 
} 

這不是很漂亮,但它的工作原理。

然後,你需要一個log4net的配置看起來像這樣

<log4net> 
    <appender name="ModifyingAppender" type="Your.Lib.Log4Net.MessageModifyingForwardingAppender,Your.Lib"> 
     <appender-ref ref="ConsoleAppender" /> 
    </appender> 
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> 
     <layout type="log4net.Layout.PatternLayout"> 
      <conversionPattern value="%date %-5level [%thread] %logger: %message%newline"/> 
     </layout> 
    </appender> 
    <root> 
     <level value="INFO"/> 
     <appender-ref ref="ModifyingAppender"/> 
    </root> 
</log4net> 

和適合您需要的GetModifiedMessage()的實現,你不在!

2

克里斯牧師的解決方案的一個小改進:繼承你的appender不是從ForwardingAppender,而是從基類AppenderSkeleton。這使得配置簡單一點 - 你不需要從你的一個引用其他追加程序,現在很容易將其應用到不同的伐木工人

public class PasswordObfuscationAppender : AppenderSkeleton 
{ 
    private static readonly FieldInfo LoggingEventmDataFieldInfo = 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); 
    } 

    /// <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)LoggingEventmDataFieldInfo.GetValue(loggingEvent); 
     loggingEventData.Message = newMessage; 
     LoggingEventmDataFieldInfo.SetValue(loggingEvent, loggingEventData); 
    } 

    private static string GetModifiedMessage(string originalMessage) 
    { 
     // TODO modification implementation 
     return originalMessage; 
    } 
} 

使用

<appender name="PasswordObfuscationAppender" type="Foundation.PasswordObfuscationAppender,Foundation" /> 

<appender name="MainAppender" type="log4net.Appender.RollingFileAppender"> 
    <file value="..\Logs\File.log" /> 
</appender> 

<root> 
    <level value="DEBUG" /> 
    <appender-ref ref="PasswordObfuscationAppender" /> 
    <appender-ref ref="MainAppender" /> 
</root> 
+0

你能提供一個web.config部分的例子,看起來像AppenderSkeleton vs ForwardingAppender? – 2017-07-10 18:32:09

+0

@ChrisBohatka改進的答案與配置示例 – mikka 2017-07-11 17:41:50

+0

優秀!謝謝! – 2017-07-13 13:15:16

0

另一種解決方案是攔截LoggerEvent在直接從記錄器到達任何appender之前。一個先決條件是能夠在創建任何記錄器之前修改根層次結構。

在下面的示例中,我們只是重新創建了一個新的LoggingEvent,但如果您關心密集型內存副本,並且沒有必要使用反射,則可以訪問基礎LoggingEventData(is struct)並將新值直接設置到字段中。

您只需在任何LogManager.GetLogger()之前調用InterceptLoggerFactory.Apply()。

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); 
     } 
    } 
} 
相關問題