'How to Download log files generated from log4Net

I'm using log4net in a ASP.NET MVC 4 application and I'm trying to download the generated log file from log4Net.

I have in mind to download the log file with a FileResult, like:

[Authorize(Roles = "Admin")]
public FileResult DownloadUserInterfaceLog()
{
    // Get the path of the log file
    string path = (LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders()[0] as FileAppender).File;
    // Get the file
    byte[] fileBytes = System.IO.File.ReadAllBytes(path);
    string fileName = "Log.txt";
    // Return the expected file
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

My problem is that when I call System.IO.File.ReadAllBytes(path);I get an Exception, cause the log file is already used by another process.

I'm already put <lockingModel value="log4net.Appender.FileAppender+MinimalLock" /> (which should release the file after any modification) in my Web.Config with no success.

Begin of log4Net configuration in Web.Config:

<log4net>
    <appender name="Appender-root" type="log4net.Appender.RollingFileAppender">
        <lockingModel value="log4net.Appender.FileAppender+MinimalLock" />
        <file value="Path..." />
        <appendToFile value="true" />


Solution 1:[1]

Here is an article about similar trouble.

File.ReadAllBytes() function is written such that it uses a call like the following to instantiate a FileStream:

FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)

Notice that the FileShare is specified as Read. That means if you have another piece of code writing to the same file at the same time, you will get an error even if the other piece of code created the FileStream by specifying the share mode as “ReadWrite” like so:

FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)

Solution is to write your own custom ReadAllBytes:

public static byte[] ReadAllBytes(String path)
{
    byte[] bytes;
    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        int index = 0;
        long fileLength = fs.Length;
        if (fileLength > Int32.MaxValue)
            throw new IOException(“File too long”);
        int count = (int)fileLength;
        bytes = new byte[count];
        while (count > 0)
        {
            int n = fs.Read(bytes, index, count);
            if (n == 0)
                throw new InvalidOperationException(“End of file reached before expected”);
            index += n;
            count -= n;
        }
    }
return bytes;
}

Solution 2:[2]

you need to close the Appender before accessing the file:

((FileAppender)LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders()[0]).Close()

Solution 3:[3]

This worked for me

            var logFile = System.Web.HttpContext.Current.Server.MapPath("/Log.txt");
            if (System.IO.File.Exists(logFile))
            {
                var copyFile = logFile.Replace(".txt", "");
                System.IO.File.Copy(logFile, copyFile);
                var bytes = System.IO.File.ReadAllBytes(copyFile);
                System.IO.File.Delete(copyFile);
                return bytes;

            }

Solution 4:[4]

However, below code can be used to open the file without throwing exception

using (var stream = File.Open(selectedItem.FileFullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (var streamReader = new StreamReader(stream))
                {
                    while (streamReader.Peek() > -1)
                    {
                        var line = streamReader.ReadLine();
                        // . . .
                    }
                }
            }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 aleha
Solution 2 Alexis Peters
Solution 3 Rick Nash
Solution 4 Carlos Liu