How do I create a new file for each log4net logger instance? - log4net

I am trying to create a different log file for each thread (the threads are handling some site processing). Essentially just naming the log file with a name that is derived from the site that is being processed.
I know all about the GlobalContext.properties and also the TheadContext.properties and neither really seem to work for what I am trying to do. In pretty much either case any concurrently running threads just use whichever file is the current output file as their output. The only difference I have seen is that if I use the ThreadContext to set the property it makes all the files but only outputs to one, where using global it seems to only make the one file unless the processes start at different times.
What I would REALLY like to do is be able to tell the file to just use the name of the logger object (the name that is used in instantiating the object) in the file name instead of using these properties.

Instead of fighting the configuration, I recommend that you rethink your logging strategy. log4net was not built for a log file per thread/class. Loggers are created at startup or on first write (depends). Use a tailing log file reader, like Kiwi Log Viewer or Splunk, and filter on the thread id or logger name in your messages.
If you put them in your conversion pattern...
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline" />

Related

How to use NLog to write to different file according to parameter

I want to be able to write to logs to a different log file according to one of my log parameters.
Lets say, bankId. Each day and bank will write to their own file like
2019-11-11-bank11.log
2019-11-12-bank11.log
and so on.
How can i achieve that programmatic with some kind of a pattern for the log file.
I don't want to create a new version of my app every time I have a new bankid.
You could set the context in one of the context classes and render it with a layout renderer.
e.g. use ${mdlc} and MappedDiagnosticsLogicalContext:
Config:
<target name="file" xsi:type="File"
fileName="${basedir}/${mdlc:bankid}.log" .. />
Code:
using (NLog.MappedDiagnosticsLogicalContext.SetScoped("bankid", "bank11"))
{
logger.Info("myLogEvent");
}
See also all context layout renderers
Sounds like you have an application-wide setting. For that you should either use:
NLog Config Variables - ${var:bankid}
Global Diagnostic Context - ${gdc:bankid}
I prefer to use the GDC has it has a minimum number of surprises, when modifying at runtime.
You can do this in NLog.config:
<target name="file" xsi:type="File"
fileName="${basedir}/${shortdate}-bank${gdc:bankid:whenEmpty=0}.log" .. />
Then at application startup then you can do this:
NLog.GlobalDiagnosticsContext.Set("bankid","11");
See also: https://github.com/nlog/nlog/wiki/Gdc-Layout-Renderer
You can also extract a setting from config-file:
app.config - https://github.com/NLog/NLog/wiki/AppSetting-Layout-Renderer
appsettings.json - https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer

Is there any logging function which allows you to create n number of log files programatically?

I'm working on a program which needs to write messages to multiple log files, depending on the number of threads it creates. The amount of threads is arbitrary. Is there a logging facility which allows me to create a separate log file for each thread? I'm currently using sl4j and logback, and it seems to require that the file names be configured in a properties file.
Logback's SiftingAppender separates (or sifts) logging according to a given runtime attributes. The general structure goes likes this:
<appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<key>clientPort</key>
<defaultValue>unknown</defaultValue>
</discriminator>
<sift>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>server-${clientPort}.log</file>
....
</appender>
</sift>
</appender>
By default, SiftingAppender assumes MDCBasedDiscriminator which relies heavily on MDC.
It is probably exactly what your are looking for. See also http://www.nurkiewicz.com/2013/04/siftingappender-logging-different.html

Creating dynamic log files via Log4Net by process ID & date without rename policy

I have been scratching around Stack and the net for a solution to my particular use case but has yet have not found one.
Log4Net 1.2.10
IIS 6.1
.NET application using CastleCore
My requirement is to create a unique file name based on process id per hour with process id, date and hour in the filename. Although if the process Id were to change within that hour then create a new file name based on that process id and date/hour.
I have a service running on a web farm in IIS, this has 4 worker processes running simultaneously, 2 app pools 2 process per pool. So 4 log files being written too simultaneously.
My current config (below) appears to work upto a point. The files get created and are logged too simultaneously, great! The logging is quite heavy in that over the course of an hour it will log around
200MB per process id.
During the course of the hour one of the files out of the two simply stops writing. I have set Minimal lock and different process id's which should prevent any deadlocks, race conditions or collisions.
My current config is below
<appender name="WSG_file_appender" type="WSG.Logger.LogAppender,WSG.Logger">
<file type="log4net.Util.PatternString" value="../../WSG/IWSGServices-[%processid]" />
<datePattern value="-dd.MM.yyyy-HH'.log'" />
<staticLogFileName value="false"/>
<rollingStyle value="Date" />
<appendToFile value="true" />
<maximumFileSize value="500MB" />
<maxSizeRollBackups value="50" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%d] [%t] %-5p [%m]%n" />
</layout>
The format of the log that is generated is:
IWSGServices[8977]-23.03.15.14.log
This is what I want, in the above example that is the log for process ID 8977 for 1400 hours. At 1500 new logs gets generated for each process id in use and the new hour stamp.
When the logging stops in log4net debug mode I get this error many times:
log4net:ERROR [LogAppender] Failed to write [].
System.ArgumentOutOfRangeException: Count cannot be less than zero.
Parameter name: count
at System.String.CopyTo(Int32 sourceIndex, Char[] destination, Int32 destinationIndex, Int32 count)
at System.IO.StreamWriter.Write(String value)
at log4net.Util.QuietTextWriter.Write(String value)
I have not found any similar cases of this error within log4net so use cases are limited. I suspect there is some I/O issue or log4net (at least this older version) is not capable of fulfilling my use case. However I am not convinced latest versions will be either. I have not upgraded log4net yet due to reported issues with later versions and Castle Core implementations.
Setting StaticLogFileName=true results in filenames being created without the date stamp i.e WSGServices[8699], and then on the hour gets renamed to IWSGServices[8977]-23.03.15.14.log for example. This is not what I want as for this use case I do not want files to get renamed as I have a log reader which sees this as a new file and parses it again.
I have tried a large number of combinations including with and without locking models, Rolling styles, datepatterns and the config above seems to be the closest I have come. It's possible this config will work if I roll per minute but this will result in over 3000 log files per day which is not practical.
I'd like to achieve this under the current version of log4net I am using, however if I patch to 2.11 there is a setting of PreserveLogFileNameExtension parameter although the file will still get renamed but just not after the extension.
One suggestion I looked at was setting the IIS pool setting Disable Overlap Recycle to false but this didn't make any difference as would only come into play on recycles of the app pool.
Another alternative is too log both processes form each app pool to a single log file although due to the amount of writes I think this solution would not work without further process collisions.
Any help appreciated in case I have missed something or if anyone has used this in current or later log4net versions.

in log4net, is it possible to mute loggers by name rather than by level only?

I am building a new C# project using the DLLs produced by some colleagues.
They have log4net statements at all levels popping around in such number that my logs are hardly visible in the mass...
in log4net, is it possible to mute loggers by name rather than by level only ?
or even better, by assembly name ? I want to mute logging in DLLs that I use...
Thank you guys for any hints !
It should be a matter of adding a section to your config file like
<logger name="xxx" additivity="false">
<level value="OFF" />
</logger>
If logging is using the standard convention, ie
internal static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
then you need to replace xxx can be the namespace or part of the namespace that you want to disable.
If your colleagues are using the exact same namespace name as you are using,then you might need to replace xxx with the actual class name which could mean you end up with a large number of entries in your config file to disable logging for each of their classes.

how to switch log4net multiple log files using C# code?

I'm using log4net, I would like to have 2 logs,
- BasketballCustomer.log, for all Customers that plays Basketball;
- ChessCustomer.log, for all Customers that plays Chess.
, while for each customer, whether he/she plays Basketball or Chess, is only known until runtime.
I would like to have each log configured separately, about log file name, size, number, log level, etc.
Also, I'd prefer such set up done by C# code, not config file.
How could I do that?
I tried search on net, there are some articles but none meet exactly my requirements
- Log4Net and multiple log files talked about multiple log files but it does not toggle during runtime;
- Configure Log4net to write to multiple files is similiar but it's done in config file....
Please kindly suggest, many thanks!
You can do this by using an environment variable in the log4net.config and then set the value of the environment variable through the C# code
So somewhere in your C# class, do something like:
Environment.SetEnvironmentVariable("log_file_name", "MyLogFileName");
And then in the log4net.config that is used, specify the value to the name of the environment variable. The syntax would be something like this:
<param name="File" value="${log_file_name}".log/>

Resources