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" />
Related
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().
I coded this:
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
public MyClass()
{
Console.Write("lol");
Logger.Debug("Debug test...");
Logger.Error("Debug test...");
Logger.Fatal("Debug test...");
Logger.Info("Debug test...");
Logger.Trace("Debug test...");
Logger.Warn("Debug test...");
}
And nothing displays.. so I was told to go and add <targets> to the config file, thing is.. where is the config file? Nothing on google, the documentation, or anything like that helps me...
From NLog Wiki:
The following locations will be searched when executing a stand-alone *.exe application:
standard application configuration file (usually applicationname.exe.config)
applicationname.exe.nlog in application’s directory
NLog.config in application’s directory
NLog.dll.nlog in a directory where NLog.dll is located (only if NLog isn't installed in the GAC)
So, the easiest would be to add a NLog.config file in the application’s directory
Sample Nlog.config File for your reference:
<?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"
throwConfigExceptions="true">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
<target name="logconsole" xsi:type="Console" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logconsole" />
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>
</nlog>
See also: https://github.com/NLog/NLog/wiki/Tutorial
Alternatively you can define the config programmatically in C# as explained in the blog docs here:
https://github.com/NLog/NLog/wiki/Configure-from-code
I am trying to log exceptions in console application. I have done everything as always (and then it worked for me...):
NLog.config:
<?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"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<targets>
<target name="LogFile" xsi:type="File"
fileName="${basedir}/Log/${date:format=yyyyMMdd} myLog.txt"
layout="${longdate}|${level:uppercase=true}|${message}|${exception}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="LogFile" />
</rules>
</nlog>
class Program
{
private static Logger _log = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
_log.Error("test");
}
}
For some mysterious reason file is never created nowhere on my computer. Any ideas why
Your config looks valid, so that shouldn't be the issue.
Some things to check:
Is you nlog.config in the correct directory? The best way to test is to copy the nlog.config to the directory with your .dll or .exe.
Enable exceptions to be sure that errors are not captured by Nlog: throwExceptions="true"
Check the internal log by setting internalLogLevel="Info" and check "c:\temp\nlog-internal.log"
A full tutorial to troubleshoot could be found on the NLog documentation.
In Visual Studio, check if your NLog.config file has this properties:
Build Action: Content.
Copy to Output Directory = Copy if newer
I am attaching a screen shot where you can see how it should appear. Sorry, it is in Spanish.
Edit your NLog config, change your log file path like this,use ${shortdate} instead {date:format=yyyyMMdd}. Set name in rules and call it like in this sample.
<?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">
<targets async="true">
<targets>
<target name="LogFile" xsi:type="File"
fileName="${basedir}/Log/${shortdate}myLog.txt"
layout="${longdate}|${level:uppercase=true}|${message}|${exception}" />
</targets>
<rules>
<logger name="ErrorLog" minlevel="Trace" writeTo="LogFile" />
</rules>
</nlog>
And your .cs
class Program
{
private Logger ErrorLogger = NLog.LogManager.GetLogger("ErrorLog");
static void Main(string[] args)
{
ErrorLogger.Error("test");
}
}
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
Sometime nLog is not logging all debug information (some of log.Debug... are missing in debug file), does anyone know why is this happening and how to avoid that?
Here is my nLog configuration
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variable name="appTitle" value="Service"/>
<targets async="true">
<target name="fallbackDebug" xsi:type="FallbackGroup" returnToFirstOnSuccess="true">
<target xsi:type="File" fileName="C:\Logs\${date:format=yyyyMMdd}_Debug.txt" layout="..."/>
<target xsi:type="File" fileName="C:\Logs\${date:format=yyyyMMdd}_Debug_bu.txt" layout="..."/>
</target>
</targets>
<rules>
<logger name="*" levels="Trace,Debug,Error,Fatal" writeTo="fallbackDebug" />
</rules>
</nlog>
In code I'm using following
private static Logger log = LogManager.GetCurrentClassLogger();
...
log.Debug("Some debug info");
Thanks!
You must call LogManager.Flush() method at the end.
Example:
private static Logger log = LogManager.GetCurrentClassLogger();
...
log.Debug("Some debug info");
...
LogManager.Flush();