You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中AWS.Logger.NLog发送CloudWatch失败时的文件回退问题

AWS CloudWatch日志回退逻辑不触发问题排查与解决

需求

  • 向AWS CloudWatch发送日志失败时,自动将日志写入本地文件作为回退方案

问题

测试时输入错误配置值(比如无效密钥、不存在的区域),代码并未进入catch块,无法触发本地回退逻辑

使用依赖

AWS.Logger.NLog


相关代码

using Amazon.Runtime;
using NLog.AWS.Logger;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using NLog;
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", 
            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}");
        }
    }
}

问题原因

  1. 异步批量推送机制:AWS.Logger.NLog的AWSTarget是异步批量推送日志,调用log.Trace(msg)只是把日志加入内存队列,不会立即执行发送操作,因此不会抛出异常,自然进不了catch块。
  2. 回退规则不匹配:当前文件目标只捕获Error及以上级别日志,但CloudWatch推送失败的错误属于目标内部错误,不会自动将原始Trace级别日志升级为Error,所以触发不了文件目标规则。

解决方案

方案1:启用AWSTarget内置错误日志

直接利用AWSTarget自带的错误日志配置,将推送失败的详情写入指定文件:

var awsTarget = new AWSTarget()
{
    // 保留原有配置...
    // 开启库内部错误日志,记录CloudWatch推送失败信息
    LibraryLogFileName = $"{req.PathFileLog}/Logs/aws-logger-errors.txt",
    // 可选:设置错误日志级别,默认是Error
    LibraryLogLevel = LogLevel.Error
};

方案2:自定义错误事件处理

通过AWSTarget的Error事件捕获推送失败,手动将原始日志写入文件目标:

// 创建awsTarget后添加错误事件监听
awsTarget.Error += (sender, args) =>
{
    var fileLogger = LogManager.GetLogger("file"); // 对应文件目标的名称"file"
    // 将原始日志和错误信息一起写入本地文件
    fileLogger.Error($"CloudWatch推送失败: {args.Exception.Message}\n原始日志内容: {args.LogEvent.Message}");
};

方案3:使用NLog的Fallback规则(NLog 4.7+支持)

修改规则配置,让日志先尝试发送到CloudWatch,失败则自动转发到文件目标:

// 替换原有的AddRule代码,添加fallback逻辑
config.AddRule(LogLevel.Trace, LogLevel.Fatal, awsTarget, "*", true)
      .FallbackRules.Add(new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, fileTarget));

测试注意事项

  • 测试时可以将BatchPushInterval设为1秒,加快错误触发速度
  • 如果开启DisableLogGroupCreation = false,需确保IAM账号有创建日志组的权限,否则会触发创建失败错误
  • 异步推送的错误不会立即出现,需等待批量推送时间到后才会触发处理逻辑

内容的提问来源于stack exchange,提问作者shadowwave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:24:53