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 customCloudWatchLoggerclass.Also note that in NLog.AWS.Logger.AWSTarget class, it:
LibraryLogErrors(default valuetrue) andLibraryLogFileName(default valueaws-logger-errors.txt)InternalLogger.Error().InternalLogger.LogFileandInternalLogger…