logging in log4net to different appenders based on circumstances - c#

I am using log4net and in one class require logging to a RollingFile appender, but then in another class, I wish to log to the event log + rolling file + console appender.
What is the best practice? and could I see some sample code?
By the way to make things more difficult, I am using Castle Windsor Logging Facility with Log4net to resolve my Logger instance.
If it helps, I was thinking this below, but have no idea if this is best practice, or how to activate a particular logger based on 'name' still utilising my current logger instance from windsor:
log4net.config:
...
<logger name="EventLogOnly">
<level value="ALL" />
<appender-ref ref="EventLogAppender" />
</logger>
<logger name="ConsoleEventLog">
<level value="ALL" />
<appender-ref ref="ColoredConsoleAppender" />
<appender-ref ref="EventLogAppender" />
</logger>
...
castle windsor container builder class:
container.AddFacility("logging.facility",
new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
class in which to log:
private ILogger Logger;
public Test(ILogger logger) {
Logger.Info("Can I log under event log only?");
Logger.Info("Now can I log under both?");
}
Thanks guys.

You can do this by applying a filter to an appender. Only if the log event passes the filter does the event get logged by that appender.
This filter configuration will log only those events coming from the logger named "MyLogger":
<appender name="EventLogAppender" ...
<filter type="log4net.Filter.LoggerMatchFilter">
<loggerToMatch value="MyLogger" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
...and this one will match log messages with certain contained text:
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="database" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
There's a good bit of configuration possible with filters. See the log4net SDK, or the Filters section of the manual, for more details.

Related

log4net appenders to database with different bufferSize

I have two loggers for same database with different level. I would like to have different bufferSize for each logger.
One way is to have two appenders to same database with only difference in bufferSize element, but it's copy-paste.
Is it possible to extend already defined appender and change it's bufferSize property?
For example:
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="20" />
...other elements
</appender>
<appender name="AdoNetAppenderChild" extends="AdoNetAppender">
<bufferSize value="1" />
</appender>
<logger name="Fatal" additivity="false">
<level value="FATAL"/>
<appender-ref ref="AdoNetAppenderChild" />
</logger>
<logger name="Common" additivity="false">
<level value="INFO"/>
<appender-ref ref="AdoNetAppender" />
</logger>
What I want to avoid is having two appenders with same elements and properties and only different value is bufferSize
You can make one appender and use a evaluator to log when you have an error message:
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR"/>
</evaluator>
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. Typically an
SmtpAppender will be setup to buffer events before sending as the cost
of sending an email may be relatively high. If an important event
arrives, say an ERROR, we would like this to be delivered immediately
rather than waiting for the buffer to become full. This is where the
Evaluator comes in as it allows us to say: "when an important event
arrives don't worry about buffering, just send over everything you
have right now".

Log4Net - checking attached appenders in a unit test

I have an issue to diagnose, and to get an understanding of it, I wrote two unit tests - one that gets a Logger that exists in my config, and another that gets logger that doesn't exist.
The first surprise was that even if the logger name doesn't exist, I'm still getting back something (instead of NULL, as I was expecting). And it even has a ConsoleAppender attached to it.... okay.... but where does that come from?
Log4net config:
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\tmp\log" />
... (some other settings) ....
</appender>
<root>
<level value="FATAL"/>
<appender-ref ref="RollingFileAppender" />
</root>
<logger name="DefinedLogger" additivity="false">
<level value="DEBUG" />
<appender-ref ref="MyCustomAppender" />
</logger>
<appender name="MyCustomAppender" type="MyAssembly.CustomAppender, MyAssembly">
.....
</appender>
</log4net>
Next, I was trying to understand how I can check what appenders are configured in each logger. My first attempt using the .Repository kept giving back all three appenders that are configured in my config file - OK, makes sense, since it's all the appenders that are in the repository.... but how can I check for an individual entry what appenders are attached?
[Test]
public void TestGetLoggerWithValidNameGetsLogger() {
// Arrange
string loggerName = "DefinedLogger";
// Act
ILog myCustomLogger = LogManager.GetLogger(loggerName);
// this returns *ALL* appenders in the config - not those attached to this logger....
var appenders = myLogger.Logger.Repository.GetAppenders();
// Assert
Assert.IsNotNull(myCustomLogger, "MyCustomLogger is NULL");
}
Any ideas? How can I check to make sure the proper appender(s) have been attached to my logger here?

Setting up a default log when Logger not found in Log4Net

I am using Log4Net as the logging mechanism for an application of ours. Our configuration is contained in a config file and in our code we programatically invoke which of our several loggers (mostly using FileAppenders) we want to invoke. Recently I realized that one of our log files was not being populated, and I tracked it down to a string mismatch, between the name in our configuration file and the name we were programatically invoking in our code. Because the LogManager could not find the specified logger the root was returned, which for our config is not setup to meaningfully log anywhere.
My question is, is there a way to setup log4net to allow for using specific loggers, but that will fall back to a general logger if the specified logger is not found?
For example using a configuration file like this
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
</root>
<logger name="TestFileLogger">
<level value="ALL" />
<appender-ref ref="TestFileAppender" />
</logger>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p [%x] - %m%n" />
</layout>
</appender>
<appender name="TestFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="TestLog" />
<param name="DatePattern" value=".yyyyMMdd".log"" />
<param name="AppendToFile" value="true" />
</appender>
</log4net>
</configuration>
And invoking the loggers in C# like this
var fileLogger = LogManager.GetLogger("TestFileLogger");
fileLogger.Info("This logs appropriately.");
var bogusLogger = LogManager.GetLogger("Bogus");
bogusLogger.Info("This should go to a general log. Bogus is not a recognized appender");
Is there a good way to log the messages from bogusLogger to some kind of general log file? My initial thought was to create a general file appender that is part of the root node, but this is very noisy as ALL log messages will be routed to this file. Is there a way to ONLY route messages that are not captured in another log file?
You could use LogManager.Exists("Bogus") to determine if the bogus-logger or your default implementation should be used.
You could create an extensionmethod on LogManager that could handle it for you.

log multiple assemblies using log4net

After lots of issues, finally I managed to configure log4net for my window service.
I am pretty new to it and today I started configuring it. I have these below doubts.
1) I need to use that into multiple assemblies. Say I have an assembly 'A' which is added as reference in assembly 'B' which is mine main assembly where I have reference of log4net.I need to log both assembly 'A' and 'B'.
2) My application is multi-threaded and use lots of thread. So is log4net is thread safe?
3) I am using this below config in my app.config. I am not much aware what’s the use of it. But I don’t want to use unnecessary parameters.
<log4net>
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\logs\log.txt"/>
<param name="AppendToFile" value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="100KB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n"/>
</layout>
</appender>
</log4net>
Use <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> under appender section. I twill increase the logging performance.
log4net is threadsafe.
<maximumFileSize value="10MB" /> //For 100 Kb configuration there will be lot of files.
<datePattern value="_yyyyMMdd" /> //It will hint the logger to create a new file per date.
Create a static class for Logger and call the static function from every assembly where you want to use.
Sample Class for logging:
public static class Logger
{
static Logger()
{
XmlConfigurator.Configure();
}
public static void Log()
{
string methodName = new System.Diagnostics.StackFrame(1, true).GetMethod().Name;
string moduleName = new System.Diagnostics.StackFrame(1, true).GetMethod().ReflectedType.FullName;
var appLog = LogManager.GetLogger(loggername);
appLog.Error(...);
}
}
that's not a problem; just use ILog as usual in assembly B.
just make sure you call Configure() once in your application's lifetime.
Yes.
I recommend familiarizing yourself with log4net. a simple google search or a look at the docs should do the trick.
<root>
<level value="DEBUG"/>
<appender-ref ref="LogFileAppender"/>
</root>
It will log only in debug mode, so make following entry in config:
<root>
<level value="ALL"/>
<appender-ref ref="LogFileAppender"/>
</root>

log4net multiple adonetappender

Is there a way to use more than one ADONetAppender in the same application. Currently I have one ado appender logging to the "Log" table. I would like to add another ADONetAppender to log to another table in the same application. Searching the google did not return much help.
Please let me know.
thanks
Yes, in my Blog post here: http://weblogs.asp.net/stevewellens/archive/2012/01/22/log4net-log-to-a-javascript-console.aspx I use three appenders.
Here is where they get listed:
<logger name="MyLogger">
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="TraceAppender" />
<appender-ref ref="JSConsoleAppender" />
</logger>
There's more but I'm not going to duplicate the whole post here.
Below is the code to use multiple ADO Appender
Just copy your ado appender and paste it again in your config file with below changes:
<appender name="CustomAppender" type="log4net.Appender.ADONetAppender">
Name of the appender should be different for Both the appender.
Then add into root tag
<root>
<appender-ref ref="ADONetAppender"/>
<appender-ref ref="CustomAppender"/>

Categories

Resources