0

I have referred this Update NLog target filename at runtime and many other links but none seems to be working in my case. I initialize logger using

private Logger logger = LogManager.GetCurrentClassLogger();

All the log messages are queued, then emptied using a timer.

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();

I am try to reset the filename of my target using the following code:

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();

But sometimes, log message aren't written to appropriate file.

Julian
  • 33,915
  • 22
  • 119
  • 174
Saurav
  • 592
  • 4
  • 21

1 Answers1

0

The issue (probably)

I see message.ProcessId in you config. It looks like you're changing the config every log event. That isn't thread safe! See How Thread-Safe is NLog? .

How to fix

The good news, there is also no need to change the config. You could use context classes for injecting values in the config. For global there is the GDC, but there is also a context for thread and message level. (and others here).

Example how to fix

You could setup the config like this:

// 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

And log like this:

var logger = LogManager.GetCurrentClassLogger();

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

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

You could also use one target and use a "if else" (${when}), it's a bit more complicated to setup.

Troubleshooting

If you have troubles with this, please check How to see NLog diagnostics and errors

Julian
  • 33,915
  • 22
  • 119
  • 174