Запись журнала NLog в другое после изменения имени файла цели - PullRequest
0 голосов
/ 11 февраля 2020

Я сослался на это Обновить целевое имя файла NLog во время выполнения и многие другие ссылки, но ни одна из них не работает в моем случае. Я инициализирую регистратор, используя

private Logger logger = LogManager.GetCurrentClassLogger();

Все сообщения журнала ставятся в очередь, затем очищаются с использованием таймера.

this.messageQueue = new ConcurrentQueue<NotificationMessagePacket>();
this.timer = new System.Timers.Timer(1000);
this.timer.Elapsed += (o, e) =>
{
    if (!isWriting)
    {
        lock (_lockObject)
        {
            isWriting = true;
            NotificationMessagePacket packet;
            while (this.messageQueue.TryDequeue(out packet) && packet != null)
            {
                try
                {
                    if (!string.IsNullOrWhiteSpace(packet.DetailMessage))
                        this.Infolog(packet);
                }
                catch (Exception ex)
                {
                    ObjectUtils.EventLogWriteError("NotificationMessagePacket emptying error : " + ex.ToString(),
                        EventLogEntryType.Warning);
                }
            }
        }
        isWriting = false;
    }
};
this.timer.Start();

Я пытаюсь сбросить имя файла моей цели, используя следующий код:

LoggingConfiguration configuration = LogManager.Configuration;

var wrapper = (AsyncTargetWrapper)configuration.FindTargetByName("log");

var target = (FileTarget)wrapper.WrappedTarget;

string path = Path.Combine(basePath, "Test", "Log", string.Concat(DateTime.Now.ToString("dd"), "_", DateTime.Now.ToString("MMMM"), "_", DateTime.Now.Year + @"\AppLogs.txt"));

if (!string.IsNullOrEmpty(message.ProcessId))
    path = Path.Combine(basePath, "Test", "Log", string.Concat(DateTime.Now.ToString("dd"), "_", DateTime.Now.ToString("MMMM"), "_", DateTime.Now.Year + @"\" + message.ProcessId + ".txt"));

target.FileName = path;
target.ConcurrentWrites = false;
LogManager.Configuration = configuration;
LogManager.ReconfigExistingLoggers();

Но иногда сообщения журнала не записываются в соответствующий файл.

1 Ответ

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

Проблема (вероятно)

Я вижу message.ProcessId в вашей конфигурации. Похоже, вы меняете конфигурацию при каждом событии журнала. Это не потокобезопасно! См. Насколько потокобезопасен NLog? .

Как исправить

Хорошая новость, также нет необходимости менять конфиг. Вы можете использовать контекстные классы для ввода значений в конфигурации. Для глобального есть GD C, но есть также контекст для потока и уровня сообщения. (и другие здесь ).

Пример того, как исправить

Вы можете настроить конфигурацию следующим образом:

// Set GDC
GlobalDiagnosticsContext.Set("basepath","somepath");

// Create config
var config = new LoggingConfiguration();

FileTarget fileTarget1 = new FileTarget();
fileTarget1.FileName = @"${gdc:basepath}\Test\Log\${Date:format:dd_MMMM_yyyy}\AppLogs.txt";

FileTarget fileTargetWithProcessId = new FileTarget();
fileTargetWithProcessId.FileName = @"${gdc:basepath}\Test\Log\${Date:format:dd_MMMM_yyyy}\${event-properties:ProcessId}.txt";

var hasProcessIdProperty = "${event-properties:item=ProcessId}!=''";
var rule1 = new LoggingRule()
{ 
    // log without processid to fileTarget1
    Targets = { fileTarget1 },
    Filters = { new ConditionBasedFilter()
    {
        Condition = hasProcessIdProperty,
        Action = FilterResult.Ignore,
        DefaultFilterResult = FilterResult.Log
    } }
};
var rule2 = new LoggingRule()
{
    // log only with processid to fileTarget1
    Targets = { fileTargetWithProcessId },
    Filters = { new ConditionBasedFilter()
    {
        // Log with property processid
        Condition = hasProcessIdProperty,
        Action = FilterResult.Log,
        DefaultFilterResult = FilterResult.Ignore
    } }
};

// Enable trace to fatal (so all levels)
rule1.SetLoggingLevels(LogLevel.Trace, LogLevel.Fatal);
rule2.SetLoggingLevels(LogLevel.Trace, LogLevel.Fatal);

config.LoggingRules.Add(rule1);
config.LoggingRules.Add(rule2);

LogManager.Configuration = config; // apply

И войти в систему так:

var logger = LogManager.GetCurrentClassLogger();

logger.Info("I go to AppLogs.txt");

logger.WithProperty("ProcessId", message.ProcessId).Info("I go to processid logs");

Вы также можете использовать одну цель и использовать «if else» ($ {when}), это немного сложнее в настройке.

Устранение неполадок

Если у вас возникли проблемы с этим, проверьте Как просмотреть диагностику и ошибки NLog

...