Can I somehow set up an event handler for fatal errors in the code? I would like to terminate the application immediately if such an error happens, i.e. something like this:
void Fail(string format, params object[] args) {
Logger.Fatal(format, args);
Environment.Exit(-1);
}
However I would like this to happen automatically:
Logger.Fatal(...); // logs the error and invokes Environment.Exit(-1);
Is there a way to setup some kind of callback for all fatal errors or some configuration option for this?
Yes,
you can do this using MethodCall target (see https://github.com/nlog/NLog/wiki/MethodCall-target)
Here example:
namespace SomeNamespace
{
using System;
public class MyClass
{
public static void HandleFatalEventLog(string level)
{
if(level.Equal("Fatal", StringComparison.OrdinalIgnoreCase))
{
Environment.Exit(-1);
}
}
}
}
And NLog.config file:
<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="m" xsi:type="MethodCall" className="SomeNamespace.MyClass, MyAssembly" methodName="HandleFatalEventLog">
<parameter layout="${level}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Fatal" writeTo="m" />
</rules>
</nlog>
PS: But, I would not recommend this approach, logger should not shutdown application
Related
I have used NLog to log the entry and exits of functions in my code. But with different runs of the same Application I am getting different logs. It is a multi threaded application. And I am using async to log the information.
The following is my configuration:
<?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>
<target name="asynclogger" xsi:type="AsyncWrapper" overflowAction="Grow" queueLimit="100000" batchSize="5000" timeToSleepBetweenBatches="1">
<target name="logfile" xsi:type="File" fileName="D:\IALogs\${processname}_${processid}_${threadid}.ialog" layout ="${longdate} ${processname} ${processid} ${threadid} ${mdlc:item=threadid} ${level} ${message}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="asynclogger" />
</rules>
</nlog>
The following is the logger code.
class Program
{
private static readonly NLog.Logger nLogger = NLog.LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
Thread th1 = new Thread(() => print(5000000));
th1.Start();
Thread th2 = new Thread(() => print(5000000));
th2.Start();
th1.Join();
th2.Join();
print(10000);
Console.WriteLine("Done!!!!");
Console.ReadLine();
}
private static void print(int noOfItems)
{
for (int i = 1; i <= noOfItems; i++)
{
nLogger.Info("Printing i =" + i);
}
}
}
With Console.Readline() the logs are completely written,
if there is no Console.Readline() the logs are different each time and also
the third Print method call from the main thread doesn't log anything if there is no Console.Readline(). If Console.Readline() is present then the 3rd print statement logs all the information
I guess your sentence "I am getting different logs" should be translated to "I am missing some logs".
When enabling async-operations for NLog targets, then it is important to flush, because writing happens on background threads. Must wait for these, before exiting the application:
NLog.LogManager.Flush()
See also: NLog Tutorial - Remember to flush
I just finished struggling with a generic error in AspNetCore3.1. The error simply reads this:
2019-12-11 21:52:46.6862 Microsoft.AspNetCore.Server.Kestrel
Connection id "0HLRUMQV9RNJI", Request id "0HLRUMQV9RNJI:00000001": An
unhandled exception was thrown by the application.
After much pain, I found that it was because I missing a registration of a service:
public void ConfigureServices(IServiceCollection services)
{
// This service was missing
services.AddTransient<IThingService, ThingService>();
services.AddControllers();
}
So, now, I'm on a quest to find out why I didn't get any details on what the problem was. I created a new Core 3.1 app from the Visual Studio templates. I installed NLog.Web.AspNetCore and added an nlog.config file.
<?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="true"
internalLogLevel="Off" internalLogFile="c:\temp\logs\nlog-internal.log">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets async="true">
<target xsi:type="ColoredConsole" name="c" layout="${longdate} ${logger} ${message}" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="c" />
</rules>
</nlog>
AppSettings:
{
// I removed the logging section completely so that NLOG can control log levels
"AllowedHosts": "*"
}
I also added the following code to program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseIISIntegration()
.ConfigureLogging((hostingContext, loggingBuilder) =>
{
loggingBuilder.ClearProviders();
loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseStartup<Startup>()
.UseNLog();
});
}
So then, I removed the registration of IThingService, and I started getting the same generic, useless error:
"2019-12-11 21:52:46.6862 Microsoft.AspNetCore.Server.Kestrel
Connection id "0HLRUMQV9RNJI", Request id "0HLRUMQV9RNJI:00000001": An
unhandled exception was thrown by the application."
After some tinkering, I found that I commented out the line in program.cs, "loggingBuilder.ClearProviders();" I started getting actual useful error messages:
System.InvalidOperationException: Unable to resolve service for type
'WebApplication3.Controllers.IThingService' while attempting to
activate 'WebApplication3.Controllers.WeatherForecastController'.
But, it's not NLog doing the logging, it's the default Core 3 logging.
Setup instructions for NLog can be found here: https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3
So, now for the question, why does ClearProviders() make nlog work, but lose the details in my error messages? It seems to only be logs that would take place down in the pipeline, not at the controller/domain level.
I think the special detail you are looking for is ${exception:format=tostring}. Your current layout is this:
<target xsi:type="ColoredConsole" name="c" layout="${longdate} ${logger} ${message}" />
Try changing into this:
<target xsi:type="ColoredConsole" name="c" layout="${longdate} ${logger} ${message}${exception:format=tostring}" />
You might also consider including ${level} in Layout (Unless coloring is enough).
For my console application , I want to write all the logs to custom event source under Application and Services Logs under separate section MyEventSourceName.
I tried to use NLog.Etw, but seems nothing appears. How to do this?
<?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"
autoReload="true"
throwExceptions="false">
<extensions>
<add assembly="NLog.Etw" />
</extensions>
<targets async="true">
<target xsi:type="EtwEventSource"
name="eetw"
providerName="MyEventSourceName"
taskName="${level}"
layout="${message}">
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="eetw" />
</rules>
class Program
{
private static Logger logger = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
logger.Info("New person created with name {0}");
}
}
You could use the eventlog target:
For example:
<target xsi:type="EventLog"
name="eventlog"
source="MyEventSourceName"
log="MyEventSourceLogName"
layout ="${message}${newline}${exception:format=ToString}"/>
See docs
The target supports .NET3.5+ and .NET Standard 2.0. For NetStandard 2.0 use the NLog.WindowsEventLog package.
I am using Nlog 2.1 and trying to write errors into Windows Event logger with different eventId. To better distinguish different errors.
If I specify eventId property it's working, but if don't I am not seeing any record in Windows Event Logger.
NLog.config file:
<?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>
<target name="console" xsi:type="ColoredConsole"
layout="${date:format=HH\:mm\:ss}|${level:uppercase=true}|${message}" />
<target xsi:type="EventLog"
name="eventlog"
layout="{${newline}
"Logger": "${logger}",${newline}
"StackTrace": "${stacktrace}",${newline}
"Message": "${message}",${newline}
"Exception": "${exception:format=ToString,Data}"${newline}}"
machineName="."
source="CareFusion Analytics Agent Service"
eventId="${event-properties:EventID}"
log="Application" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="console" />
<logger name="*" minlevel="Error" writeTo="eventlog" />
</rules>
</nlog>
Usage:
private static void Main(string[] args)
{
Logger logger = LogManager.GetCurrentClassLogger();
logger.Error("Sample error message"); //This is not working
LogEventInfo logEvent = new LogEventInfo()
{
Level = LogLevel.Error,
Message = "Hello",
LoggerName = logger.Name
};
logEvent.Properties.Add("EventID", 400);
logger.Log(logEvent); //This is working
Console.WriteLine("Press any key....");
Console.ReadKey();
}
The call logger.Error("Sample error message"); goes wrong as the EventLogTarget tries to convert the ${event-properties:EventID} to a integer.
Because layout renders in NLog never return null (but string.Empty), this will give a exception - which will be caught by NLog. In the NLog's internal log you should see a FormatException.
So we need to specify a default value, you could do that with the whenEmpty:
<target xsi:type="EventLog"
...
eventId="${event-properties:EventID:whenEmpty=0}" />
PS: tested it with NLog 4.3.11
Hello dear developers,
I encountered a weird problem with NLog,
I had a crash, but couldn't find a trace for the user activity in the logs.
i assume, Logging is not working...
tried searching for permissions problems and such, but all seems to be O.K.
I want to debug my logging in-case of problems so i created the following
code to tell the user if it failed to create anything:
public static class Log
{
static Log()
{
try
{
AppLogger = LogManager.GetLogger("Megatec.EngineeringMatrix.AppLogger");
ChangeLogger = LogManager.GetLogger("Megatec.EngineeringMatrix.ChangeLogger");
DRCLogger = LogManager.GetLogger("Megatec.EngineeringMatrix.DRCLogger");
if((AppLogger == null) || (ChangeLogger == null) || (DRCLogger == null))
throw new NLogConfigurationException("Configuration does not specify correct loggers");
writeStartupLogEntry();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), #"Failed to load `Megatec.EngineeringMatrix` Loggers.");
throw;
}
}
public static readonly Logger AppLogger;
public static readonly Logger ChangeLogger;
public static readonly Logger DRCLogger;
with the following configuration file:
<?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" throwExceptions="true">
<targets>
<target xsi:type="File" name="AppLogFile" createDirs="true" fileName="c:/log?s/${processname}/${logger}_${shortdate}.log"
layout=">> ${time} ${uppercase:${level}} ${callsite} ${message} ${exception:format=tostring}" />
<target xsi:type="File" name="ChangeLogFile" createDirs="true" fileName="c:/log?s/${processname}/${logger}_${shortdate}.log"
layout=">> ${date} ${message} ${exception:format=tostring}" />
<target xsi:type="File" name="DRCLogFile" createDirs="true" fileName="c:/logs/${processname}/${logger}_${shortdate}.log"
layout=">> ${date} ${message} ${exception:format=tostring}" />
</targets>
<rules>
<logger name="Megatec.EngineeringMatrix.AppLogger" minlevel="Trace" writeTo="AppLogFile" />
<logger name="Megatec.EngineeringMatrix.ChangeLogger" minlevel="Trace" writeTo="ChangeLogFile" />
<logger name="Megatec.EngineeringMatrix.DRCLogger" minlevel="Trace" writeTo="DRCLogFile" />
</rules>
</nlog>
OBVIOUSLY I written a BAAD config because a directory c:\lo?gs cannot be created.
but still, i don't get the message
MessageBox.Show(ex.ToString(), #"Failed to load 'Megatec.EngineeringMatrix'
and even AppLogger.Info() skips the exception...
nothing i written to log, but the App don't know it...
In debug, i can catch the exception, and see it is handled by NLog,
How can I catch it from my code?
This is an old issue, but there are some recent changes on this.
Some exceptions were 'eaten' by NLog in the past. For example in the AsyncWrapper (or using the attribute async on <target>)
This has been fixed in NLog 4.3:
Consistent handling of exceptions (BEHAVIOUR CHANGE)
The logging and throwing of exceptions was previously inconsistent. Not all of it was logged to the internal logger and some times they got lost. For example, the async wrapper (or async attribute) was catching all exceptions without a proper rethrow.
This is bad as it is sometimes unclear why NLog isn’t working (got it myself multiple times). This has been fixed in NLog 4.3!
All exceptions are logged to the internal logger
The “throwExceptions” option will be respected in all cases
Advise: disable throwExceptions in production environments! (this the default)
see http://nlog-project.org/2016/04/16/nlog-4-3-has-been-released.html