Reputation: 1867
I just updated to xUnit 2.1. I'm using this method via a lot of tests running in parallels from differents assemblies to log to the same file with a certain name. The problem is I can't manage concurrency (even using TextWriter.Synchronized), every time I run my tests, different tests says:
The error is:
Message: System.IO.IOException : The process cannot access the file 'C:\LOGS\myFileName-20170510.txt' because it is being used by another process.
My method is:
private static void WriteToLogFile(string fileName, string strMessage)
{
DateTime utcNow = DateTime.UtcNow;
lock (fileName)
{
using (StreamWriter w = File.AppendText(fileName + utcNow.Year + utcNow.Month.ToString("00") + utcNow.Day.ToString("00") + ".txt"))
{
w.WriteLine("{0};{1};{2}", DateTime.UtcNow, SecurityHelper.GetPrincipalName(), strMessage);
w.Flush();
w.Close();
}
}
}
I tried even (but this doesn't helped):
private static void WriteToLogFile(string fileName, string strMessage)
{
DateTime utcNow = DateTime.UtcNow;
lock (fileName)
{
using (StreamWriter w = File.AppendText(fileName + utcNow.Year + utcNow.Month.ToString("00") + utcNow.Day.ToString("00") + ".txt"))
{
w.WriteLine("{0};{1};{2}", DateTime.UtcNow, SecurityHelper.GetPrincipalName(), strMessage);
w.Flush();
w.Close();
}
}
}
private static readonly ConcurrentDictionary<string, object> Tokens = new ConcurrentDictionary<string, object>();
private static object GetToken(string fileName)
{
if (!Tokens.ContainsKey(fileName))
Tokens.TryAdd(fileName, new object());
return Tokens[fileName];
}
This is due to some strange behaviour of xUnit? Thanks in advance.
Upvotes: 1
Views: 1483
Reputation: 4592
Following line is a problem:
lock (fileName)
Do not use a string and a parameter as lock object. In your case try a private static object. See MSDN and this question on stackoverflow. That would look something like this:
private readonly object Locker = new object();
private static void WriteToLogFile(string fileName, string strMessage)
{
DateTime utcNow = DateTime.UtcNow;
lock (Locker)
{
...
This solves the potential problem that multiple threads want to write at once, but that is not the real problem. Have a look at this stackoverflow question. I do not exactly know how the xunit test runner is working, but if there are multiple processes writing at once you'll get that exception. Instead of using File.AppendText
use this (as suggested by the answer of stackoverflow question):
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
The OS will allow multiple processes accessing the same file.
You might still have following problem: The content might be a mess, because for example two processes might want to write at the same line and then dump two linebreaks consecutively. As a workaround you can append process IDs to the log file.
If this gets too weird consider using a logging library which manages this kind of problem for you.
Upvotes: 1