1

I'm trying to read a log file that was written from a custom ILoggerProvider in a dotnet application:

HostApplicationBuilder builder = Host.CreateApplicationBuilder();
builder.Logging.ClearProviders();
builder.Logging.AddCustomLogger(logFilePath);

using (IHost host = builder.Build())
{ 
    host.RunAsync();
    var hostLogger = host.Services.GetRequiredService<ILogger<Program>>();
    hostLogger.LogDebug("debug");
}

string readLog = File.ReadAllText(logFilePath, Encoding.Unicode);
Console.WriteLine(readLog);

In my custom logger provider, I open the file in Append mode:

_logFileStream = new FileStream(logFilePath, new FileStreamOptions()
{
    Access = FileAccess.Write,
    Mode = FileMode.Append,
    Share = FileShare.ReadWrite
});

And close/dispose it:

public override void Dispose()
{
    if (_logFileStream != null)
    {
        _logFileStream.Close();
        _logFileStream.Dispose();
    }
}

However, when I try to read this file after the using should have disposed the IHost it's still locked (The process cannot access the file because it is being used by another process.)

I've tried adding a shutdown/wait to the host:

host.StopAsync();
host.WaitForShutdown();

I've even tried running GC.Collect(), but still the file remains locked by the host process.

How can I get this IHost to let go of my file?

3
  • 1
    You need to elaborate on your custom logger provider, such as why it needs to override Dispose but doesn't call base.Dispose? Is there another derived type that hasn't called base.Dispose yet? Do you know if this Dispose has been called? Commented 6 hours ago
  • 2
    I notice you don't await the call to RunAsync, i.e. await host.RunAsync();. So the host could be disposed before it's done running. Is that a mistake? Is there any chance that, somehow, the log file is getting opened by some async code after, rather than before, the host is disposed? Commented 6 hours ago
  • 1
    And by using FileShare.ReadWrite, the file can be opened by others. Commented 6 hours ago

1 Answer 1

2

You're disposing your FileStream, but the problem is that the host never disposes your custom logger provider because host.RunAsync() keeps the host running until the process shuts down. Even though the using block looks like it should dispose the host, you're exiting the block before the host actually stops.

RunAsync() is non-blocking. Your code continues immediately, so:

  1. The host is still running

  2. The logging system is still alive

  3. Your logger provider is still holding the file handle

That's why the file stays locked.

Fix: Stop the host before leaving the using block

HostApplicationBuilder builder = Host.CreateApplicationBuilder();
builder.Logging.ClearProviders();
builder.Logging.AddCustomLogger(logFilePath);

using (IHost host = builder.Build())
{
    await host.StartAsync();

    var hostLogger = host.Services.GetRequiredService<ILogger<Program>>();
    hostLogger.LogDebug("debug");

    // Make sure logging is flushed and providers are disposed
    await host.StopAsync();
}
        
string readLog = File.ReadAllText(logFilePath, Encoding.Unicode);
Console.WriteLine(readLog);

Why this works

  • StartAsync() starts the host without blocking.

  • StopAsync() shuts down the host and disposes logging providers.

  • Exiting the using block then disposes the host itself.

  • Only after that is the file handle released.

Important note

RunAsync() never completes until the application shutdown signal occurs.
So if you use RunAsync(), you must await it, or the host won't shut down:

await host.RunAsync(); // blocks

But in your example you only want to fire a log and exit, so StartAsync/StopAsync is the correct pattern.

New contributor
Towseef Altaf is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.