I am new to logging in .Net and was trying to learn log4net as a logging tool. I am running into a problem which is
I have created a log4net config file and trying to add values of logs into SSMS but values are not populating as expected. Here is my log4net config file
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %5level %logger.%method [%line] - %message%newline" />
</layout>
</appender>
<appender name="DatabaseAppender" type="ToolsCommon.logging.AdoNetAppender">
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="Startup" />
<acceptOnMatch value="false" />
</filter>
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />0
<connectionString value="dynamicly created" />
<commandText value="INSERT INTO Log ([EntryID],[Message],[TimeStamp],[SeverityId]) VALUES (#entryid, #message, #log_date, #severityId)" />
<parameter>
<parameterName value="#entryid" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%entryid" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#severityId" />
<dbType value="Int64" />
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="severityId" />
<type value="ToolsCommon.logging.QCSeverityConverter" />
</converter>
<conversionPattern value="%severityId" />
</layout>
</parameter>
</appender>
<appender name="FileAppender" type="ToolsCommon.logging.CustomFileAppender">
<file value="%property{logFilePath}/ToolLog.log" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %5level %logger.%method [%line] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="DatabaseAppender" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
Issue with above code is EntryID is not getting populated as expected rather it gets populated with some other value which I have no idea where that value is coming from.
Is there any way I can debug this and find out how EntryID value is populated?
I tried debugging it but since this is a config file I cannot debug it using Visual Studios debugger. I think this is getting invoked as and when logger is called but I am not sure where EntryId value is coming from? I am expecting any clue so I can figure out how EntryId is getting populated.
You can turn on internal debugging with:
<configuration>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
</configuration>
see here for more info.
Please edit your configuration file according to this format:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,
log4net-net-1.0" />
</configSections>
<log4net>
..
</log4net>
</configuration>
Related
I'm trying to implement logging with log4net in an asp.net core console app. I have a business library written in .net 4.7.1 with a logging wrapper that I'm using to do logging in all of my apps. I have a file appender, a console appender, an smtp appender, and an ado.net appender. All of these work on my asp.net core web app and they also work in my non-core console apps.
Only the console and file appenders work in .net core console. The ado.net and email appenders do not seem to work. I don't get emails and nothing is inserted into the DB.
This is my Main method:
static void Main(string[] args)
{
// Set up DI
var serviceProvider = new ServiceCollection()
.AddSingleton<IRepository, Repository>()
.AddSingleton<ITdnLogger, TdnLogger>()
.BuildServiceProvider();
var logger = serviceProvider.GetService<ITdnLogger>();
logger.Log(LoggingLevel.Info, "This is a test log error!");
var logga = new TdnLogger();
logga.Log(LoggingLevel.Error, "Error but not an error");
Console.ReadLine();
}
I first attempt to get the logger to log using dependency injection and then I instantiate a new one and try again. I get the same results both times. Console and File appenders work, email and ado do not. So I'm thinking it has nothing to do with DI, but is probably more of a set up issue. I don't understand where the setup could be wrong, because it works for everything else, but...
In my business library's AssemblyInfo.cs I have the log4net config set up like this:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")]
This is what the config looks like:
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="SmtpAppender" />
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file value="ApplicationLog.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
</appender>
<appender name="SmtpAppender" type="Business.Logging.SimpleSmtpAppender">
<subject>**** Application Error Notification ****</subject>
<smtpHost value="{server}" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR"/>
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%date [%thread] %level %logger - %message%newline%newline%exception" />
</layout>
</appender>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<threshold value="INFO" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="{valid con string}" />
<commandText value="INSERT INTO Log ([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="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
Any ideas of why the ado and email appenders might not work in a core console app?
EDIT #1:
I got the email appender to work, I had the email address setup incorrectly.
The ado appender is throwing this error:
System.TypeLoadException: Could not load type
System.Runtime.Remoting.Messaging.CallContext from assembly 'mscorlib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
at log4net.Util.LogicalThreadContextProperties.GetLogicalProperties()
at log4net.Util.LogicalThreadContextProperties.GetProperties(Boolean
create) at log4net.Core.LoggingEvent.CreateCompositeProperties()
at log4net.Core.LoggingEvent.CacheProperties() at
log4net.Core.LoggingEvent.FixVolatileData(FixFlags flags) at
log4net.Appender.BufferingAppenderSkeleton.Append(LoggingEvent
loggingEvent) at
log4net.Appender.AppenderSkeleton.DoAppend(LoggingEvent loggingEvent)
Try using https://github.com/microknights/Log4NetAdoNetAppender, instead of the standard log4net.Appender.AdoNetAppender. You will need to change the appender type definition in your config file to:
MicroKnights.Logging.AdoNetAppender, MicroKnights.Log4NetAdoNetAppender
as per the documentation on their project page.
We have a Windows Service that kicks off another process called ClusterProcess.
I want to get logs from the Windows Service and from the ClusterProcess, and I want those logs to go to the database and to files. For instance, if the database is not accessible, I want to be able to see the logs in the files.
I have an external config file for the Log4Net settings. There are two RollingFileAppenders and two AdoNetAppenders.
There is the default root logger and an additional logger called, ClusterProcessLogger.
The idea is that the Windows Service uses the root logger and logs to one of the AdoNetAppenders and one of the RollingFileAppenders, and that the ClusterProcess uses the ClusterProcessLogger and logs to the other AdoNetAppender and the other RollingFileAppender.
The AdoNetAppenders for both cases work fine. The RollingFileAppenders do not.
So here is the external config file for the log4net configuration:
<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="true">
<appender name="RollingFileAppender"
type="log4net.Appender.RollingFileAppender">
<file value="C:\Program Files\Sym\Logging\CalcEngineLog.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger %location -
%message%newline%exception"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG"/>
<levelMax value="FATAL"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
<appender name="SpecialRollingFileAppender"
type="log4net.Appender.RollingFileAppender">
<file value="C:\Program Files\Sym\Logging\SpecialCalcEngineLog.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger %location -
%message%newline%exception"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG"/>
<levelMax value="FATAL"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<!--<threshold value="Error" />-->
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data,
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="" />
<commandText value="INSERT INTO [Calculation Engine Log] ([Date],[Thread],
[Level],[Logger],[Location],[Message],[Exception]) VALUES (#log_date,
#thread, #log_level, #logger, #location, #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="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#location" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%location" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<appender name="ClusterProcessAdoNetAppender"
type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data,
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="" />
<commandText value="INSERT INTO [ClusterProcess Calculation Engine Log]
([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="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<logger name="ClusterProcessLogger" additivity="false">
<level value="Debug" />
<appender-ref ref="ClusterProcessAdoNetAppender" />
<appender-ref ref="SpecialRollingFileAppender" />
</logger>
<root>
<level value="Debug"/>
<appender-ref ref="AdoNetAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>
</log4net>
Here is the Main method of the Windows Service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;
using System.Globalization;
using Sym.Core.Culture;
using System.Threading;
namespace Sym.WindowsService
{
static class Program
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
static void Main()
{
if (!log4net.LogManager.GetRepository().Configured)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Sym\\bin\\Log4NetSettingsGlobal.xml"));
}
log.Debug("Culture info before change: " + Thread.CurrentThread.CurrentCulture.Name);
...
}
}
}
Here is the App.config of the Windows Service:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="ConfigPath" value="C:\Program Files\Sym\Configs\Example.config"/>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\Program Files\Sym\Logging\Log4Net_Trace_WindowsServer.txt" />
</listeners>
</trace>
</system.diagnostics>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
For the ClusterProcess project, here is the Main method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sym.Core.Config;
using Sym.Clustering.Framework;
using System.Diagnostics;
using Sym.Core.Services;
using System.Reflection;
using System.IO;
using log4net.Repository.Hierarchy;
using log4net;
using log4net.Appender;
using System.Configuration;
using System.Collections.Specialized;
using Sym.Core.Log4Net;
using log4net.Config;
namespace Sym.Clustering.ClusterProcess
{
class Program
{
private static ClusterProcessor _ClusterProcessor ;
private static SelectedConfiguration _Config;
private static readonly log4net.ILog log = log4net.LogManager.GetLogger("ClusterProcessLogger");
static void Main(string[] args)
{
try
{
...
try
{
log4net.Config.XmlConfigurator.Configure();
if (!log4net.LogManager.GetRepository().Configured)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Sym\\bin\\Log4NetSettingsGlobal.xml"));
}
Log4NetConfiguration.ConfigureLog4Net(_Config); // Load connection strings
}
catch (Exception e)
{
Console.WriteLine(e);
}
log.Debug("ClusterProcess using DatabaseName: " + config.Database.DatabaseName);
...
}
catch(Exception exp)
{
log.Error(exp.Message, exp);
}
}
}
}
Here is the App.config of the ClusterProcess project:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\Program Files\Sym\Logging\Log4Net_Trace_ClusterProcess.txt" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
In the log4net trace of the ClusterProcess, these errors are given:
log4net:ERROR Failed to find configuration section 'log4net' in the application's .config file. Check your .config file for the <log4net> and <configSections> elements. The configuration section should look like:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
log4net:ERROR [RollingFileAppender] ErrorCode: GenericFailure. Unable to acquire lock on file C:\Program Files\Sym\Logging\SpecialCalcEngineLog.txt. The process cannot access the file 'C:\Program Files\Sym\Logging\SpecialCalcEngineLog.txt' because it is being used by another process.
log4net:ERROR [RollingFileAppender] ErrorCode: GenericFailure. Unable to acquire lock on file C:\Program Files\Sym\Logging\CalcEngineLog.txt. The process cannot access the file 'C:\Program Files\Sym\Logging\CalcEngineLog.txt' because it is being used by another process.
I don't know what to do about the first error.
The second and third error shouldn't be there. The ClusterProcess should be able to access the SpecialCalcEngineLog.txt, and it shouldn't be bothered with the CalcEngineLog.txt, as that is the RollingFileAppender that the Windows Service is using.
How do I solve these errors? What am I overlooking?
First error can be mitigated by adding
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
somewhere.
Multiple RollingFileAppenders cannot write to the same file. However, you can distinguish by, for example, adding process id to the file name (and then collect logs from all processes):
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\log\logfile_[%processid].log" />
...
</appender>
I have found other posts with similar problems, but thus far I haven't been able to solve my particular case.
If I put the log4net configuration in the app.config then all works fine, but I want it in a separate file.
I have looked at the following links, and have tried to implement some of the proposed solutions (but perhaps I didn't understand it correctly):
Similar SO question, but with web scenario
Apache documentation, 'Reading Files Directly' section
Tim Corey's log4net tutorial
So here is my Log4NetSettings.config file's content (wrapped in a configuration element):
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="" />
<commandText value="INSERT INTO [Calculation Engine Log] ([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="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="AdoNetAppender"/>
</root>
</log4net>
I change the connectionstring value during runtime.
Here is what I have in the app.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<appSettings>
<add key="log4net.Config" value="Log4NetSettings.config" />
</appSettings>
<log4net configSource="Log4NetSettings.config" />
In the executable class I have this:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4NetSettings.config", Watch = true)]
and then as soon as I can get hold of the connectionstring and configure it to the AdoNetAppender, I call:
log.Info("Testing");
I also have:
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
in the class with the assembly attribute and first logging call.
The Log4NetSettings.config file has its Build Action set to Content and its 'Copy to Output Directory' set to 'Copy Always'.
I have been pulling my hair out, and I don't know what I am doing wrong.
Should I have Log4NetSettings.config as just a normal xml file?
Should I put the assembly attribute in the AssemblyInfo.cs file?
Should I rather call:
XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(AppDomain.CurrentDomain.BaseDirectory + "Log4NetSettings.config"));
than have the assembly attribute?
It feels like I've tried so many different things, that perhaps I have mixed them up and gotten the wrong combination.
Adding debug = "true" to the <log4net> tag (i.e. <log4net debug="true"> ) gives a lot of helpful information which may help to resolve.
Yes, you should have the log4net config in an XML file. When you have log4net in a separate file, it's no longer related to the app.config so the configuration section is not required, and the config should not be wrapped in a configuration element. (It isn't necessary to have the assembly attribute in the AssemblyInfo.cs, and I note you have initialised the logging system in your startup code, which is required when using the assembly attribute technique)
Thus your log4net file will look like this:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!-- config .. -->
If you still have problems, log4net has diagnostic and debugging capability, see this question for how to enable it.
(Also, if you're using log4net 1.2.11 or later, you can set the connection string name in the log4net config, assuming it is in your app.config)
I have an appender that calls a stored procedure to to write a log record. It looks like this (trimmed for brevity):
<log4net>
<root>
<level value="WARN" />
<appender-ref ref="ElsAppender" />
</root>
<appender name="LogAppender" type="LoggerAssembly.Appender, LoggerAssembly">
<bufferSize value="1" />
<reconnectonerror value="True" />
<parameter>
<parameterName value="#EntryDate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="40000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
</log4net>
Note the size field of the message parameter is set to 40,000.
I have a logger however where I need the message length to be much longer. How do I change this setting for that specific logger. I tried cloning the LogAppender and changing the size value, like this:
<log4net>
<root>
<level value="WARN" />
<appender-ref ref="LogAppender" />
</root>
<logger name="SpecialLogger">
<level value="INFO" />
<appender-ref ref="SpecialLogAppender" />
</logger>
<appender name="LogAppender" type="LoggerAssembly.Appender, LoggerAssembly">
<bufferSize value="1" />
<reconnectonerror value="True" />
<parameter>
<parameterName value="#EntryDate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="40000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
<appender name="SpecialLogAppender" type="LoggerAssembly.Appender, LoggerAssembly">
<bufferSize value="1" />
<reconnectonerror value="True" />
<parameter>
<parameterName value="#EntryDate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="400000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
</appender>
</log4net>
but that results in the message from the SpecialLogger being logged twice, once by the LogAppender and once by the SpecialLogAppender. Any ideas?
You need to add additivity="false" to your special logger definition:
<logger name="SpecialLogger" additivity="false">
<level value="INFO" />
<appender-ref ref="SpecialLogAppender" />
</logger>
You need to add a suitable <filter> element to your log4net appender(s). See
http://logging.apache.org/log4net/release/manual/configuration.html#filters
http://logging.apache.org/log4net/release/sdk/log4net.Filter.html
http://logging.apache.org/log4net/release/sdk/index.html
Log4net appenders are checked in document order, so your special appender needs to precede the default appender. Then something like this ought to do yo:
<appender name="SpecialAppender" type="log4net.Appender.FileAppender">
<file value="log.txt" />
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="your-logger-name-here">
<acceptOnMatch="true"
</filter>
<layout type="log4net.Layout.SimpleLayout" />
</appender>
<appender name="DefaultAppender" type="log4net.Appender.FileAppender">
<file value="log.txt" />
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="your-logger-name-here">
<acceptOnMatch="false"
</filter>
<layout type="log4net.Layout.SimpleLayout" />
</appender>
I have Web API that needs to write log data, both to a file and to the database.
Is it possible to configure such a setup? I am trying to understand ILoggerRepository but I am confused.
Can someone give me the some tips on how to configure it and how to use it in application?
It sounds to me like you want to write to two different style appenders at the same time.
The good news is that this is built right into the log4Net library.
What you want to do so configure you configuration file to two different appenders. A file Appender and a Database appender.
Examples of the different appenders can be found here.
http://logging.apache.org/log4net/release/config-examples.html
Here is an example of an web.config that i whipped together. You are going to have to tweak it to get it to work for you, but it will get you on the right start.
One last point, your log4net configuration does not have to be in your web.config but IMHO it just makes things easier to get started. Worry about breaking it out once your web.config starts to get a little cluttered.
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<log4net>
<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>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="100" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=[database server];initial catalog=[database name];integrated security=false;persist security info=True;User ID=[user];Password=[password]" />
<commandText value="INSERT INTO Log ([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="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
</configuration>