log4net multiple appenders, writing to event viewer - c#

I am using log4net for logging, I have two appenders one file and other eventlog appender. I have register application in registry editor, problem is now both logger are writing in event viewer. I need fileAppender to write in file and eventLogAppender to be shown in event viewer.
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<file value="file.log"/>
<appendToFile value="false"/>
<layout type="log4net.Layout.PatternLayout">
<header value="Logging Start
"/>
<footer value="Logging End
"/>
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline"/>
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<param name="ApplicationName" value="eventlog" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
<appender-ref ref="EventLogAppender" />
</root>
</log4net>
and then in code
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly ILog log = LogManager.GetLogger("LogFileAppender");
private static readonly ILog logEvents = LogManager.GetLogger("EventLogAppender");
I have tried different things but no one is working, any solution?
Thanks!

In order to use multiple ILog instances with log4net and to log different information to each, you must configure at least two Logger elements in the log4net section of your config file.
In your case, you have two targets that you want - file and event log. I'll call them FileLogger and EventLogger.
Here is an example of the additional configuration you need in the log4net section:
<logger name="FileLogger">
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
</logger>
<logger name="EventLogger">
<level value="ALL" />
<appender-ref ref="EventLogAppender" />
</logger>
Then, to use each one in code, instantiate them like so:
private static readonly ILog fileLogger = LogManager.GetLogger("FileLogger");
private static readonly ILog eventLogger = LogManager.GetLogger("EventLogger");
Note that the ref attribute of the appender elements matches the name attribute of the appenders you have already configured and that the name passed to GetLogger matches the name attribute of the logger elements.

Related

How to write text into log4net file

I have a C# application. I would like to integrate a log File. Then I try do this in App.config
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="logfile.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" />
</layout>
</appender>
<appender name="InfoFileAppender" type="log4net.Appender.FileAppender">
<file value="info_logfile.txt" />
<appendToFile value="true" />
</appender>
<appender name="ErrorFileAppender" type="log4net.Appender.FileAppender">
<file value="error_logfile.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
<level value="INFO" />
<appender-ref ref="InfoFileAppender" />
<level value="ERROR" />
<appender-ref ref="ErrorFileAppender" />
</root>
</log4net>
So I try to write in infoFile:
log.Info("chiamata json");
but I don't see any text in info_logfile.txt
Where is my error?
Can we help me?
Reguards
Do you instantiate your log file? Try the following to see that it works with a console appender. (this example is copied from David Saltner)
using log4net;
using log4net.Config;
public class LogTest
{
private static readonly ILog logger =
LogManager.GetLogger(typeof(LogTest));
static void Main(string[] args)
{
BasicConfigurator.Configure();
logger.Debug("Here is a debug log.");
logger.Info("... and an Info log.");
logger.Warn("... and a warning.");
logger.Error("... and an error.");
logger.Fatal("... and a fatal error.");
}
}
.
private static readonly ILog logger =
LogManager.GetLogger(typeof(LogTest));
This creates a logger for the class LogTest. You don't have to use a different logger for each class you have, you can use different loggers for different sections or packages within your code. The class of the logger is output to the log so you know where any logged information has come from.
BasicConfigurator.Configure();
This method initializes the log4net system to use a simple Console appender. Using this allows us to quickly see how log4net works without having to set up different appenders.
This should get you started. Check out this great article for a brief introduction on how to set up appenders and more.
If the configuration is in your app.config file you need to add the sections in the config file:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net, Version=1.2.10.0,
Culture=neutral, PublicKeyToken=1b44e1d426115821" />
</configSections>
It is better practice to configure your log4.net is a log4net.config file. Then you need to add the following line to your assembly which reads your configuration file:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

programatically altering the fileappender of log4net

I am trying to set up logging using log4net, with no prior experience of log4net, in a wpf application
taken from this SO answer, I have
public partial class App : Application
{
private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected override void OnStartup(StartupEventArgs e)
{
XmlConfigurator.Configure();
base.OnStartup(e);
//Set data directory
string baseDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + #"\BlowTrial";
if (!Directory.Exists(baseDir))
{
Directory.CreateDirectory(baseDir);
}
//Set logging
foreach (var appender in LogManager.GetRepository().GetAppenders())
{
var fileAppender = appender as FileAppender;
if (fileAppender != null)
{
fileAppender.File = fileAppender.File.Replace("|DataDirectory|", baseDir);
...
but there are no elements in LogManager.GetRepository().GetAppenders() despite the app.config having the following within the configuration node:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
<appender-ref ref="ColoredConsoleAppender"/>
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="|DataDirectory|\log.txt"/>
<param name="AppendToFile" value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="1MB"/>
<staticLogFileName value="false"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline"/>
</layout>
</appender>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline"/>
</layout>
</appender>
</log4net>
I was wondering why the appender "LogFileAppender" is not an element within the LogManager.GetRepository().GetAppenders() method, and how I might change the name of the file?
Thanks for your expertise
The RollingFileAppender does some stuff internally when it's initialized (using XmlConfigurator.Configure();), which results in the path of |DataDirectory|\log.txt throwing a System.ArgumentException when trying to retrieve the path. You can view how to debug log4net if you want more details here.
According to this answer, since you're using a special folder path anyways, you can specify this in the app.config, and not worry about setting the path from the code:
<param name="File" type="log4net.Util.PatternString" value="%envFolderPath{CommonApplicationData}\\BlowTrial\\log.txt"/>

Write a Server.MapPath in the web.config file?

Hi there i'm trying to write log for my live website and am having problems with my paths, I need to use the method Server.MapPath but i need it done in my web.config.
How would i go about this?
The file value holds the path, but i need to set a Server.MapPath on it.
<log4net>
<add key="LogFilePath1" value="../Logs/CurrentLog" id="FP1"/>
<add key="LogFilePath2" value="../Logs/CurrentLog.txt" id="FP2" />
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="../Logs/CurrentLog"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10000"/>
<staticLogFileName value="true"/>
<filter type="log4net.Filter.LevelRangeFilter">
<acceptOnMatch value="true"/>
<levelMin value="INFO"/>
<levelMax value="FATAL"/>
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%thread] %-22.22c{1} - %m%n"/>
</layout>
</appender>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<file value="../Logs/Log.txt"/>
<appendToFile value="true"/>
<layout type="log4net.Layout.PatternLayout">
<header value="**"/>
<footer value="**"/>
<conversionPattern value="%newline%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>
<logger name="ConsoleApp.LoggingExample">
<level value="ERROR"/>
<appender-ref ref="EventLogAppender"/>
</logger>
Logger code C#:
public class Logger
{
protected static readonly ILog logger = LogManager.GetLogger(typeof(Logger));
public void logError(string message, Exception ex)
{
HttpContext.Current.Server.MapPath(Convert.ToString(ConfigurationManager.AppSettings["LogFilePath1"]));
HttpContext.Current.Server.MapPath(Convert.ToString(ConfigurationManager.AppSettings["LogFilePath2"]));
log4net.Config.XmlConfigurator.Configure();
logger.Error(message + ex);
}
public void logInfo(string message)
{
HttpContext.Current.Server.MapPath(Convert.ToString(ConfigurationManager.AppSettings["LogFilePath1"]));
HttpContext.Current.Server.MapPath(Convert.ToString(ConfigurationManager.AppSettings["LogFilePath2"]));
log4net.Config.XmlConfigurator.Configure();
logger.Info(message);
}
}
I have added C# code to Server.MapPath the Keys, i'm just struggling calling the keys in thhe file value =
Store your path in the config as
<add key="LogFilePath1" value="~/Logs/CurrentLog" id="FP1"/>
From your code read the key
string path = GetPath("LogFilePath1");
string fullPath = System.Web.HttpContext.Server.MapPath(path);
Log4net does not use Server.Map path when reading the paths from your configuration files. It does not know it is running in a web context. I geuss you can implement your own version of the Rolling File Appender and override the function which gets the path from the config. However I would just use the full paths to the log locations. Normally you do want to log on an other disk your application is running to prevent running out of diskspace and killing your application.

With log4net, do you specify which appender to use?

When you have 2 appenders, say one for debug errors and one for product errors, in your code, do you explicitly create 2 log classes or is an appender basically going to write any log messages that meet a certain criteria?
So in your code, you use a single log method, and depending on how your appenders are setup, it will log the message if it e.g. is logged from a specific namespace, or is a certain log level.
So its possible a single log entry is written to 2 log files?
Yes, you can have single log statements post to multiple appenders. As long as it meets the criteria for each, it will use each appender.
For example, take this config section, it logs all messages to file, and also logs warnings and errors to event viewer.:
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="c:\logs\MySite"/>
<appendToFile value="true"/>
<datePattern value=".yyyy-MM-dd.\l\o\g"/>
<rollingStyle value="Date"/>
<MaxSizeRollBackups value="14"/>
<param name="StaticLogFileName" value="false"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%thread] %-5level %logger{1} - %m%n"/>
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<applicationName value="Trading.Web"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%thread] %-5level %logger{1} - %m%n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="WARN"/>
<param name="LevelMax" value="ERROR"/>
</filter>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="EventLogAppender" />
</root>
</log4net>
So this:
_log.Debug("This is a debug message");
Will only appear in the log file (because it doesn't meet the event log appender's filter criteria).
But this:
_log.Error("This is an error message.");
Will log to both the log file and the event viewer.
UPDATE: On your filtering question, if you had:
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFileAppender"/>
</root>
<!-- Print only messages of level WARN or above in the namespace Com.Foo -->
<logger name="Com.Foo">
<level value="WARN" />
</logger>
Then all things under Com.Foo will log if WARN or higher, but everything else would log at DEBUG or higher....

Is it possible to wildcard logger names in log4net configuration?

In my application, I use log4net, with all types creating their own logger based on their type - e.g. :
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
As I am developing, I leave the root logger on DEBUG so as to catch all log output from my code.
However, a third party component also uses this same approach, but is generating 100s of log messages a second, none of which I am interested in.
Is it possible to use some sort of wildcarding in the logger configuration, to force all their loggers to only log at WARN, e.g. :
<logger name="com.thirdparty.*">
<level value="WARN"/>
</logger>
[The exact example above, using a * doesn't work]
You can just specify part of a namespace so it will apply to all messages within that namespace (including nested).
Here is the example I often use:
<root>
<level value="FATAL" />
<appender-ref ref="RollingFile" />
</root>
<logger name="MyCompany.Web" >
<level value="WARN" />
<appender-ref ref="WebErrors" />
</logger>
<!-- Will log all FATALs from NHibernate, including NHibernate.SQL and all the nested -->
<logger name="NHibernate" >
<level value="FATAL" />
</logger>
Additionally I would recommend to read the manual. It provides a lot of explanation. For example you can read about Logger Hierarchy. Here is the quote from there:
A logger is said to be an ancestor of
another logger if its name followed by
a dot is a prefix of the descendant
logger name. A logger is said to be a
parent of a child logger if there are
no ancestors between itself and the
descendant logger. The hierarchy works
very much in the same way as the
namespace and class hierarchy in .NET.
and also:
Level Inheritance:
The inherited level for a given logger X, is equal to the first
non-null level in the logger
hierarchy, starting at X and
proceeding upwards in the hierarchy
towards the root logger.
Can't you do the opposite of what you're asking. What I mean is just set the default log level to warn and then set the specific loggers you have defined to DEBUG.
Also, you could set the threshold of your appender to DEBUG and have the other appender set the WARN.
For example:
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<applicationName value="Application" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
<threshold value="WARN" />
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender,log4net">
<to value="asdf#example.com" />
<from value="group#example.com" />
<subject value="Notification" />
<smtpHost value="server01" />
<bufferSize value="1" />
<lossy value="false" />
<layout type="log4net.Layout.PatternLayout,log4net">
<conversionPattern value="%property{log4net:HostName} :: %level :: %message %newlineLogger: %logger%newlineThread: %thread%newlineDate: %date%newlineNDC: %property{NDC}%newline%newline" />
</layout>
<threshold value="DEBUG" />
</appender>

Categories

Resources