I have a service application that on startup reads an XML file and starts a thread for each entry in the XML file. Each thread creates an instance of a worker class which requires a logger to log any output to a thread specific log file.
In the services app.config I have the log4net configuration settings set to use an XML appender and the file is specified as a PatternString as shown below:
<appender name="XmlAppender" type="log4net.Appender.FileAppender">
<file type="log4net.Util.PatternString" value="D:\Temp\Logs\%property{LogName}.log" />
<immediateFlush value="true"/>
<appendToFile value="true" />
<layout type="log4net.Layout.SimpleLayout" />
</appender>
In a thread locked method for each instance of the worker class created I get the logger using the log4net.LogManager.GetLogger("MyLogger")
method and then I set the current threads PatternStrings LogName property using ThreadContext.Properties["LogName"] = "Log name prefix"
.
All of the files are created but when the logger is called it just logs all message to one seemingly random file.
I have searched about for quite a while trying to find a solution or some answers to what I am doing wrong but I have had no luck.
Does anyone have any idea why this is happening?
Adam's answer has worked pretty well for me, but there is one this I would like to add. If there is a possibility of your logFileName being reused in your application, you will need to check to make sure the repository does not already exist.
I think I have worked out the issue. The steps follow:
ILoggerRepository
object (loggerRepository
in this example) on each thread.In return I get a new configured logger pointing to the respective file for that thread.
The XML configuration is the same as it was originally and shown here for completeness:
The code to create the loggers is below. Each time this code is run it is run in its own thread.
This seems to work with no issues so far. I will be moving forward with this solution for the moment but I will update this post if I find out anything else.
@Adam's solution helped me. For posterity here's simple code that creates 5 Tasks (using threads from the threadpool), where in each task each thread writes to a separate log file (and then sleeps for 1 second), five times.
.NET Framework 4.7.2
.NET Console Application
AssemblyInfo.cs
Program.cs
App.config
C:\logs\Worker0_TaskLog.log
C:\logs\Worker1_TaskLog.log
C:\logs\Worker2_TaskLog.log
C:\logs\Worker3_TaskLog.log
C:\logs\Worker4_TaskLog.log