Log4Net propertyfilter总是匹配

时间:2014-12-03 22:24:32

标签: logging filter log4net

我想根据我调用的方法记录两个不同的级别。我正在使用拦截,所以我试图用propery过滤器达到目标。这是我的配置:

<log4net>
 <appender name="DoWorkFileAppender" type="log4net.Appender.RollingFileAppender">
   <datePattern value="yyyyMMdd'_dowork.log'" />
    ...
   <filter type="log4net.Filter.PropertyFilter">
      <key value="realMethod" />
      <stringToMatch value="DoWorkTest" />
      <acceptOnMatch value="true" />
   </filter>
 </appender>

 <appender name="WebsiteFileAppender" type="log4net.Appender.RollingFileAppender">
   <datePattern value="yyyyMMdd'_website.log'" />
    ...
    <filter type="log4net.Filter.PropertyFilter">
       <key value="realMethod" />
       <stringToMatch value="DoWorkTest" />
       <acceptOnMatch value="false" />
    </filter>
  </appender>

  <root>
     <appender-ref ref="WebsiteFileAppender">
       <threshold value="ERROR" />
     </appender-ref>
     <appender-ref ref="DoWorkFileAppender">
       <threshold value="INFO" />
       </appender-ref>
   </root>
</log4net>

现在,如果我调用metod DoWorkTest,一切正常并且消息只写在*_dowork.log文件中。但是,如果我调用另一个与方法anotherMethod不匹配的方法,则会在两个文件中写入消息。

我尝试用以下代码替换节点root

<root>
  <level value="ALL" />
</root>
<logger name="WebSiteLogger">
  <level value="ERROR" />
  <appender-ref ref="WebsiteFileAppender" />
</logger>
<logger name="PaymentsLogger">
  <level value="INFO" />
  <appender-ref ref="DoWorkFileAppender" />
</logger> 

但是使用此代码没有过滤器匹配。 我有什么要纠正的?谢谢。

1 个答案:

答案 0 :(得分:3)

好的,你的问题让我很感兴趣,所以我花了一些时间尝试。据我了解,您需要能够根据方法名称进行过滤。问题是可以基于命名空间和类创建日志,但不能创建方法名称,除非您对其进行硬编码。

在这种情况下,你最终会得到类似的东西:

    private void MyMethod()
    {
        log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString() 
                                        + "." + System.Reflection.MethodBase.GetCurrentMethod().Name);
        log.Error("Logging an error from MyMethod");
    }

这将允许您根据方法名称进行过滤:

这是appender的过滤器,只记录来自MyMethod的调用:

        <filter type="log4net.Filter.LoggerMatchFilter">
            <!-- ...accept only logs from MyMethod -->
            <loggerToMatch value="Log4netTest.Form1.MyMethod" />
            <acceptOnMatch value="true" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />

这是另一个过滤器,它不记录MyMethod日志:

        <filter type="log4net.Filter.LoggerMatchFilter">
            <!-- ...don't accept logs from MyMethod -->
            <loggerToMatch value="Log4netTest.Form1.MyMethod" />
            <acceptOnMatch value="false" />
        </filter>

现在这可以完成工作,但是如果你想要一种更通用的方法来根据方法名称进行记录,请尝试这样的事情:

    private void LogErrorByMethod(string message)
    {
        StackTrace stackTrace = new StackTrace();
        StackFrame frame = stackTrace.GetFrame(1);
        string fmname = frame.GetMethod().Name;

        string dt = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + fmname;
        log4net.ILog log2 = log4net.LogManager.GetLogger(dt);

        log2.Error(message);
    }

然后您可以通过任何方法拨打电话,您的日志将按照方法排序:

    private void MyMethod()
    {
        LogErrorByMethod("Logging from MyMethod");
    }
    private void Method2()
    {
        LogErrorByMethod("Logging from Method2");
    }

您必须为不同级别使用不同的方法,或传入级别枚举并使用开关,但您可以使用堆栈跟踪找出调用的方法,并基于该方法创建记录器

使用LogByMethod还允许您在模式中使用%logger属性在日志消息中包含方法名称,但如果您想更加明确,可以添加自定义属性:

        string fmname = frame.GetMethod().Name;
        log4net.GlobalContext.Properties["methodname"] = fmname;

然后你的模式可以包括:

...如果您已经记录了%logger,那么这是多余的,但它允许您自动将方法名称分开,如下所示:

<parameter>
<parameterName value="@method" />
<dbType value="String" />
<size value="100" />
<layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%property{methodname}" />
</layout>
</parameter>

最后,仅仅因为我在滚动,我想到了一种能够按方法名称记录的另一种方法来进行过滤。试试这个,你根本不需要appender中的过滤器:

    <logger name="Log4netTest.Form1.Method1" additivity="False">
        <level value="INFO"/>
        <appender-ref ref="RollingFileAppenderMethod1"/>
    </logger>
    <root>
        <level value="INFO"/>
        <appender-ref ref="RollingFileAppenderAllOtherMethods"/>
    </root>