Can't copy Serilog file on Xamarin.Android while logger is active
See original GitHub issueWe are currently using Serilog as bases for logging in Xamarin.Android project. We have a function in the app which allows users to push their local logs on demand. So, we’ll go to root logging directory, copy the existing logs to a new temp location, zip them and then upload to our cloud. Everything was working fine till the latest Xamarin.Android release. Now, as soon as you try to copy the file which is currently being used by Serilog File sink, your receive the following exception
System.IO.IOException: Sharing violation on path
Here is example that I’ve created that demonstrates the issue SerilogSample.zip
Here is a small piece from the above sample
LoggerConfiguration loggerConfig = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Debug()
.WriteTo.File(new JsonFormatter(),
logPath,
rollingInterval:RollingInterval.Day
// ,shared:true
);
Logger logger = loggerConfig.CreateLogger();
for(int index = 0; index < 10; index++)
{
logger.Information($"Log message {index}");
}
// logger.Dispose();
string[] logFiles = Directory.GetFiles(rootLoggingDirPath);
foreach(string file in logFiles)
{
File.Copy(file, Path.Combine(logArchive, Path.GetFileName(file)));
}
If I uncomment the line logger.Dispose();
everything will start to work as expected. But without that the app crashes on line File.Copy
The project has 3 targets - iOS, Droid & .NET Core console. The app runs perfectly fine on Console both Mac & Windows, but not on iOS/Droid.
This code also worked perfectly fine on VS 2017.
Another aspect is that I tried to set sharing flag to true
, and file wasn’t being created at all. Only later I discovered that shared files are not supported in Xamarin in another issue #44
I dug a little bit deeper and checked how file sink opens up a stream to write, and I was able to reproduce this issue without Serilog using ordinary streams and File.Copy
. Here’s the sample
using(Stream outputStream = File.Open(testFile, FileMode.Append, FileAccess.Write, FileShare.Read))
using (StreamWriter outputFile = new StreamWriter(outputStream, encoding))
{
for(int index = 0; index < 10; index++)
{
outputFile.WriteLine($"Log message {index}");
}
outputFile.Flush();
File.Copy(testFile, archiveFile);
}
The above code has exact behavior as the Serilog issue I am experiencing. Probably this is not a Serilog issue but something that is related to Xamarin, and in fact I’ve created an issue in Xamairn.Android repo as well.
For now, I’m seeking for workaround. The ideal solution would be to force the Serilog file sink to create a new file on demand, so all locks from existing files are removed, and I’ll be able to copy that file with ease. In fact, this is the initial way I wanted to implement log upload, and I wasn’t able to find such solution in File sink, and went with hard route of tracking exact file position, and then using streams to copy files partially as they might have been already uploaded partially previously. We can’t dispose the logger either, cause it’s dependency injected and is used in other places of the app. So, couple of questions
- What can be done to workaround this situation? Is it possible to force a new file to be created?
- Is there something that can be done to overcome this locking issue in general from Serilog code perspective without Xamarin intervention?
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (2 by maintainers)
After more thorough investigation I can see that
File.Copy
issue is not Serilog’s issue. We’ve found a workaround and instead of usingFile.Copy
we use the following code for copying filesThe crucial aspect in here is that you use
File.Open
method with parameterFileShare.ReadWrite
to make this stream work nicely with Serilog’s internal open write stream. Though performance testing revealed this approach to be 5 times slower thanFile.Copy
in our system the largest file is 30MB and it’s still matter of milliseconds to do the copy on Android device, so the workaround was acceptable in our scenario. I’m sure If I spend several hours I’d be able to optimize the stream copy process a bit, but it’s not going to be as optimal asFile.Copy
ever.Thus, I’d say this issue is more feature request than an issue. If we had a possibility to force the loggers to roll over a new file, than all of the problems would be resolved.
Hi @mikegoatly ! Yes, that’s the goal of the shared file sink - multiple processes can concurrently log to the same file 👍