Log4Net - checking attached appenders in a unit test - c#

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?

Related

The custom Logger is giving error when call from another project in solution

I have created a class for customLogger to log the data and made a change in the web.config file for the same
<log4net>
<root>
<level value="ALL"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="MultiPhaseCreateOrderMainLogger"/>
<appender-ref ref="CustAppender" />
</root>
<appender name="CustAppender" type="getClient.CustomAppender.CustAppender">
<threshold value="ERROR" />
</appender>
</log4net>
In the class where I need to do the logs, I have added the following code.
private static readonly log4net.ILog log = log4net.LogManager.GetLogger("CustAppender");
log.Error("something");
This code is working fine when I am making the request using postman but when I am running this code using another project from solution for writing the test cases. It is not working
Can anyone explain why this is happening?

How not to log group of logging types (say info and debug) for a type in Log4Net?

Say I have a class with
private readonly ILog Log = LogManager.GetLogger(typeof(MyClassName));
And I want to make it not to write into log info and debug messages for only this class type. How shall I configure Log4Net to make it do such thing?
Modify the log4net.config file:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<root>
<level value="DEBUG" />
</root>
<logger name="MyClassName">
<level value="ERROR" />
</logger>
</log4net>
This will set all loggers in the whole application to Debug level, except for MyClassName, which is set to Error level.

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.

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"/>

logging in log4net to different appenders based on circumstances

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.

Categories

Resources