AWS CloudWatch logging working from one machine, not another - c#

I have 2 EC2 Windows 10 instances. Using C# and AWSSDK.CloudWatchLogs, I'm able to write to AWS CloudWatch from one of them, but not the other. I can duplicate this with the code below:
C# code:
using System;
namespace AllPurposeDuck
{
class Program
{
private static Logger _log = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
try
{
_log.Info("Quack!");
_log.Debug("Quack!!");
_log.Trace("Quack!!!");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>
<nlog throwExceptions="true"
internalLogFile="c:\temp\allpurposeducklog.txt"
internalLogLevel="Info"
xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="console" xsi:type="Console" layout="${longdate} | ${level} | ${machinename}| ${message}" />
<target name="aws" xsi:type="AWSTarget" logGroup="Ducks_and_stuff" region="us-west-2" layout="${machinename} ${longdate} | ${level} | ${message}" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="console, aws" />
</rules>
</nlog>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
On the machine that otherwise silently fails, I notice a short pause and see the following warning in my c:\temp\allpurposeducklog.txt local log file:
2021-03-20 01:36:40.7679 Info Shutting down logging...
2021-03-20 01:36:42.2809 Warn Target flush timeout. One or more targets did not complete flush operation, skipping target close.
2021-03-20 01:36:42.2809 Info Logger has been shut down.
The other machine quacks happily to CloudWatch (both quack to the console).
The failing machine is in the same VPC, with the same IAM role, availability zone, and security groups as the working machine. Both machines are working properly with CloudWatch Agent, which monitoring Windows memory and triggering alerts when it gets too low.
I'm having a hard time narrowing it down any further than that. Ideas? Is there somewhere in AWS where the reason for the failure might be getting recorded? Thanks.

Because the program exits soon after the logging, NLog could still be busy with writing the logs. If the target use asynchronous logging, NLog needs to know it should wait on writing.
It's always recommend to give some time just before the program exit. Add at the end of Main:
LogManager.Shutdown();
This will give NLog 15 seconds at max.
If that isn't enough time, you could flush first and wait for example max 30 sec.
LogManager.Flush(TimeSpan.FromSeconds(30));
LogManager.Shutdown();
See also https://github.com/NLog/NLog/wiki/Logging-troubleshooting

Related

NLog logger doesn't log to the configured logfile in release build

I have the configuration file set up
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog autoReload="true">
<targets>
<target name="file" type="File" fileName="${basedir}/log/${shortdate}.log" layout="${date:format=HH\:mm\:ss.fff}|${message}"/>
<target name="file_webs" type="File" fileName="${basedir}/log/${shortdate}_webs.log" layout="${date:format=HH\:mm\:ss.fff}|${message}"/>
</targets>
<rules>
<logger name="WebSocket.*" minlevel="Debug" writeTo="file_webs" final="true"/>
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>
</configuration>
The logger is loaded in each class like this:
private static Logger logger = LogManager.GetCurrentClassLogger();
The logging is directed to the correct file as long as I don't run the build version. Then all logging is done in the default log file.
What could be the cause?
Check the following:
Is the correct config file placed in the output directory of the release. Maybe there is a different version of your config file there or it is missing.
Are there other things running after your build? Like a tool to obfuscate the source code? If so, this might mess up the class name in your build, the config the can not redirect to the right output. In that case, explicitly load the logger for your class this way:
private static Logger logger = LogManager.GetLogger("WebSocket.*");

how to use etw nlog for writing log to custom eventsource

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.

Log only to a specific target at runtime

I am using NLog with two targets:
<?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">
<target name="logfile" xsi:type="File" fileName="my.log"/>
<target name="console" xsi:type="Console"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile"/>
<logger name="*" minlevel="Info" writeTo="console"/>
</rules>
</nlog>
Is it possible to log a message only to the "logfile" target, without having the message written to the "console" target as well?
EDIT
To clarify: I want to direct messages from the same class to different loggers at run time (w/o having to change the XML). Something like:
class Program
{
static Logger _logger = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
// Note - _logger.InfoToTarget() does not really exist
_logger.InfoToTarget("logfile", "This is my very detailed message, possibly with object dumps");
_logger.InfoToTarget("console", "Short message");
}
}
I'm aware that this couples my code with the NLlog.config file.
One way to accomplish the functionality you are looking for is to name your logger
_logger = LogManager.GetLogger("MyConsoleLogger")
_logger.Info("This will log to the console...");
_logger = LogManager.GetLogger("MyFileLogger")
_logger.Trace("This will log to a file...");
rather than using
LogManager.GetCurrentClassLogger().
In your config file you could then list in the rules
<rules>
<logger name="MyFileLogger" minlevel="Trace" writeTo="logfile"/>
<logger name="MyConsoleLogger" minlevel="Info" writeTo="console"/>
</rules>
This is by far not the most pretty solution to look at, but it does give you the functionality that you are looking for.
There are a few ways to do this, and the correct method depends on your situation.
Keep in mind that you typically want to avoid having your app know too much about the inner-workings of logging. If possible, it's best to configure nlog to decide where things should get logged.
Is there a specific namespace that should not be logged to console? That's easy to configure. Also, you can use the "When" filter (https://github.com/nlog/nlog/wiki/When-filter) or conditions (https://github.com/nlog/nlog/wiki/Conditions)
It may also be best to have multiple logger instances, so you can call the one that is appropriate for each situation (logger per class) (Why do loggers recommend using a logger per class?).
Absolutely, however I am assuming you mean at release you no longer wish to log to the console. You can do this very easily by removing or commenting out the listener that writes to the console target. Now it will only write to the logfile target.
<?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">
<target name="logfile" xsi:type="File" fileName="my.log"/>
<target name="console" xsi:type="Console"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile"/>
<!--<logger name="*" minlevel="Info" writeTo="console"/>-->
</rules>
</nlog>
The rule that writes to the console is now deactivated, but the log file is active. If this is during release you probably want to change your rule to not process your trace logging as the min level for the log file since it will slow down your app with excessive IO. I have asked this question in the past and it appears that best practice is to do this via the XML configuration files. (Logging in Release Build of Application (C#))

Why does NLog miss some messages when logging a large number of messages?

I try to test NLog performance (latest version) with settings:
<?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">
<variable name="basePath" value="c:\logs\" />
<variable name="msgFormat" value="${message}" />
<targets async="true">
<target name="file"
xsi:type="File"
fileName="${basePath}/${logger}/${date:format=yyyy}/${date:format=MMMM}/log-${date:format=yyMMdd}-${level}.log"
layout="${msgFormat}"
concurrentWrites="true" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file"/>
</rules>
</nlog>
and run this code:
var msg = "this is example string for logging test. it's not very long, but not very short";
var count = 20000;
Parallel.For(0, count, x => nlog.Info(msg));
NLog writes to file, but when file size reaches 1MB it stops writing. I try to use simple for loop, but it doesn't helped me.
And i try to use internal logging, but there is no errors, by the way i see there this strings:
2013-04-01 11:36:18.2458 Trace Opening
c:\logs/NLogTest/2013/April/log-130401-Info.log with
concurrentWrite=False
It's very strange, because concurrentWrites default value is true, furthermore I've set this value in config.
The problem lies in the default value of the AsyncWrappers QueueLimit, which is 10000.
The value determines how big the queue of messages to write are allowed to be, the problem arises because all 20000 messages are queued before anything is written to the file, which causes NLog to discard the last 10000 messages.
Unfortunately this cannot be changed when using the async attribute, you have to define the AsyncWrapper manually to be able to control the QueueLimit, which is done like 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">
<variable name="basePath" value="c:\logs\" />
<variable name="msgFormat" value="${message}" />
<targets async>
<target name="asyncWrapper" xsi:Type="AsyncWrapper" queueLimit="20000">
<target name="file"
xsi:type="File"
fileName="${basePath}/${logger}/${date:format=yyyy}/${date:format=MMMM}/log-${date:format=yyMMdd}-${level}.log"
layout="${msgFormat}"
concurrentWrites="true" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file"/>
</rules>
</nlog>
Where QueueLimit is set to 20000.
You could also changed the OverflowAction if you need to do something other the discard messages not put in the queue, see AsyncWrapper documentation for more information. The options are Block, Discard or Grow.

NLog Refuse to Throw Exception

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

Categories

Resources