AWS Lambda 在 cloudwatch (.NET Core 3.1) 中写入额外的行

AWS Lambda writes extra line in cloudwatch (.NET Core 3.1)

我正在 .NET Core 3.1(C#) 中编写一个 lambda 函数,我想在我的逻辑中保留正在执行的操作的日志,当我在 cloudwatch 的 AWS Lambda 服务中部署我的 lambda 时,它会额外添加一个仅显示在输出中的行(也影响我的本地但不影响我的纯文本文件)我可能配置错误吗?

要创建项目,请使用 AWS Toolkit For Visual Studio 2019 中的模板“AWS Lambda Project (.NET Core - C#)”。

依赖关系:

NLog.Web.AspNetCore (4.14.0)
NLog (4.7.13)
Microsoft.Extensions.Configuration.Abstractions (6.0.0)
Amazon.Lambda.Serialization.SystemTextJson (2.2.0)
Amazon.Lambda.Core (2.1.0)

存储库:https://github.com/Weyne/AWS-NET_CORE-NLOG/

NLog.config

<?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="aws"
                xsi:type="AWSTarget"
                logGroup="aws/lambda/WeyneLoggingWithNLog"
                region="us-east-1"
                layout="
               -------------- ${level} (${longdate}) --------------${newline}
                ${newline}
                Call Site: ${callsite}${newline}
                Exception Type: ${exception:format=Type}${newline}
                Exception Message: ${exception:format=Message}${newline}
                Stack Trace: ${exception:format=StackTrace}${newline}
                Additional Info: ${message}${newline}" />
        <target xsi:type="File" name="fileTarget" filename="C:\Log${machinename}-${local-ip}-mylambda-${date:format=yyyy-MM-dd}.txt" layout="${longdate}|${level:uppercase=true}|${local-ip}|${callsite}|${message}|${exception:format=tostring}"></target>

        <target name="aws" type="AWSTarget" />
    </targets>
    <rules>
        <!--Skip Microsoft logs and so log only own logs-->
        <logger name="Microsoft.*" maxlevel="Info" final="true" />
        <logger name="*" minlevel="Trace" writeTo="fileTarget" />
        <logger minlevel="Error" name="*" writeTo="aws"/>
    </rules>

</nlog>

Function.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    
    using Amazon.Lambda.Core;
    using Microsoft.AspNetCore.Mvc.Infrastructure;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using NLog;
    using NLog.Web;
    using WeyneLoggingWithNLog.Interfaces;
    using WeyneLoggingWithNLog.Services;
    
    // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
    [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
    
    namespace WeyneLoggingWithNLog
    {
        public class Function
        {
    
            /// <summary>
            /// A simple function that takes a string and does a ToUpper
            /// </summary>
            /// <param name="input"></param>
            /// <param name="context"></param>
            /// <returns></returns>
            public string FunctionHandler(string input, ILambdaContext context)
            {
                var logger = NLogBuilder.ConfigureNLog("NLog.config").GetCurrentClassLogger();
                try
                {
    
                    var builder = new ConfigurationBuilder();
                    BuildConfig(builder);
    
                    var host = Host.CreateDefaultBuilder()
                        .ConfigureLogging((hostingContext, logging) =>
                        {
                            logging.ClearProviders(); //esta línea hace la diferencia
                            logging.AddConsole();//mal
                            logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); //esta línea hace la diferencia
                            logging.AddNLogWeb();
                        })
                        .ConfigureServices((context, services) =>
                        {
                            services.AddHttpContextAccessor();
                            services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
                            services.AddScoped<IProcessService, ProcessService>();
                            services.BuildServiceProvider();
                            services.AddLogging();
                        })
                        .UseNLog()
                        .Build();
    
                    var service = ActivatorUtilities.CreateInstance<ProcessService>(host.Services);
    
                    return service.Invoke(input).Result.ToUpper();
                }
                catch (Exception ex)
                {
                    logger.Error(ex, "Stopped program because of exception");
                    throw ex;
                }
                finally
                {
                    NLog.LogManager.Shutdown();
                }
            }
    
            static void BuildConfig(IConfigurationBuilder builder)
            {
                builder.SetBasePath(Directory.GetCurrentDirectory())
                    //.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddEnvironmentVariables();
            }
        }    
    }

ProcessService.cs

    using System.Threading.Tasks;
    using WeyneLoggingWithNLog.Interfaces;
    using Microsoft.Extensions.Logging;
    
    
    namespace WeyneLoggingWithNLog.Services
    {
        public class ProcessService : IProcessService
        {
            private readonly ILogger<ProcessService> _logger;
    
            public ProcessService(ILogger<ProcessService> logger)
            {
                _logger = logger;
            }
    
            public async Task<string> Invoke(string input)
            {
                _logger.LogInformation("Hola mundo: {0}", input);
                _logger.LogError("Error: {0}", input);
                _logger.LogTrace("Trace: {0}", input);
                return input;
            }
        }
    }

本地打印日志

我注意到如果我删除“logging.AddConsole();”来自 Function.cs 的行,不再显示额外的行(标记为黄色),但日志输出停止工作(在我的本地和 aws 中)并且只打印物理日志。

云观察:

AWS 拉姆达:

我取得了这个成绩:

本地:

AWS 拉姆达:

云观察:

我做的修改如下:

存储库:https://github.com/Weyne/AWS-NET_CORE-NLOG/

删除对

的引用
NLog

修改NLog.config:

<?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 xsi:type="File" name="fileTarget" filename="C:\Log${machinename}-${local-ip}-mylambda-${date:format=yyyy-MM-dd}.txt" layout="${longdate}|${level:uppercase=true}|${local-ip}|${callsite}|${message}"></target>
        <target name="console" xsi:type="Console" layout="${level:uppercase=true}|${callsite}|${message}" />

        <target name="aws" type="AWSTarget" />
    </targets>
    <rules>
        <logger name="*" minlevel="Info" writeTo="console" />
        <logger name="*" minlevel="Trace" writeTo="fileTarget" />
    </rules>

</nlog>

删除行“logging.AddConsole();”来自 Function.cs.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using WeyneLoggingWithNLog.Interfaces;
using WeyneLoggingWithNLog.Services;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace WeyneLoggingWithNLog
{
    public class Function
    {

        /// <summary>
        /// A simple function that takes a string and does a ToUpper
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public string FunctionHandler(string input, ILambdaContext context)
        {
            var logger = NLogBuilder.ConfigureNLog("NLog.config").GetCurrentClassLogger();
            try
            {

                var builder = new ConfigurationBuilder();
                BuildConfig(builder);

                var host = Host.CreateDefaultBuilder()
                    .ConfigureLogging((hostingContext, logging) =>
                    {
                        logging.ClearProviders(); //esta línea hace la diferencia
                        logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); //esta línea hace la diferencia
                        logging.AddNLogWeb();
                    })
                    .ConfigureServices((context, services) =>
                    {
                        services.AddHttpContextAccessor();
                        services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
                        services.AddScoped<IProcessService, ProcessService>();
                        services.BuildServiceProvider();
                        services.AddLogging();
                    })
                    .UseNLog()
                    .Build();

                var service = ActivatorUtilities.CreateInstance<ProcessService>(host.Services);

                return service.Invoke(input).Result.ToUpper();
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Stopped program because of exception");
                throw ex;
            }
            finally
            {
                NLog.LogManager.Shutdown();
            }
        }

        static void BuildConfig(IConfigurationBuilder builder)
        {
            builder.SetBasePath(Directory.GetCurrentDirectory())
                //.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
        }
    }    
}