log4net different messages for different appenders, creating duplicate log entries in file

1.7k Views Asked by At

I have implemented a custom appender for log4net in which i am doing logging to a file and sending out mail. I want to log different message strings for each case. Below code creates two log entries in the file, one with appended string & one without appended string. It also sends out the email without the appended string.

public static void Log(this ILog log, Level level, string message)
{
    var token = string.Format("{0},{1},{2}", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, level, message);
    int count = _tokenTimeThrottler.CheckAllow(token);
    if (count >= 0)
    {
        //only to file logger, with an appended string
        log = LogManager.GetLogger("LogFileAppender");
        log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, level, count <= 1 ? message : count + " counts of: " + message, null);
    }

    //only to mail
    log = LogManager.GetLogger("MyMailAppender");
    log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, level, message, null);
    }

But I want to don't want to log to file when I am doing.

//only to mail
log = LogManager.GetLogger("MyMailAppender");
log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, level, message, null);

My Config file, one appender is added using config file, the other appender is a dll so its added at runtime.

1st appender:

<log4net>
    <root>
      <level value="INFO" />
      <appender-ref ref="LogFileAppender" />
    </root>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="C:\git\logs\log.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p  %m%n" />
      </layout>
    </appender>
</log4net>

2nd appender (Added at runtime):

Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
      PatternLayout patternLayout = new PatternLayout { ConversionPattern = "%d [%t] %-5p %m%n" };

      MyMailAppender myAppender = new MyMailAppender 
      {
        Name = "MyMailAppender",
        Layout = patternLayout,
        Access = "ghjkgj",
        Threshold = Level.Info,
      };

      myAppender .ActivateOptions();
      hierarchy.Root.AddAppender(myAppender );

      hierarchy.Root.Level = Level.All;
      hierarchy.Configured = true;
3

There are 3 best solutions below

0
On BEST ANSWER

The solution was to use two logger elements instead of root, as root applies to all appenders. So anything appended added to root will be written creating duplicate entries.

    <log4net>
         <logger name="MyMailAppender">
          <level value="INFO" />
        </logger>
        <logger name="LogFileAppender">
          <level value="INFO" />
          <appender-ref ref="LogFileAppender" />
        </logger>
</log4net>

Then at runtime i create the appender from dll and add it to MyMailAppender logger.

0
On

I would recommend using two BufferingFowardAppender with filters based on the logger name (log4net.Filter.LoggerMatchFilter):

  • one forwarding appender would filter messages for the mailing logger based on the logger name: root at INFO level -> fowarding appender with filter for MyMailAppender logger name -> mail appender
  • one forwarding appender would filter messages for the standard logger: root at INFO level -> fowarding appender with filter NOT letting MyMailAppender logger name pass -> other appender

You don't need to use in code configuration, this is entirely doable through configuration only

0
On

It;s not completely clear to me what you're doing, as your examples aren't actually calling your extension method, but I think the simplest solution is to add another parameter to the extension method which specifies if you want to send the log entry by email:

public static void Log(this ILog log, Level level,
                       string message, bool sendEmail = true)
{ …

 if (sendEmail)
  { 
      //only to mail
      log = LogManager.GetLogger("MyMailAppender");
      log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, level, message, null);
  }
}

Then you just specify when you don't want it to be sent:

log = LogManager.GetLogger("MyMailAppender");

// Call extension method, specifying no email should be sent
log.Log(level, message, false);

Because sendEmail has a default value of true, if you do want send email then you don't need to pass the parameter at all, which means there is no impact on existing code.