How to use a fallback when it cannot send data to CloudWatch #283
-
In cases where sending to CloudWatch fails under any circumstances, write to a log file instead. Thank a lot. public class CloudWatchLogger
{
public CloudWatchLogger(CloudWatchLoggerReq req)
{
// Setup the NLog configuration
var config = new LoggingConfiguration();
// Add console target
config.AddRule(LogLevel.Trace, LogLevel.Fatal, new ConsoleTarget());
var awsTarget = new AWSTarget()
{
LogGroup = req.LogGroupName,
// (Optional) How often batches of log messages should be pushed to AWS CloudWatch
BatchPushInterval = TimeSpan.FromSeconds(3),
FlushTimeout = TimeSpan.FromSeconds(req.TimeoutSec),
// (Optional) Whether NLog should try create the log group if it does not exist or not
DisableLogGroupCreation = true,
// (Optional) The maximum number of log events that are kept in memory before being pushed to
// AWS CloudWatch
MaxQueuedMessages = 10000,
// (Optional) A string to prefix log stream names with
LogStreamNamePrefix = "Prefix",
// (Optional) A string to suffix log stream names with
LogStreamNameSuffix = "Suffix",
// (Optional) AWS credentials that should be used to log into AWS and access AWS CloudWatch
Credentials = new BasicAWSCredentials(req.Accesskey, req.SecretAccessKey),
// CloudWatch logs should be logged in. In this case it defaults to the AWS Profile's region
Region = req.Region,
// (Optional) Custom layout that should be used when formatting log messages
Layout = new SimpleLayout("${message}"),
LogStreamName = "${date:format=yyyyMMdd}",
// (Optional) Log System Error
//LibraryLogFileName = $"{req.PathFileLog}/Logs/aws-logger-erros.txt",
};
// Add AWS target and fallback file target
config.AddRule(LogLevel.Trace, LogLevel.Fatal, awsTarget);
// Add file target for fallback
var fileTarget = new FileTarget("file")
{
FileName = $"{req.PathFileLog}/Logs/Log_${{date:format=yyyyMMdd}}.txt", // Path สำหรับบันทึกไฟล์ log
Layout = new SimpleLayout("[${date}] ${message} ${exception}")
};
config.AddRule(LogLevel.Error, LogLevel.Fatal, fileTarget);
LogManager.Configuration = config;
}
//create logMessage
public static void LogMessageAsync(SendMessageCloudWatch req)
{
var log = LogManager.GetCurrentClassLogger();
string msg = string.Empty;
try
{
msg = req.msg;
log.Trace(msg);
}
catch (Exception ex)
{
//Failed to send log to AWS CloudWatch
string guid = System.Guid.NewGuid().ToString();
log.Error($"Req - {guid}: {msg}");
log.Error($"Res - {guid}: {ex}");
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
@thewinner55 Thanks for starting discussion. I see some problem in your code. You are defining static method Also note that in NLog.AWS.Logger.AWSTarget class, it:
I was able to use your code (corrected and modified for reproduction): using Amazon.Runtime;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NLog.AWS.Logger;
namespace NLogTestNet8
{
public class CloudWatchLogger
{
static CloudWatchLogger()
{
// Setup the NLog configuration
var config = new LoggingConfiguration();
// Add console target
config.AddRule(LogLevel.Trace, LogLevel.Fatal, new ConsoleTarget());
DateTime date = DateTime.Now;
var awsTarget = new AWSTarget()
{
LogGroup = "TestCloudWatchLoggerLogGroup",
// (Optional) How often batches of log messages should be pushed to AWS CloudWatch
BatchPushInterval = TimeSpan.FromSeconds(3),
FlushTimeout = TimeSpan.FromSeconds(10),
// (Optional) Whether NLog should try create the log group if it does not exist or not
DisableLogGroupCreation = true,
// (Optional) The maximum number of log events that are kept in memory before being pushed to
// AWS CloudWatch
MaxQueuedMessages = 10000,
// (Optional) A string to prefix log stream names with
LogStreamNamePrefix = "Prefix",
// (Optional) A string to suffix log stream names with
LogStreamNameSuffix = "Suffix",
// (Optional) Custom layout that should be used when formatting log messages
Layout = new SimpleLayout("${message}"),
LogStreamName = $"{date:format=yyyyMMdd}",
// (Optional) Log System Error
//LibraryLogFileName = $"{req.PathFileLog}/Logs/aws-logger-errors.txt",
};
// Add AWS target and fallback file target
config.AddRule(LogLevel.Trace, LogLevel.Fatal, awsTarget);
// Add file target for fallback
var fileTarget = new FileTarget("file")
{
FileName = $"{Path.GetTempPath()}/Logs/Log_{date:format=yyyyMMdd}.txt",
Layout = new SimpleLayout("[${date}] ${message} ${exception}")
};
config.AddRule(LogLevel.Error, LogLevel.Fatal, fileTarget);
InternalLogger.LogFile = $"{Path.GetTempPath()}/NLogInternalLogger.log";
LogManager.Configuration = config;
}
//create logMessage
public static void LogMessage(string message)
{
var log = LogManager.GetCurrentClassLogger();
string msg = string.Empty;
try
{
msg = message;
log.Trace(msg);
}
catch (Exception ex)
{
//Failed to send log to AWS CloudWatch
string guid = System.Guid.NewGuid().ToString();
log.Error($"Req - {guid}: {msg}");
log.Error($"Res - {guid}: {ex}");
}
}
}
} Program.cs namespace NLogTestNet8
{
internal class Program
{
static void Main(string[] args)
{
CloudWatchLogger.LogMessage("Test Message");
}
}
} Executing above code:
Such exceptions are not propagated to calling (user) code since the logging is being done as part of a event loop, with logs flushed at regular configured interval (imagine web application being crashed due to just logging error, which should essentially happen in background without affecting the application). |
Beta Was this translation helpful? Give feedback.
@thewinner55 Thanks for starting discussion. I see some problem in your code. You are defining static method
LogMessageAsync()
, but your constructor is not static, which means it only executes when you create an instance of your customCloudWatchLogger
class.Also note that in NLog.AWS.Logger.AWSTarget class, it:
LibraryLogErrors
(default valuetrue
) andLibraryLogFileName
(default valueaws-logger-errors.txt
)InternalLogger.Error()
.InternalLogger.LogFile
andInternalLogger…