NLog - Почему заблокированные файлы не освобождаются после вызова Shutdown? - PullRequest
0 голосов
/ 05 февраля 2020

Я понимаю, что NLog LogManager.Shutdown () эффективно удаляет все элементы журналов и прекращает журналирование. После этого должно работать программное удаление заблокированного файла журнала, вместо этого я обнаружил, что он не удаляется сразу, файл все еще заблокирован и разблокируется только после завершения процесса.

Это моя программа c config:

            var fileTarget = new FileTarget()
            {
                FileName = "logs.txt",
                Layout = <string layout>,
                KeepFileOpen = true,
                ArchiveAboveSize = 50000000,
                ArchiveEvery = FileArchivePeriod.Day,
                ArchiveNumbering = ArchiveNumberingMode.DateAndSequence,
                ArchiveDateFormat = DatePattern
            };

            var asyncFileTarget =
                new NLog.Targets.Wrappers.AsyncTargetWrapper(fileTarget, 10000, NLog.Targets.Wrappers.AsyncTargetWrapperOverflowAction.Block);
            asyncFileTarget.Name = "async_target";

            var config = new LoggingConfiguration();
            config.AddTarget(asyncFileTarget);
            config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, asyncFileTarget);

Тогда, если я это сделаю,

    LogManager.Shutdown(); //logs get flushed and written to the file
    File.Delete("logs.txt"); //Nothing happens, file deletes only after process exits

Я также попытался

    LogManager.Configuration = null;

, который имел тот же результат.

I необходимо иметь KeepFileOpen = true по соображениям производительности. Как мне заставить NLog выпустить заблокированные целевые файлы?

Ответы [ 2 ]

0 голосов
/ 09 февраля 2020

Когда вы проверите источник NLog, вы увидите, что завершение работы закроет все цели. В Filetarget это CloseTarget. Это снимет блокировки в FileAppenders.

Я создаю очень маленький пример, показывающий, как это работает. Вы могли видеть это здесь, в Github . Использование NLog 4.6.8.

Демонстрационная часть:

static void Main(string[] args)
{
    const string fileName = "C:/temp/logs.txt";

    var config = CreateLogConfig(fileName);
    LogManager.Configuration = config;

    Console.WriteLine("Write logs");
    var myLogger = LogManager.GetLogger("myLogger");
    myLogger.Info("Hi from my logger!");

    LogManager.Flush();// flush to check if really locked. You could disable this and it still works.

    WriteConsoleFileExistsAndLockInfo(fileName);

    Console.WriteLine("Shutdown NLog");
    LogManager.Shutdown(); //logs get flushed and written to the file

    WriteConsoleFileExistsAndLockInfo(fileName);
    Console.WriteLine($"File content: {File.ReadAllText(fileName)}");
    Console.WriteLine($"Full path: {new FileInfo(fileName).FullName}");
    Console.WriteLine("Deleting file ...");
    File.Delete(fileName);
    Console.WriteLine("Deleted file");
    WriteConsoleFileExistsAndLockInfo(fileName);
}

Вывод:

enter image description here

Если он все еще не работает на вашем сайте, проверьте Внутренний журнал NLog : <nlog internalLogFile="c:\log.txt" internalLogLevel="Trace">

Конечно, это может быть другой процесс, блокирующий ваш файл. Может быть, антивирус?

0 голосов
/ 05 февраля 2020

Моим лучшим предположением будет то, что nLog (с которым я не знаком) работает в другом потоке. Я не уверен, насколько вы знакомы с многопоточностью, но это будет означать, что код File.Delete (Logs.txt) может быть выполнен до того, как LogManager сможет завершить sh завершение работы.

Возможно, попробуйте использовать ключевое слово await в некоторых функциях asyn c? Может это поможет?

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async

В качестве альтернативы, если nLog имеет функцию / индикатор типа «IsBusy» или «isRunning» - вы всегда можете использовать некоторое время l oop ( после того как вы вызвали выключение)?

Грубый пример:

       while (nLog.isBusy)
       {
            // Sleep while we wait for the isBusy status to change
            System.Threading.Thread.Sleep(100); 
       }
...