使用Nlog从Lambda进行Cloudwatch日志记录,创建只读文件系统Exceptionns



我在登录cloudwatch时遇到问题,因为它看起来是间歇性的。并不是所有的错误都记录到Cloudwatch,我在默认的lambda日志组中得到了只读文件系统异常。

该系统的体系结构涉及由SQS队列触发并从其接收消息的lambda(dotnet core 2.1(。然后lambda向第三方发出http请求,并将响应上传到S3。队列上一次有1000多条消息,我已经将lambdas保留的并发性设置为100来处理这一问题,每次处理1条记录,这一切看起来都很好。

我使用Nlog来格式化和过滤lambda中的日志记录,下面的配置显示我只有AWSTargets,没有文件系统目标。我添加了异步包装器来尝试阻止这些问题,但仍然没有成功。

<?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"
throwConfigExceptions="true">
<extensions>
<add assembly="NLog.AWS.Logger" />
</extensions>
<targets>
<target name="CloudwatchTraceTargetAsync" xsi:type="AsyncWrapper" overflowAction="Block">
<target name="CloudwatchTraceTarget" type="AWSTarget" logGroup="/aws/lambda/adx-dev-batch-processor-consumer-trace" region="eu-west-2" layout="${longdate}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}"/>
</target>
<target name="CloudwatchErrorTargetAsync" xsi:type="AsyncWrapper" overflowAction="Block">
<target name="CloudwatchErrorTarget" type="AWSTarget" logGroup="/aws/lambda/adx-dev-batch-processor-consumer-error" region="eu-west-2" layout="${longdate}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" maxlevel="Trace" writeTo="CloudwatchTraceTargetAsync" enabled="false" />
<logger name="*" minlevel="Error" maxlevel="Error" writeTo="CloudwatchErrorTargetAsync" enabled="true" />
</rules>
</nlog>

lambda的入口点如下。我是一名构造函数,像往常一样将记录器注入到我的每个服务和日志中。

public class QueueConsumerLambda
{
private const string AspnetCoreEnvironmentVariable = "ASPNETCORE_ENVIRONMENT";
private IServiceProvider _serviceProvider;
[LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
public async Task ProcessQueueMessage(SQSEvent sqsEvent, ILambdaContext context)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var environmentName = Environment.GetEnvironmentVariable(AspnetCoreEnvironmentVariable);
LogManager.Configuration = new XmlLoggingConfiguration($"nlog.Consumer.{environmentName}.config");
var logger = LogManager.GetCurrentClassLogger();
try
{
logger.Trace($"QueueConsumer.ProcessQueueMessage - started with {sqsEvent.Records.Count} records.");
var config = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile($"appsettings.{environmentName}.json", false, false)
.AddEnvironmentVariables()
.Build();
_serviceProvider = ConfigureServices(config);
var dataRetrievalController = _serviceProvider.GetRequiredService<QueueConsumerController>();
foreach (var record in sqsEvent.Records)
{
logger.Trace($"QueueConsumer.ProcessQueueMessage - messageId: {record.MessageId}, eventSource: {record.EventSource}, record.Body: {record.Body}");
var messageBody = JsonConvert.DeserializeObject<SqsMessageModel>(record.Body);
await dataRetrievalController.GetData(messageBody, record.ReceiptHandle);
}
stopwatch.Stop();
logger.Trace($"QueueConsumer.ProcessQueueMessage - finished and it took {stopwatch.Elapsed.Seconds} seconds.");
}
catch (Exception ex)
{
logger.Error(ex, "Stopped program because of exception");
}
finally
{
LogManager.Shutdown();
}
}
private static IServiceProvider ConfigureServices(IConfiguration config)
{
var services = new ServiceCollection()
.AddLogging(loggingBuilder =>
{
// configure Logging with NLog
loggingBuilder.ClearProviders();
loggingBuilder.AddConfiguration(config.GetSection("Logging"));
loggingBuilder.AddNLog(config);
})
// registering more services
}
}

我成功地将日志放入单独的错误日志组,但不是所有日志。一些错误没有被记录下来,我知道这一点,因为http请求的预期输出文件不在S3中,并且当我在本地调试时,我遇到了预期的异常。我唯一的猜测是,记录到默认日志组的只读文件系统错误是一种症状。同样值得注意的是,并非总是丢失相同的错误,如果我在第二天处理相同的请求,则不会记录不同数量的错误。

我很困惑,不确定我是否在lambda函数的上下文中正确设置了日志记录,或者我是否达到了cloudwatch限制或任何其他原因。因此,任何见解都值得赞赏。如果需要更多信息,请告诉我

我可能会更改它,使构造函数负责设置日志。不具有请求功能:

public class QueueConsumerLambda
{
private const string AspnetCoreEnvironmentVariable = "ASPNETCORE_ENVIRONMENT";
private IServiceProvider _serviceProvider;
private NLog.Logger _logger;
public QueueConsumerLambda()
{
try
{
var environmentName = Environment.GetEnvironmentVariable(AspnetCoreEnvironmentVariable);
LogManager.Configuration = new XmlLoggingConfiguration($"nlog.Consumer.{environmentName}.config");
_logger = LogManager.GetCurrentClassLogger();
var config = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile($"appsettings.{environmentName}.json", false, false)
.AddEnvironmentVariables()
.Build();

_serviceProvider = ConfigureServices(config)
}
catch (Exception ex)
{
_logger?.Error(ex, "Stopped program because of exception");
_logger?.LogFactory?.Shutdown();
}
}
[LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
public async Task ProcessQueueMessage(SQSEvent sqsEvent, ILambdaContext context)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var logger = _logger;
try
{
logger.Trace($"QueueConsumer.ProcessQueueMessage - started with {sqsEvent.Records.Count} records.");
var dataRetrievalController = _serviceProvider.GetRequiredService<QueueConsumerController>();
foreach (var record in sqsEvent.Records)
{
logger.Trace($"QueueConsumer.ProcessQueueMessage - messageId: {record.MessageId}, eventSource: {record.EventSource}, record.Body: {record.Body}");
var messageBody = JsonConvert.DeserializeObject<SqsMessageModel>(record.Body);
await dataRetrievalController.GetData(messageBody, record.ReceiptHandle);
}
stopwatch.Stop();
logger.Trace($"QueueConsumer.ProcessQueueMessage - finished and it took {stopwatch.Elapsed.Seconds} seconds.");
}
catch (Exception ex)
{
logger.Error(ex, "Stopped program because of exception");
}
finally
{
LogManager.Flush(); // Not shutdown
}
}
private static IServiceProvider ConfigureServices(IConfiguration config)
{
var services = new ServiceCollection()
.AddLogging(loggingBuilder =>
{
// configure Logging with NLog
loggingBuilder.ClearProviders();
loggingBuilder.AddConfiguration(config.GetSection("Logging"));
loggingBuilder.AddNLog(config);
})
// registering more services
}
}

但也许正确的建议是通过ILambdaContext进行日志记录。另请参阅https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-cloud-logging-with-Azure-function-or-AWS-lambda#writing-到aws和中的ilambdacontext ilambdaloggerhttps://github.com/aws/aws-logging-dotnet#aws-λ

最新更新