I have 2 appender in my config file which is configured to insert to different tables, "Log" and "LogFirms", but somehow both of the loggers are inserting to both of the tables.
<log4net debug="true">
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception],[ClientIp],[Username],[Controller],[Action],[Parameters]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception, #clientip, #username, #controller, #action, #parameters)" />
...
</appender>
<appender name="AdoNetAppenderForFirms" type="log4net.Appender.AdoNetAppender" additivity="false">
<bufferSize value="1" />
<commandText value="INSERT INTO LogFirms ([Date],[Thread],[Level],[Logger],[Message],[Exception],[ClientIp],[Username],[Controller],[Action],[Parameters]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception, #clientip, #username, #controller, #action, #parameters)" />
...
</appender>
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="AdoNetAppenderForFirms" />
</root>
</log4net>
Here is the logger class;
public static class Logger
{
private static ILog log { get; set; }
private static ILog logFirms { get; set; }
static Logger()
{
log = LogManager.GetLogger("AdoNetAppender");
logFirms = LogManager.GetLogger("AdoNetAppenderForFirms");
}
public static void Error(string controller, string action, string parameters, object msg, Exception ex)
{
if (controller == "AccountController" && logFirms.IsErrorEnabled)
{
logFirms.Error(msg, ex);
}
else if (log.IsErrorEnabled)
{
log.Error(msg, ex);
}
}
There is no error seen in the controller, so the problem must be in the configuration... I searched and tried adding
additivity="false"
property to the "AdoNetAppenderForFirms" element but that changed nothing. So do you have any advice to fix this?
You can do this by adding loggers to your configuration, instead of appenders on root level:
<root>
<level value="ALL" />
</root>
<logger name="AdoNetAppender" additivity="false">
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
</logger>
<logger name="AdoNetAppenderForFirms" additivity="false">
<level value="ALL" />
<appender-ref ref="AdoNetAppenderForFirms" />
</logger>
Related
I have multiple loggers referencing the same (rolling file) appender.
Only the first logger's output is appearing in the file.
Is it possible to make the appender work with multiple loggers? (I suppose not, but have not found any info in the docs, so need to confirm).
(I know there's logger inheritance, but I'm asking about non-inherited "independent" loggers)
My logger configuration is as follows
<logger name="a.b.c.Class1">
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
<appender-ref ref="ErrorsAppender"/>
</logger>
<logger name="a.b.c.Class2">
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
<appender-ref ref="ErrorsAppender"/>
</logger>
<logger name="a.b.c.Class3">
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
<appender-ref ref="ErrorsAppender"/>
</logger>
<logger name="a.b.c.Class4">
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
<appender-ref ref="ErrorsAppender"/>
</logger>
<logger name="a.d.e.Class5">
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
<appender-ref ref="ErrorsAppender"/>
</logger>
My appender configuratoin is as follows
<appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:/Debug.log" />
<appendToFile value="true" />
<maximumFileSize value="256KB" />
<maxSizeRollBackups value="10" />
<param name="Threshold" value="DEBUG" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="Event: %d [%t] %-5p %c - %m%nProperties: %properties%n%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="FATAL" />
</filter>
</appender>
<appender name="ErrorsAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:/Errors.log" />
<appendToFile value="true" />
<maximumFileSize value="256KB" />
<maxSizeRollBackups value="10" />
<param name="Threshold" value="WARN" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="Event: %d [%t] %-5p %c %stacktrace - %m%nProperties: %properties%n%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="WARN" />
<levelMax value="FATAL" />
</filter>
</appender>
The Log4net configuration is loaded with the regular
log4net.Config.XmlConfigurator.Configure()
I use Castle.Windsor and Log4Net for initialize my Logger.
My log4net.config:
<?xml version="1.0"?>
<configuration>
<log4net>
<appender name="AllMessagesFile" type="log4net.Appender.RollingFileAppender,log4net">
<file value="Logs/Log.log" />
<level value="ALL" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maximumFileSize value="100000KB" />
<maxSizeRollBackups value="-1" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %identity [%t] %-5p %c{1}.%M %m%n" />
<IgnoresException value="False" />
</layout>
</appender>
<appender name="ErrorsOnlyFile" type="log4net.Appender.RollingFileAppender,log4net">
<file value="Logs/Error.log" />
<level value="ERROR" />
<encoding value="utf-8" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maximumFileSize value="100000KB" />
<maxSizeRollBackups value="-1" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %identity [%t] %-5p %c{1}.%M %m%n" />
</layout>
</appender>
<root>
<priority value="ALL" />
<appender-ref ref="AllMessagesFile" />
<appender-ref ref="ErrorsOnlyFile" />
</root>
</log4net>
</configuration>
My AssamblyInfo.cs have foolow row:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
In constructor of class I got object via Winsdor:
public class ACIStart
{
private ILogger Logger { get; set; }
public ACIStart(ILogger logger)
{
Logger = logger;
}
I don't have any exceptions, I just got a logger with all properties (IsDebbugEnabled, IsErrorEnabled ... ) as false.
My log no write anything to log file.
What could be the problem?
It could be that you need to add the loglevel in you root node:
<root>
<level value="DEBUG" />
...
I'm using NLog for logging exceptions in my EPiserver application. I used this blog as a reference and my application does not log anything.
I created a NLog bridge appender class and configured EPiServerLog.config and NLog.config:
NLogBridgeAppender class:
using System;
using System.Collections.Generic;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using NLog;
namespace Tietgen.Web.Business.Core
{
public class NLogBridgeAppender : AppenderSkeleton
{
Dictionary<string, Logger> _loggers = new Dictionary<string, Logger>();
readonly object _lockObject = new object();
public static void Initialize()
{
BasicConfigurator.Configure(new NLogBridgeAppender());
}
protected override void Append(LoggingEvent loggingEvent)
{
var nLogEvent = ToNLog(loggingEvent);
var nLogger = GetLogger(loggingEvent);
nLogger.Log(nLogEvent);
}
Logger GetLogger(LoggingEvent loggingEvent)
{
Logger nLogger;
if (_loggers.TryGetValue(loggingEvent.LoggerName, out nLogger))
{
return nLogger;
}
lock (_lockObject)
{
if (_loggers.TryGetValue(loggingEvent.LoggerName, out nLogger))
{
return nLogger;
}
nLogger = LogManager.GetLogger(loggingEvent.LoggerName);
_loggers = new Dictionary<string, Logger>(_loggers)
{
{ loggingEvent.LoggerName, nLogger }
};
}
return nLogger;
}
private static LogLevel ToNLogLevel(Level level)
{
LogLevel nLevel;
if (level == Level.Fatal) nLevel = LogLevel.Fatal;
else if (level == Level.Error) nLevel = LogLevel.Error;
else if (level == Level.Warn) nLevel = LogLevel.Warn;
else if (level == Level.Debug) nLevel = LogLevel.Debug;
else if (level == Level.Info) nLevel = LogLevel.Info;
else if (level == Level.Trace) nLevel = LogLevel.Trace;
else if (level == Level.Off) nLevel = LogLevel.Off;
else
{
var message = string.Format("Unsupported log level: {0}.", level);
throw new NotSupportedException(message);
}
return nLevel;
}
private static LogEventInfo ToNLog(LoggingEvent loggingEvent)
{
return new LogEventInfo
{
Exception = loggingEvent.ExceptionObject,
LoggerName = loggingEvent.LoggerName,
Message = Convert.ToString(loggingEvent.MessageObject),
Level = ToNLogLevel(loggingEvent.Level),
TimeStamp = loggingEvent.TimeStamp,
FormatProvider = null
};
}
}
}
NLog.config:
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<target xdt:Transform="Insert" xsi:type="File" name="AllFile" fileName="${basedir}/Logs/All.${shortdate}.log" layout="[${longdate}][${uppercase:${level}}][${logger}] ${message} ${exception:format=ToString,StackTrace}" />
<target xdt:Transform="Insert" xsi:type="File" name="TietgenFile" fileName="${basedir}/Logs/Tietgen.Web.${shortdate}.log" layout="[${longdate}][${uppercase:${level}}][${logger}] ${message} ${exception:format=ToString,StackTrace}" />
</targets>
<rules>
<logger xdt:Transform="Insert" name="*" minlevel="Warn" writeTo="AllFile" />
<logger xdt:Transform="Insert" name="Tietgen.Web" writeTo="TietgenFile" minlevel="Warn" />
</rules>
EPiServerLog.config:
<appender xdt:Transform="Remove"
xdt:Locator="Match(name)"
name="errorFileLogAppender" />
<appender xdt:Transform="Remove"
xdt:Locator="Match(name)"
name="outputDebugStringAppender" />
<appender xdt:Transform="Insert"
xdt:Locator="Match(name)"
name="NLogBridgeAppender"
type="Tietgen.Web.Business.Core.NLogBridgeAppender, Tietgen.Web.Business.Core">
<encoding value="utf-8" />
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="Tietgen.Web" />
<acceptOnMatch value="false" />
</filter>
</appender>
<logger xdt:Transform="Replace"
xdt:Locator="Match(name)"
name="EPiServer.Core.OptimisticCache"
additivity="false">
<level value="Error" />
<appender-ref ref="NLogBridgeAppender" />
</logger>
<logger xdt:Transform="Replace"
xdt:Locator="Match(name)"
name="EPiServer.Core.ContentProvider"
additivity="false">
<level value="Error" />
<appender-ref ref="NLogBridgeAppender" />
</logger>
<logger xdt:Transform="Replace"
xdt:Locator="Match(name)"
name="EPiServer.Data.Dynamic.Providers.DbDataStoreProvider"
additivity="false">
<level value="Error" />
<appender-ref ref="NLogBridgeAppender" />
</logger>
<logger xdt:Transform="Replace"
xdt:Locator="Match(name)"
name="EPiServer.Data.Providers.SqlDatabaseHandler"
additivity="false">
<level value="Error" />
<appender-ref ref="NLogBridgeAppender" />
</logger>
<logger xdt:Transform="Replace"
xdt:Locator="Match(name)"
name="EPiServer.Data.Providers.ConnectionContext"
additivity="false">
<level value="Error" />
<appender-ref ref="NLogBridgeAppender" />
</logger>
<root xdt:Transform="Replace">
<level value="Warn" />
<appender-ref ref="NLogBridgeAppender" />
</root>
Ok I ended up using log4net alone in our web application to get the job done.
I managed to get started with Log4net but all my classes are using the same appender.
I want some classes to use a special appender.
Following is my log file:
<appender name="InfoRollingLogFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
<param name="File" value="C:\Test.log"/>
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value="_yyyy-MM-dd.log"/>
<param name="StaticLogFileName" value="true"/>
<maximumFileSize value="100KB" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline ---------------START---------------------- %newline %date - %message %newline ----------------END--------------------- %newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="DEBUG" />
</filter>
<filter class="log4net.Filter.DenyAllFilter"/>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="InfoRollingLogFileAppender" />
</root>
Here is how I am using it in my code:
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
and then to log I use log.Debug("Goes in Log File").
My question is how can I have different appenders for specific classes?
You can define appenders per logger which in your case translates to "per class":
<root>
<level value="DEBUG" />
<appender-ref ref="InfoRollingLogFileAppender" />
</root>
<logger name="YourNameSpace.YourClass" additivity="false">
<level value="DEBUG" />
<appender-ref ref="YourOtherAppender" />
</logger>
Important is the additivity flag: Without it the appenders defined in the root (or parent) logger are inherited.
I obviously don't understand log4net. My root log level is configured as follows:
<root>
<level value="ERROR"/>
<appender-ref ref="FileAppender" />
</root>
My log initialization looks as follows:
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
And my actual logging call looks as follows:
LOG.Error("Error submitting Registration.", exc);
Here's the funny part. This log statement ONLY works if I set the root log level to INFO. Why does the log level ERROR not work (and I only want errors, not Info, Debug etc...)?
<root>
<level value="ALL" />
...
</root>
Someone of my log4net-Configfile:
<appender name="FileAppender_FullLog" type="log4net.Appender.FileAppender">
<file value="Log_Full.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] [%logger{2}] - %message%newline" />
</layout>
</appender>
<appender name="FileAppender_SmallLog" type="log4net.Appender.FileAppender">
<file value="Log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] [%logger{2}] - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
..
</appender>
<!--LogLevel: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
<root>
<level value="ALL" />
<appender-ref ref="FileAppender_FullLog" />
<appender-ref ref="FileAppender_SmallLog" />
<appender-ref ref="SmtpAppender" />
</root>
Edit:
<appender name="FileAppender_SmallLog" type="log4net.Appender.FileAppender">
<file value="Log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] [%logger{2}] - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
<levelMax value="FATAL" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
<!--LogLevel: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
<root>
<level value="ALL" />
<appender-ref ref="FileAppender_SmallLog" />
</root>
The better way ist to use "< filter type="log4net.Filter.LevelRangeFilter">..." because you can change this setting for every appender if you want this in feature.
With the help of our clever architect I figured this one out...
I used to have my log initialization in assemblyInfo.cs (but this was wrong).
I moved the log initialization to my global.asax in app_startup:
protected void Application_Start(Object sender, EventArgs e)
{
string configFilePath = Server.MapPath("~/Config/Log4Net.config");
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(configFilePath));
}
The server.MapPath bit is very important, otherwise log4net tries to read its configuration from the system32\inetsrv folder.
I think my previous logging worked from time to time due to the order in which the assemblies were loaded, or something like that. Either way, this solution works.