How to include log4net for a class library? - c#

I want to implement logging function into a class library, which is itself referenced in a webservice. I tried to add app.config and did everything needed, but it seems that when an exception is thrown, log4net simply does nothing.
my app.config
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="D:\\mylogfile.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="test" />
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="error" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline%exception" />
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
in AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "app.config")]
in LogManager.cs:
private static readonly ILog Log = log4net.LogManager.GetLogger
(MethodBase.GetCurrentMethod().DeclaringType);
public static void WriteLog(Exception ex)
{
Log.Error(ex);
}
Can you please tell me what's wrong? How can I get log4net working for my class library?
Thank you

At runtime, config file is always used from host application, unless declared explicitly. Here in case, web.config is being used not app.cofig. Rather mention some other custom config file name and ensure that file is copied in virtual directory of web service. Also as chibacity said, ensure permission on log file. Better keep it in app_data folder for web service host.

You could use some kind of injection, either you build a simple one like:
public interface ILogger
{
void LogInfo(string message);
.
.
.
}
And then you just inject something that matches that interface, like a wrapper for log4net or such.
But, I think the most correct thing is to not log in the class library. Why I think so is because the library itself is not the application, your web service is so your web service should decide what to log. If you want to log exceptions just don't catch them in the class library and let your web service handle the logging. This will also make it easier to centralize the logging.

Please see my answer to the following question:
Use log4net in SDK
It has a log configuration routine that will construct a complete path to a log4net config file. As you are in a webservice it my not be looking where you expect for "app.config".
Also make sure that you have permission to write to "D:\mylogfile.txt" from your webservice.

Related

When do I need to specify log4net.Appender.FileAppender.LockingModel in ASMX services

We have a project which consists of 3 different ASMX service files for example Service1.asmx, Service2.asmx, and Service3.asmx all of which are running from the same application pool.
We've just started using log4net to log our requests and responses, and it seems to be logging every request and response for each service correctly in the same log file (which is what we want).
However, on reading log4net config examples, I've seen some examples that are using log4net.Appender.FileAppender.LockingModel.
Do I need to consider this in my scenario? This is my current code:
public class Global : System.Web.HttpApplication
{
public static readonly log4net.ILog asmxDebugLog = log4net.LogManager.GetLogger("AsmxDebugLogFile");
protected void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
}
}
In my web.config file I have
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<appender name="AsmxDebugLogFile" type="log4net.Appender.RollingFileAppender">
<file value="App_Data/log4net_ASMX.DEBUG_" type="log4net.Util.PatternString" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyy-MM-dd'.log'" />
<staticLogFileName value="false" />
<maximumFileSize value="5GB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<logger name="AsmxDebugLogFile">
<level value="DEBUG" />
<appender-ref ref="AsmxDebugLogFile" />
</logger>
</log4net>
</configuration>
We are logging like this
asmxDebugLog.Debug("Log something useful");
You only really need to care about locking when the loggers are not all in one process, which for you it seems they are (1 app pool ~= 1 process).
The default locking mode is 'exclusive', which is fastest, so you don't need to (or want to) change that (and slow it down).
If you later split the services into different app pools, you can then choose either InterProcess (if all on the same machine) or Minimal.

Log4Net not working in MVC web application but working in console and window application

I have created a solution which consist of class library, MVC web application and console application.
For my class library project is actually responsible to perform logging using log4net which is also included the log4net configuration in the log4net.config. Currently i am facing a problem which the logging is not working when my web application call the logging function from class library. But it's working fine when my console application. My log4net.config looks as below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\\Temp\" />
<datePattern value="'Test.log_'yyyy-MM-dd'.log'" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<appendToFile value="true" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout, log4net">
<conversionPattern value="%date [%thread] %-5level %logger [%method] - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
</configuration>
I have also included the line below in my class library [AssemblyInfo.cs]
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
My sample class library function as below:
private static readonly log4net.ILog log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void Write ()
{
log.Info("Success");
}
I have set the log4net.config Copy to Output Directory to Copy always.
Sample log4net output from console application [Test.log_yyyy-MM-dd.log]:
2019-10-01 12:07:48,923 [1] INFO ClassLibrary2.Class1 [Write] - Success
But there is log file generated for MVC web application. Is there any additional step need to configure for the web application?
I would be grateful for any help with it.
Thanks.
Did you add something in your Application_Start method? (global.asax) like:
string l4net = Server.MapPath("~/log4net.config");
log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(l4net));
Try To Add ConfigSections in your web.config. Also there's the guide especially for MVC applications.
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
Complete Guide

Problematic N-Tier logging with log4net

I am currently developing series of web services in WCF using .NET 4.5. For my logging I have chosen log4net framework but I found that its a big problem to use it in my project design.
I have everything separated into projects like this :
DataAccess
Common
etc. etc.
ExternalServicesContracts
ExternalServices
ExternalServicesProxies
InternalService
All of the services projects contains more services.
Situation
I need my log files to look like this ServiceName_YYYY_DDMM.log.
So in the log4net config file i need to use different loggers per namespace of the web service. I can achieve it by using loggers like this :
For the first service :
private static readonly ILog Log = LogManager.GetLogger(typeof(MyFirstService));
And the same for the second service :
private static readonly ILog Log = LogManager.GetLogger(typeof(MySecondService));
and then in config file I just point to them by loggers
<logger name="ExternalServices.MyFirstService">
<appender-ref ref="FirstServiceAppender"/>
</logger>
<logger name="ExternalServices.MySecondService">
<appender-ref ref="SecondServiceAppender"/>
</logger>
And in appenders
<appender type="log4net.Appender.RollingFileAppender" name="FirstServiceAppender">
<file value="c:\temp\FirstService"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.lo\g"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
<appender type="log4net.Appender.RollingFileAppender" name="SecondServiceAppender">
<file value="c:\temp\SecondService"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.lo\g"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
Problem
After this change, I can`t see anything from my DataAccess and Common because I had to do the same strategy with classes inside the layer.
So the logger will be loaded the same way like this:
private static readonly ILog Log = LogManager.GetLogger(typeof(UsersProvider));
I could add another logger for both projects but I need the logs from it to be written inside the same file (the log file used by the caller).
Question
I really cant separate the services into more projects because of the client.
Is there a way to use the same logger inside a library as the caller is using ? (So the DataAccess and Common writes logs into FirstServiceAppender when the service is using it.)
Or is there any pattern that would get me out of this situation ?
I don't have time to try this out right now, but this should be easier that you think it is. You can try configuring log4net to have a dynamic file name based on a GlobalContext.Properties value. In each service, put a value GlobalContext.Properties that "names" the service. This should be ok as each service is essentially a separate process, so using the GlobalContext should not result in any conflicts. This way you will need only one file target and your loggers can be configured very simply (just send the output to the one file target).
Configuration should be something like this:
<appender type="log4net.Appender.RollingFileAppender" name="RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\temp\%property{Service}"/>
<rollingStyle value="Composite" />
<datePattern value="_yyyy_MM_dd.log"/>
<maxSizeRollBackups value="-1"/>
<maximumFileSize value="100MB"/>
....
</appender>
<root>
<appender-ref ref="RollingFileAppender" />
</root>
In your code, when each service is initialized, put something like this:
GlobalContext.Properties["Service"] = "FirstService"; // for FirstService
GlobalContext.Properties["Service"] = "SecondService"; // for SecondService
Note that you must set the value into GlobalContext.Properties BEFORE anything else is done with log4net. The best place would be in the static constructor of your application/service.
This configuration should all logs generated in "FirstService" to be written to the FirstService log file and all logs generated in "SecondService" to be written to the SecondService log.
Update:
<appender name="DynamicRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="c:\temp\%property{Service}" />
<datePattern value="_yyyy_MM_dd.lo\g" />
<appendToFile value="true" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="5000KB" />
<preserveLogFileNameExtension value="true"/>
<staticLogFileName value="false" />
<countDirection value="1"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%method] - %message%newline" />
</layout>
</appender>
You can pass logger as a parameter for classes. So maybe your DataAccess classes should take a logger as a constructor parameter and use it for loggin. Then you could give a desired logger from outside.

how to create dynamic log using log4net

My Project is in C# (Windows Form) .net3.5
In my code there are multiple events and in each event multiple searches are running.
I have to create log file for each event and multiple searches can access & write this single log file.
The problem is that I don't know how to use log4net for creating multiple logs with dynamic(set at run time) names.
How to set there location(Path)
I explorer internet regarding my problem but haven't found any help which address this type of issues.
any idea pls
log4net is generally used to have mutiple sources and appenders.
To generate a defined source, ask LogManager to have a named log, generally we use a type to identify a log, but feel free to use a string if you want:
var myLog = LogManager.GetLogger("NAME");
....
var myLog = LogManager.GetLogger(GetType());
In the first case logger is identified by "NAME", in the second by the type name with namespaces.
Then you can configure the appenders, for all logs, for a subset of them, with filters and so on.
Let's see an example:
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="MYFILE" type="log4net.Appender.RollingFileAppender">
<file value=".\logs\myname.log"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level (%thread) %logger - %message%newline"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<!-- all logger append to these appenders />
<appender-ref ref="xxxxxx"/>
</root>
<logger name="NAME">
<level value="INFO"/>
<appender-ref ref="MYFILE"/>
</logger>
<!-- add other appender here -->
Don't forget to call at your application start XmlConfigurator.Configure();

Log4net Configuration Issue

Had something weird start happening to me today. I have an asp.net mvc app with log4net setup and everything had been working fine. Something must have changed somewhere and now nothing is getting logged (no log file is being created).
Here's my global.asax.cx
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure();
}
Here's my configuration in my web.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<file value="c:\logs\api\ApiLog.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
For some reason the c:\logs\api\apilog.txt file never gets created. However, if I change my application_start method to this it works fine:
log4net.Config.XmlConfigurator.Configure(new FileInfo("DirectPathToMy\web.config"));
Any ideas why calling Configure() is not finding the configuration in my web.config by default?
Don't know why your approach don't work but the issue is that you need to make sure it is activated in your project.
I usually put this as an assembly level reference in my AssemblyInfo.cs under /Properties:
[assembly: log4net.Config.XmlConfigurator()]
Reference:
http://logging.apache.org/log4net/release/manual/configuration.html

Categories