将匹配特定模式的Cloudwatch日志发送到SQS队列

9
我想发送所有Cloudwatch日志,其中控制台日志的消息与特定模式匹配(例如包含单词“postToSlack”,或具有某些json字段如“slack:true”...)。
但是,在我的尝试中,我卡在了最开始的地方:我首先尝试实现最基本的任务:将在执行我的Lambda时编写的所有cloudwatch日志(通过放置在lambda函数内部的console.logs)消息发送到SQS(为什么?因为我首先尝试做最简单的事情,然后再复杂化过滤要发送的日志和不发送的日志)。
因此,我创建了一个Cloudwatch规则>事件>事件模式,如下所示:
{
  "source": [
    "aws.logs"
  ]
}

作为目标,我选择了SQS,然后选择了一个我创建的队列。
但是,当我触发我的lambda函数时,它们出现在Cloudwatch日志中,所以我本来希望日志内容被“发送”到队列中,但是当我轮询/检查队列内容时,在SQS上没有任何可见内容。
我是否对Cloudwatch规则有什么误解?
背景说明:
我的lambda每小时会大量触发(在我的规模下可能是每1或2分钟执行300到500次)。
我想在Slack上监控它们的console.logs(我记录了真正的error.stack JavaScript消息以及纯粹信息性的消息,如lambda输出的结果“公司的报告卡:苹果公司,地点:cupertino...”)。
我可以在每个lambda上使用http调用到Slack,但是Slack的传入钩子每秒只能请求1个,如果您尝试每秒发送多个收件箱webhook,则会收到429错误。因此,我认为需要使用队列,这样我就不需要300多个lambda在同一秒写入Slack,而是在名为slackQueue的集中队列中控制从AWS到Slack的流程。
我的想法是将某些日志(请参见下文)从Cloudwatch发送到SQS slackQueue,然后使用此SQS队列作为lambda触发器,并使用此lambda将10条消息(AWS允许的最大值;对我来说,每个消息= 1个console.log)通过连接成一个大字符串或数组(无论哪种方式)发送到我的Slack频道(顺便说一句,您可以将100条Slack消息连接并在一次调用中发送,基于Slack限制,因此如果我可以处理100条消息= console.log并连接,我会这样做,但是当前批处理大小限制为10 AWS I think),从而确保我不会向Slack发送超过1个“请求”(此请求具有10个console.logs的内容)。
当我在上面说“某些日志”时,实际上我不希望将所有日志发送到队列中(因为我不想在Slack上看到它们):实际上,我不想要纯粹“调试”的消息,例如console.log(“输入函数foo”),这些消息在开发期间非常有用,但与Slack无关。
关于一些评论:我不想使用CloudWatch警报或度量过滤器,因为它们非常昂贵(每小时会触发数百次),并且实际上并不符合我的需求:我不仅想在Slack上阅读关键问题或“问题”发生时的信息(例如CPU> xxx...),而是真正地将“几乎”所有日志的经过筛选的流发送到Slack,以便在Slack中阅读日志,而不是在AWS中阅读。因为Slack是全天开放的工具,用于来自其他来源而不仅仅是AWS的日志/消息的集中地,并且漂亮的Slack附件消息格式更易于我们消化。当然,最终的lambda函数(将消息发送到Slack)会进行一些格式化操作,以添加斜体/粗体等Markdown,以便拥有漂亮格式的“Slack附件”,但这不是最复杂的问题 :)

@JohnRotenstein 感谢您的回复和帮助!我认为您说得对,没有提供足够的上下文,所以我在问题上添加了详细的解释。我愿意接受任何类型的系统,即使它不是我最初认为最好的那种(cloudwatch日志->过滤无用的console.logs-> SQS-> lambda-> Slack),因为说实话,我一个月前才开始使用AWS,并不是专家。 - Mathieu
1
@Mathieu,也许SNS是这项工作的正确工具。结合Opsidian与SLack的集成,您可能可以实现所需的功能:https://medium.com/opsidian/how-to-crush-your-aws-monitoring-with-slack-96b6fde8a9db - Sofo Gial
@SofoGial Opsidian 谢谢你的回答。Opsidian看起来确实很酷,但问题是他们在网站上谈论“获得智能警报”,所以对我来说,Opsidian有两个主要问题。请看下一个评论。 - Mathieu
设置警报并不是我的目标,就像问题所述,我不想仅通过警报发送“问题”/错误(例如CPU > xx),而是如问题所述,即使它们不是问题(例如如何使用您的中等帖子描述的系统过滤由console.log(“lambda的报告卡:company = Apple,location = cupertino ...)发送的日志?);即使我可以“弯曲”云监控警报用于不是真正的“问题警报”的东西,每次都为每个日志记录,因为它们不是崩溃/问题,将所有日志都像这样传输将非常昂贵。 - Mathieu
似乎CloudWatch日志不支持事件模式匹配。https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html - tinker
显示剩余2条评论
2个回答

4

@Mathieu,我认为您在理解CloudWatch事件和CloudWatch日志方面有些误解。

您需要的是实时处理由lambda函数生成的日志数据,基于某种模式筛选日志,然后将这些筛选出的日志存储到Slack中进行分析。

但是配置带有SQS的CloudWatch事件类似于SQS触发Lambda。在这里,cloudWatch会触发(发送消息到)SQS队列。消息的内容不是您的日志,而是您创建的默认消息或自定义消息。

解决方案#1:

使用订阅过滤器根据要求过滤日志,并订阅AWS Kinesis / AWS Lambda / Amazon Kinesis Data Firehouse。使用过滤流(Kinesis),触发您的lambda将该数据推送到Slack。

https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Subscriptions.html https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html

解决方案#2:

  • 将您的cloudWatch日志推送到S3。
  • 在'S3 ObjectCreated'事件上创建一个通知事件,并使用它来触发Lambda函数。
  • 在Lambda函数中,编写逻辑以从S3中读取日志(相当于阅读文件),筛选它们并将筛选出的日志推送到Slack。

谢谢,现在清楚多了。我想我会尝试使用Kinesis。非常感谢你的帮助。 - Mathieu
我也遇到了同样的问题。我发现这里的文档不是很清楚?CloudWatch事件看起来像是你可以将来自外部帐户的CloudWatch日志流式传输到自己的帐户,但这是不可能的? - lifeofguenter
1
@lifeofguenter,没错。配置CloudWatch事件类似于为作业配置触发点,一旦该事件被触发,作业就会启动。CloudWatch日志是AWS上管理日志的完全不同的服务。 - Agam

1

@Mathieu,我知道你卡住的地方的答案。

首先,无论你想触发哪个 Lambda 函数一旦匹配到模式,你需要在那里添加事件,就像我在我的无服务器 yml 文件中添加了事件一样。

events:
  - cloudwatchLog:
      logGroup: '/aws/lambda/lambda-function-name'
      filter: '{$.level = 0}'

那么

  • 在您的Lambda函数中,编写逻辑以从CloudWatchLogsEvent读取日志,您可以从"cloudWatchLogsEvent.Awslogs.EncodedData"中读取。

  • 您需要安装Amazon.Lambda.CloudWatchLogsEvents nuget包以使用CloudWatchLogsEvent类。

  • 您需要对其进行解码解压缩。一旦解压缩,您需要将其反序列化为您的模型。

         byte[] decodedData = Convert.FromBase64String(cloudWatchLogsEvent.Awslogs.EncodedData);
    
         using (var compressedStream = new MemoryStream(decodedData))
         using (var decompressedStream = new MemoryStream())
         using (var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
         {
             gzipStream.CopyTo(decompressedStream);
             var decompressedBytes = decompressedStream.ToArray();
             var decompressedData= Encoding.UTF8.GetString(decompressedBytes);
         }
    
         var logJObject = JObject.Parse(decompressedData);
    

从这个 JObject 中,您可以直接读取属性,如下所示 -

logJObject["logEvents"];
  • 像这样,您需要对它们进行过滤,并且可以使用此日志进行通知(例如,您可以使用带有电子邮件订阅的SNS主题发送电子邮件)。

我希望这很有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接