Retrieving file value from log4net's config file - c#

I'm stuck in a situation where I believe I need to know the name of the log file that the user has specified in logging.xml. Specifically, I am trying to retrieve the value of the value attribute in the file element, as shown below (taken from the log4net docs)
For full details see the SDK Reference entry:
log4net.Appender.FileAppender.
The following example shows how to configure the FileAppender to write messages to a file. The file specified is log-file.txt. The file
will be appended to rather than overwritten each time the logging
process starts.
<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>
When I loop over the appenders with the following code:
log4net.Repository.ILoggerRepository repo = LogManager.GetRepository();
foreach (log4net.Appender.IAppender appender in repo.GetAppenders())
{
FileAppender fa = appender as FileAppender;
}
I am unable to find the value "log-file.txt" anywhere in the fa object. Perhaps I have missed it since there are a lot of members and data exposed in the debugger.
Can anyone suggest a way to get at this value?

FileAppender has property File which contains path to the file that logging will be written to. But before you start looking for this property, verify Name of appender - you can have several FileAppenders configured.
Also keep in mind that RollingFileAppender also matches condition appender is FileAppender, because it is derived from FileAppender.
string file = repo.GetAppenders()
.OfType<FileAppender>()
.Where(fa => fa.Name == "FileAppender")
.Single()
.Name;

Related

Log4net - Suppress "exception" from being appended to custom "PatternLayout"

When using a custom "PatternLayout", log4net is appending the "exception" information (when present) to every log entry. I am trying to control the output of the message and stack trace information and would like to "suppress" this information. I have searched around but cannot find a way to do it. Any ideas?
Sample web.config entry (for a RollingFileAppender):
<layout type="Example.Class.CustomLog4netLayouts,Example">
<conversionPattern value="%date [%thread] [RID:%property{CLIENT_REQUESTID}]
%-5level %logger [%property{NDC}] - %cleanmessage - %cleanstack%newline" />
</layout>
Thanks
Configure the layout like this:
<layout type="Example.Class.CustomLog4netLayouts,Example">
<IgnoresException value="False" />
...
Setting IgnoresException to false tells the appender that the layout will take care of the exception. Thus you can choose not to print the stack trace.

Setting up Log4Net to log output from a Class Library

I'm trying to setup Log4Net (this is my first time using Log4Net) to log to a text file in an assembly. I'm not getting any errors, but it's also not working. I can breakpoint the lines where I am logging my output and see that they are reached, but like I say nothing happens.
Where am I going wrong?
I have added the following to my packages.config file, inside the <packages> attribute:
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender,log4net">
<file value="c:\CTI\log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="FileAppender"/>
</root>
</log4net>
</configuration>
I have added the following line to AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
I added the Log4Net assembly using NuGet and I am logging like this:
private log4net.ILog _Log;
_Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
_Log.Debug("FooBar");
Like I say, no errors but nothing happens either.
What am I missing?
One thing that is wrong is that you are adding the log4net configuration section to the nuget config file (packages.config).
You can have the configuration in the app/web config or in a separate file to which you point from the appSettings, e.g.
configuration is in a file called config.log4net (the copy to output directory attribute of the file is set to copy always) and you add the following entry in app/web.config:
<add key="log4net.config" value="config.log4net"/>
If you don't want to depend on a web/app configuration, you can set the ConfigFileExtension property of the XmlConfiguratorAttribute attribute in AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
Then name the log4net configuration file the same as your exe/assembly plus the configured extension, e.g. MyApplication.exe.log4net or MyLibrary.dll.log4net
Another thing that is wrong is your appender filter. The range that you have set excludes DEBUG level, which you expect to log. Here are all logging levels:
ALL
DEBUG
INFO
WARN
ERROR
FATAL
OFF
As you can see, DEBUG is not between INFO and FATAL.

log4net EventLog custom logname created, but not used

In a project, i'm using log4net to write down in the event log. I need to create a custom log so all will go there. I have tried to add the event to different logs, and it worked, but for some reasons, now it is impossible to change the logname from the config file. Even if I change it, it will keep the previous one and log into it. Here is a sample of my app.config:
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{yyyy-MMMM-dd HH:mm:ss, fff} [%thread] %level %message %exception%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="FATAL" />
</filter>
<ApplicationName>TestLoggerFichierConfig</ApplicationName>
<LogName>AgentLogger</LogName>
</appender>
I read that the event log must be restarted when adding a new log so the recent events will be displayed in it. I did this, and it allowed me to see the new log that has been created, but nothing will go there. Is it possible to force Log4Net to stop using the previous log to rather use the one I defined in the app.config?
Thanks for the help.
Update:
It seems that le EventLogs recognizes the source application and decide in wich log to put the new events since he remembers where it previously went. When I first set the logName, it works fine. If I stop the app, change the logname and restart it, the event will still go to the previous log. If the logName does not exists in the event log, it will be created, but not used! There might be something to do, but it is not in the side of log4net, and it may be dangerous to change the windows settings at this level. I created two eventLogAppender on the same app.config file, both pointing at different logs. the events got to the same log though. It is being obvious that the problem doesn't come from log4net, and the solution to my problem will not be solved by code. Thanks for the great advices though.
Something is probably wrong with your configuration and it is simply not telling you about it because log4net itself is designed to never, ever throw errors.
You can turn on internal debugging for log4net, but don't deploy to production with log4net debugging turned on. Weirdness will eventually happen if deploy your product with the log4net debugging switch on.
http://haacked.com/archive/2006/09/27/Log4Net_Troubleshooting.aspx
http://logging.apache.org/log4net/release/faq.html (see the troubleshooting section)
I ran into this and it wasn't down to log4net but the re-mapping of the source to a new custom log. I took log4net out of the equation and finding that the problem occurred usint the EventLog class directly, I eventually found EventLog.CreateEventSource is not creating a custom log
I think it's also the reason behind this Windows service always writes to custom log and application log
First and foremost, I'd encourage you to turn on internal debugging, as found in the link ntcolonel posted. Add this to your config file:
<add key="log4net.Internal.Debug" value="true"/>
Perhaps I am not understanding your question entirely, but I'd like to ensure you have both created the appender and properly tell log4net that you want to actually use that appender:
<log4net debug="true">
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Logs\SomeApplication.xml"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<countDirection value="1"/>
<maxSizeRollBackups value="30"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.XmlLayoutSchemaLog4j">
<locationInfo value="true"/>
</layout>
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="SomeDistributionList#somehost.com"/>
<from value="SomeApplication#somehost.com"/>
<subject type="log4net.Util.PatternString" value="Some Application Error - %property{log4net:HostName}"/>
<smtpHost value="smtp.somehost.com"/>
<bufferSize value="1"/>
<threshold value="ERROR"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %property{log4net:HostName} %logger %level %newline%newline%property{ExceptionThrottleInformation}%newline%newline%message%newline"/>
</layout>
<filter type="SomeNamespace.SomeSubNamespace.Log4Net.ExceptionThrottleFilter, SomeSubNamespace">
<threshold value="10"/>
<thresholdTimeoutSeconds value="60"/>
<timeoutSecondsBetweenMessages value="600000"/>
<exceptionText value="Timeout expired"/>
</filter>
</appender>
<appender name="DatabaseAppender" type="SomeNamespace.SomeSubNamespace.DatabaseTraceAppender, SomeSubNamespace">
<hoursToKeepInformationalTraces value="48"/>
<hoursToKeepErrorTraces value="96"/>
<threshold value="INFO"/>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="RollingFileAppender"/>
<appender-ref ref="SmtpAppender"/>
<appender-ref ref="DatabaseAppender"/>
</root>
Note that while I have multiple appenders, I reference which to call within the root tag. Since you didn't post your whole config file, it's tough to tell if everything is matching as it should.

log4net print DateTime/calling class/function on each line

Is there any way using log4net to automatically write date/time and class name/function name to the start of each logged line?
In the log4net configuration file modify Appender section by adding a PatternLayout with custom format. Following pattern will output DateTime ClassName.MethodName
<appender name="DebugOut"
type="log4net.Appender.OutputDebugStringAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{MM/dd/yy HH:mm} %C{1}.%M" />
</layout>
</appender>
You can output fully qualified name of class by changing %C{1} to %C

Where will log4net create this log file?

When I set the file value to logs\log-file.txt, where exactly will it create this folder? In the /bin directory?
My web.config looks like this:
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="logs\log-file.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
</log4net>
Is this the correct way to log:
ILog logger = LogManager.GetLogger(typeof(CCController));
logger.Error("Some Page", ex); // where ex is the exception instance
If you want your log file to be place at a specified location which will be decided at run time may be your project output directory then you can configure your .config file entry in that way
<file type="log4net.Util.PatternString" value="%property{LogFileName}.txt" />
and then in the code before calling log4net configure, set the new path like below
log4net.GlobalContext.Properties["LogFileName"] = #"E:\\file1"; //log file path
log4net.Config.XmlConfigurator.Configure();
How simple is it? :)
it will create the file in the root directory of your project/solution.
You can specify a location of choice in the web.config of your app as follows:
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="c:/ServiceLogs/Olympus.Core.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value=".yyyyMMdd.log" />
<maximumFileSize value="5MB" />
<staticLogFileName value="true" />
<lockingModel type="log4net.Appender.RollingFileAppender+MinimalLock" />
<maxSizeRollBackups value="-1" />
<countDirection value="1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level [%thread] %logger - %message%newline%exception" />
</layout>
</appender>
the file tag specifies the location.
The file value can either be an absolute path like "c:\logs\log.txt" or a relative path which I believe is relative to the bin directory.
As far as implementing it, I usually place the following at the top of any class I plan to log in:
private static readonly ILog Log = LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
Finally, you can use it like so:
Log.Debug("This is a DEBUG level message.");
Log4net is saving into your project folder. Something like: \SolutionFolder\ProjectFolder\bin\SolutionConfiguration\logs\log-file.txt.
Where:
SolutionFolder is where you save your solution
ProjectFolder is the folder where your project lives into the solution and
SolutionConfiguration is the folder that contais all the binaries of your project (the default is Debug or Release)
Hope this helps!
FileAppender appender = repository.GetAppenders().OfType<FileAppender>().FirstOrDefault();
if (appender != null)
logger.DebugFormat("log file located at : {0}", appender.File);
else
logger.Error("Could not locate fileAppender");
For the log folder and file stuff, go with #Bens answer.
I will comment on the creating log part, though. Imo there is no correct way. When coding loggers manually I do it the way you're doing it:
ILog logger = LogManager.GetLogger(typeof(CCController));
because it is short and concise.
That said, I do not create the logger instances inside the classes these days, I let my IoC container inject it for me.
I was developing for .NET core 2.1 using log4net 2.0.8 and found NealWalters code moans about 0 arguments for XmlConfigurator.Configure(). I found a solution by Matt Watson here
log4net.GlobalContext.Properties["LogFileName"] = #"E:\\file1"; //log file path
var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));
I think your sample is saving to your project folders and unless the default iis, or .NET , user has create permission then it won't be able to create the logs folder.
I'd create the logs folder first and allow the iis user full permission and see if the log file is being created.
if you want to choose dynamically the path to the log file use the method written in this link: method to dynamic choose the log file path.
if you want you can set the path to where your app EXE file exists like this -
var logFileLocation = System.IO.Path.GetDirectoryName
(System.Reflection.Assembly.GetEntryAssembly().Location);
and then send this 'logFileLocation' to the method written in the link above like this:
Initialize(logFileLocation);
and you are ready to go! :)
In your case, the log file will be in bin\Debug\netcoreapp3.1\ folder
and this may depends on your framework too.
I used Asp.Net core 3.1 so the folder path is bin\Debug\netcoreapp3.1\

Categories