NLog create log files based on static variable - c#

How can I set NLog file name based on static variable in my application.
I have windows service that performs different tasks. Reads configuration file with task details.
I would like to create log file based on given task name.
NOTE: class name will not work, since all the tasks call the same code.
NOTE: I am already using ${logger} variable as my current class. Since I need to know where I am as well.
-------------UPDATE--------------
Seems like this is not possible to do.
Modified question: How to set variable values at run time?
I am talking about this:
<variable name="logFileName" value="" />
Thank you.

You cannot, I believe. But you can use something like this:
In code:
static NLog.Logger loggerA = NLog.LogManager.GetLogger("nameA");
static NLog.Logger loggerB = NLog.LogManager.GetLogger("nameB");
void Something()
{
loggerA.Error("Something");
}
void SomethingElse()
{
loggerB.Error("SomethingElse");
}
NLog config:
<nlog ...>
<targets>
<target name="Error" xsi:type="AsyncWrapper">
<target name="file" xsi:type="File" fileName="${basedir}/Logs/Error.txt">
<layout ... />
</target>
</target>
</targets>
<!--other targets pointing to different files.-->
<rules>
<logger name="nameA" minlevel="Warn" writeTo="Error" />
<logger name="nameB" minlevel="Trace" maxLevel="Info" writeTo="Log" />-->
<logger name="*" minlevel="Trace" maxLevel="Info" writeTo="CommonLog" />
</rules>
</nlog>
You can also use SomeNamespace.Component.* as name of a logger and than only logs from SomeNamespace.Component will be logged via it. In that case the logger would be obtained like this:
static NLog.Logger loggerA = NLog.LogManager.GetCurrentClassLogger();
Here is the documentation for Nlog: https://github.com/NLog/NLog/wiki/Tutorial
There is a way to edit NLog configuration programmatically: https://github.com/nlog/NLog/wiki/Configuration-API

The easy solution is to use NLog GlobalDiagnosticsContext:
<target name="file" xsi:type="File" fileName="${gdc:logFileName:whenEmpty=DefaultApp}.txt">
Then you can override it like this:
NLog.GlobalDiagnosticsContext.Set("logFileName", "HelloApp");
See also: https://github.com/nlog/nlog/wiki/Gdc-Layout-Renderer

Related

Nlog logs location overwritten by code still logging happening at config location

NLog version - 4.4.3
Platform - .Net 4.5.2
Current NLog config -
<nlog autoReload="true" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variable name="layout" value="${longdate}|${level:uppercase=true}|${threadid}|${logger}|${message}" />
<variable name="logLocation" value="logs" />
<targets async="true">
<target name="debugger" xsi:type="Debugger" layout="${layout}" />
<target name="console" xsi:type="Console" layout="${layout}" />
<target name="logfile"
xsi:type="File"
fileName="${logLocation}\${processname}.log"
archiveFileName="${logLocation}\\${processname}.{###}.log"
archiveEvery="Day"
archiveAboveSize="2048000"
archiveNumbering="Rolling"
maxArchiveFiles="10"
concurrentWrites="false"
keepFileOpen="false"
layout="${layout}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logfile" />
<logger name="*" minlevel="Debug" writeTo="debugger" />
<logger name="*" minlevel="Info" writeTo="console" />
</rules>
</nlog>
Code to override location
LogManager.ReconfigExistingLoggers();
var target = (FileTarget)LogManager.Configuration.FindTargetByName<AsyncTargetWrapper>("logfile").WrappedTarget;
target.FileName = $#"..\..\..\..\logs\Foobar.log";
What is the current result?
When application/service starts it writes to overwritten location, but sometimes (not sure of scenario - maybe rollover) it start writing to config location.
What is the expected result?
Logs should always be written to overwritten location.
Did you checked the Internal log?
No
Please post full exception details (message, stacktrace, inner exceptions)
No Exception
Are there any workarounds? yes/no
Restart service/application.
Is there a version in which it did work?
No idea. This is the version we started with and sticking to.
Can you help us by writing an unit test?
Unit tests won't help as it is an intermittent scenario.
You have auto reload (<nlog autoReload="true”) enabled, so if it needs to reload (after sleep or change in config), you will lose the changes made in code.
The solution it so disable autoreload, or set the change after reload again. See code example:
static void Main(string[] args)
{
UpdateNLogConfig();
LogManager.ConfigurationReloaded += LogManager_ConfigurationReloaded;
log.Info("Entering Application.");
Console.WriteLine("Press any key to exit ...");
Console.Read();
}
private static void LogManager_ConfigurationReloaded(object sender, LoggingConfigurationReloadedEventArgs e)
{
UpdateNLogConfig();
}
private static void UpdateNLogConfig()
{
//note: don't set LogManager.Configuration because that will overwrite the nlog.config settings
var target = (FileTarget)LogManager.Configuration.FindTargetByName<AsyncTargetWrapper>("logfile").WrappedTarget;
target.FileName = $#"..\..\..\..\logs\Foobar.log";
LogManager.ReconfigExistingLoggers();
}
See also Combine XML config with C# config · NLog/NLog Wiki
Instead of doing target lookup, and modifying target properties directly. Then I suggest making use of the NLog Layout Logic.
<nlog autoReload="true" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets async="true">
<target name="logfile"
xsi:type="File"
fileName="${gdc:item=logFile:whenEmpty=log/${processname}.log}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logfile" />
</rules>
</nlog>
And then just assign the logLocation:
NLog.GlobalDiagnosticsContext.Set("logFile", $#"..\..\..\..\logs\Foobar.log");
Using GDC will also works very well with autoReload=true and no need to call LogManager.ReconfigExistingLoggers().

Generic Logging and Specific Logging (using NLOG), Duplication of Logging

I am trying to create 2 loggers (using NLog)
First logger logs all the desired item to log in the solution
The other one traces specific items (I do it to keep things clean and focused, and only run trace here)
Below is the configuration
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="logfile"
xsi:type="File"
layout="${longdate} ${level} ${threadid} ${callsite} ${message}"
fileName="${basedir}\Logs\GatewayApplicationDebugAndErrorLog.txt"
archiveNumbering="Rolling"
maxArchiveFiles="10"
archiveAboveSize="10000000"/>
<target name="J1939Trace"
xsi:type="File"
layout="${longdate} ${level} ${threadid} ${callsite} ${message}"
fileName="${basedir}\Logs\J1939Trace.txt"
archiveNumbering="Rolling"
maxArchiveFiles="10"
archiveAboveSize="10000000"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile" />
<logger name="J1939Trace" maxlevel="Trace" writeTo="J1939Trace" final="true" />
</rules>
and usage is shown below
private readonly Logger logger = LogManager.GetCurrentClassLogger(); // Generic Logger
private readonly Logger j1939Logger = LogManager.GetLogger("J1939Trace"); // Specific Logger.
What I observe is that the specific logger item is also logged in generic log item and I don't want that duplication. Any ideas what am I doing wrong?
Will this work?
From: NLog: How to exclude specific loggers from a specific rule?
Adding final="true" means that no more rules will be executed for the events produced by "SpammyLogger", but it applies only to the specified levels.(see https://github.com/nlog/nlog/wiki/Configuration-file#rules)
Make sure to read through all the comments in the answer.

NLog: disable/enable multiple log files

I have 2 loggers: one for Info messages, and another for other ones.
<logger name="ErrLogger" levels="Trace,Debug,Warn,Fatal,Error" writeTo="logfile_w" />
<logger name="InfoLogger" level="Info" writeTo="logfile_i" />
Each one write information to his own file.
Is it possible in runtime turn off and on certain loggers?
Btw, for each class I'm using code like this:
private static Logger _logger = LogManager.GetCurrentClassLogger();
And then in functions I use _logger.Info("message");. Should I modify class loggers too?
You can use filtering for that.
Example
<rules>
<logger name="*" writeTo="file">
<filters>
<when condition="${logger}==loggername" action="Ignore" />
</filters>
</logger>
</rules>
See filtering on NLog wiki and the ${logger} layout renderer.
Hint: not sure what the (full) name of the logger is? Just log something with ${logger} and check the logs.

Ignoring NLog Configuration referenced in other assembly

I have a unique problem with the NLog. I have a third-party assembly we use into our project. They have used the NLog into their project and referenced NLog configuration into their configuration which I don't have access to.
I initially had a problem even adding the NLog to a project since both version of dlls were different. I had to download the source code of NLog and change the assembly name since alias was not working for me (OR I didn't know how to use it.)
After giving my own assembly name, NLog started wotrking but.. It started logging third-party log information too with it. Looks like they were not careful enough when defining the logger and they just defined (*). Now my question is, how do I avoid their stuff from logging in to my file? I have also tried setting it to final = true.
Here is how my very simple configuration file looks like.
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<!-- add your targets here -->
<!--
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
<target name="errorLog" xsi:type="File"
fileName="${basedir}/logs/error/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}${onexception:${newline}EXCEPTION\: ${exception:format=ToString}}"
/>
<target name="generalLog" xsi:type="File"
fileName="C:/logs/${date:format=yyyy-MM-dd}.log"
layout="${longdate} ${uppercase:${level}} ${message}"/>
</targets>
<rules>
<!-- add your logging rules here -->
<logger name="Errors" writeTo="errorLog" minlevel="Warn"/>
<logger name="EBusiness.Model.*" writeTo="generalLog" levels="Trace,Debug,Info" final="true"/>
<!--
<logger name="*" minlevel="Trace" writeTo="f" />
-->
</rules>
</nlog>
If they are writing to the root logger, you should configure the root logger to not log to anywhere you care (maybe point it at a console logger) and your application can log to a specific logger which does write to your files.
Ugly, but should work.
For example:
Add this target:
<target name="console" xsi:type="Console" />
And Change the * rule to be:
<logger name="*" minlevel="Fatal " writeTo="console" />
Then, Add your own logger rule, say something like:
<logger name="MyNameSpace.*" minlevel="Trace" writeTo="logfile" final="true" />
Assuming you have a logfile target defined pointing at your file.

Do not allow users to delete log files

I have a simple app:
public class Program
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
while (true)
{
Logger.Info(DateTime.Now.ToString());
Thread.Sleep(5000);
}
}
}
And configuration:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="logfile" xsi:type="File" fileName="C:\Logs\log.txt" keepFileOpen="true" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile" />
</rules>
</nlog>
But NLog does not seem to lock log.txt (desipte keepFileOpen property being set to true) - I can delete it. Even worse - the log file is not recreated after it has been deleted. So if user accidentally deletes the file - there will be no logging until the application is restarted (or in more general case until new log file name takes place).
Is there any way to make NLog lock log files or at least recreate them after they have been deleted?
Use enableFileDelete setting to make NLog lock file:
<target name="logfile" xsi:type="File"
fileName="C:\Logs\log.txt"
keepFileOpen="true"
enableFileDelete="false" />

Categories