43

I want to send Info Level & above to the XML appender and Error/Fatal Level to the EventLog appender.

I gather that I need to modify the root element of the config but I'm struggling with the syntax. What is the configuration syntax to direct logs to the correct appender for a given level or range of levels?

This is the configuration so far:

<log4net>
  <appender name="SomeXmlAppender" type="log4net.Appender.RollingFileAppender">
    ...
  </appender>
  <appender name="SomeEventLogAppender" type="log4net.Appender.EventLogAppender">
    ...
  </appender>
  <root>
    <level value="DEBUG" />
    <appender-ref ref="SomeXmlAppender" />
    <appender-ref ref="SomeEventLogAppender" />
  </root>
</log4net>

Edit: Thanks @agileguy. That post did indeed contain the syntaxt I needed. The working solution now looks like this:

<log4net>
  <appender name="SomeXmlAppender" type="log4net.Appender.RollingFileAppender">
    ...
    <evaluator type="log4net.Core.LevelEvaluator">
      <threshold value="INFO"/>
    </evaluator>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="INFO" />
      <acceptOnMatch value="true" />
    </filter>
    <filter type="log4net.Filter.DenyAllFilter" />
  </appender>
  <appender name="SomeEventLogAppender" type="log4net.Appender.EventLogAppender">
    ...
    <evaluator type="log4net.Core.LevelEvaluator">
      <threshold value="ERROR"/>
    </evaluator>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR" />
      <acceptOnMatch value="true" />
    </filter>
    <filter type="log4net.Filter.DenyAllFilter" />
  </appender>
  <root>
    <level value="DEBUG" />
    <appender-ref ref="SomeXmlAppender" />
    <appender-ref ref="SomeEventLogAppender" />
  </root>
</log4net>
Philipp M
  • 1,877
  • 7
  • 27
  • 38
grenade
  • 31,451
  • 23
  • 97
  • 126
  • 5
    Note that an evaluator is only used by appenders that support buffering. If you want to specify a specific level per appender you only need to use the element by itself - it doesn't need to be wrapped in an evaluator. – Brian Jan 24 '11 at 20:23
  • element should only be used for appenders implementing BufferingAppenderSkeleton (i.e. not RollingFileAppender). – dave Jul 27 '14 at 19:41
  • I think Mr Graham's article [here](http://weblogs.asp.net/tgraham/archive/2007/03/15/a-realistic-log4net-config.aspx) will get you going. – Daniel Elliott Sep 07 '09 at 10:20

3 Answers3

15

This can be done using the threshold or filter elements within the appender.

Note that the threshold can be directly under the appender, where it acts as an inclusive filter, or under a evaluator e.g.

<evaluator type="log4net.Core.LevelEvaluator">
  <threshold value="ERROR"/>
</evaluator>

where it acts as an inclusive filter for skipping buffering (immediate output), where applicable.



Full explanation (source):

<threshold value="ERROR" />

The Threshold is implemented in the AppenderSkeleton and therefore supported by almost all appenders. It is just a simple test that is used to ignore logging events that have a level below the threshold. The threshold is checked early and as a simple test is very performant.

There is another way to specify the same behaviour as the threshold using filters. Filters are very much more flexible and as they are pluggable you can also develop your own custom logic and insert it into the filter chain.

<filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="ERROR" />
    <levelMax value="OFF" />
</filter>

Like the Threshold check Filters are implemented in the AppenderSkelton base class and are supported by almost all appenders. The above filter has the same effect as <threshold value="ERROR" />. It is a LevelRangeFilter that will allow through any events with a level in the range ERROR to OFF (inclusive). Note that OFF is the name of the highest level, conversely ALL is the name of the lowest level.

Filters have a great deal of flexibility because multiple filters can be chained together to provide fine grained control over the events that are output. Because of this they also have a higher cost in terms of performance, each filter in the chain is an object and is asked to decide on the correct course of action. In the simple case of the threshold filtering the Threshold property should be used in preference to a filter.

The Evaluator is implemented by the BufferingAppenderSkeleton and is therefore only supported by appenders that extend this base class and provide support for buffering. The SmtpAppender is one such appender.

The Evaluator is a pluggable object that is used by the BufferingAppenderSkeleton to determine if a logging event should not be buffered, but instead written/sent immediately. If the Evaluator decides that the event is important then the whole contents of the current buffer will be sent along with the event. The evaluator does not function like the threshold or a filter in that it does not discard events.

Danny Varod
  • 17,324
  • 5
  • 69
  • 111
6

You can a set a different threshold property for each appender. All log events with lower level than the threshold level are ignored by the appender. I'm pasting below two appenders, one for files and another one for database (you should set your connection string). The database appender has a threshold property indicating that only errors are going to be saved in the database.

<configuration>
  <log4net>
    <!--Database appender-->
    <appender name="DbAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="0" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <connectionString value="Data Source=AEG-PC\SQLEXPRESS;Initial Catalog=JCZ6;Uid=sa;Pwd=qwerty;" />
      <commandText value="INSERT INTO Log4Net ([date],[thread],[level],[logger],[message],[exception]) VALUES 
         (@log_date, @thread, @log_level, @logger, @message, @exception)" />
      <parameter>
        <parameterName value="@log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@thread" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%t" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@log_level" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%p" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%c" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%m" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
      <threshold value="Error" /> <!--THIS IS THE IMPORTANT LINE-->
    </appender>
    <!--File appender-->
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="log-file.txt" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <root>
      <level value="INFO" />
      <appender-ref ref="FileAppender" />
      <appender-ref ref="DbAppender" />
    </root>
  </log4net>
</configuration>
Wouter Simons
  • 2,856
  • 1
  • 19
  • 15
Francisco Goldenstein
  • 13,299
  • 7
  • 58
  • 74
2

I had the same question. It appears, assuming I'm understanding the original question, that thresholds won't work as it will send certain output to one appender and that plus the rest to the other appender. I was able to get it working using the LevelRangeFilter as suggested above. I wanted ERROR, INFO and WARN to go to one appender and all others to go to another appender, but not ERROR, INFO and WARN.

Here's the config which worked for me:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    <log4net>
        <appender name="LoggingAppender" type="log4net.Appender.FileAppender" >
            <file value="logs.txt" />
            <filter type="log4net.Filter.LevelRangeFilter">
                <levelMin value="INFO"/>
                <levelMax value="OFF"/>
            </filter>
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
            </layout>
        </appender>
        <appender name="TracingAppender" type="log4net.Appender.FileAppender" >
            <file value="traces.txt" />
            <filter type="log4net.Filter.LevelRangeFilter">
                <levelMin value="ALL"/>
                <levelMax value="DEBUG"/>
            </filter>
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
            </layout>
        </appender>
        <root>
            <appender-ref ref="LoggingAppender"/>
            <appender-ref ref="TracingAppender"/>
        </root>
    </log4net>
</configuration>

Thanks, Nick