亚马逊AWS官方博客

如何使用 CloudWatch 获得有关特定 Lambda 函数错误模式的通知

本篇博文演示了如何使用 Amazon CloudWatch 日志订阅自动发出针对特定 AWS Lambda 函数错误的警报通知。 CloudWatch Logs 允许您在日志条目与模式匹配时调用 Lambda 函数。 Amazon CloudWatch 警报用于在 Lambda 函数发生错误时发出通知; 此通知不会提供有关错误的任何详细信息。对于您需要具体说明通知中的错误的情况,您可以使用 CloudWatch Logs 订阅。 CloudWatch Logs 订阅可让您可以将日志中的条目与特定错误模式相匹配,并收到这些错误详细信息的通知。 这将为您节省额外的步骤来分析日志并采取必要的操作。您还可以将其用作蓝图,以便在 Lambda 函数中检测到错误模式时构建自动反应式措施。

这篇文章将引导您了解如何配置触发 AWS Lambda 函数来处理日志的 CloudWatch 日志订阅。 Lambda 函数使用 Amazon SNS 发送包含特定错误详细信息和日志位置的电子邮件。

解决方案概述

该解决方案的架构相当简单。 您拥有一堆 Lambda 函数,并且希望收到有关其特定严重错误的通知。 CloudWatch Logs 从这些 Lambda 函数中捕获日志。 当日志条目与过滤模式匹配时,它会调用“错误处理”Lambda 函数,例如,ERROR、CRITICAL 或自定义错误。 此错误处理 Lambda 函数反过来将消息发布到 Amazon SNS 主题,当错误发生时可以订阅该主题以获取电子邮件。

出于本文的演示目的,我们将使用以下示例错误生成 Lambda 函数:

import logging
import os

logging.basicConfig(level=logging.DEBUG)
logger=logging.getLogger(__name__)


def lambda_handler(event, context):
    logger.setLevel(logging.DEBUG)
    logger.debug("This is a sample DEBUG message.. !!")
    logger.error("This is a sample ERROR message.... !!")
    logger.info("This is a sample INFO message.. !!")
    logger.critical("This is a sample 5xx error message.. !!")

部署教程

先决条件

要实施此解决方案,您必须创建:

  • SNS 话题
  • IAM 角色
  • 一个 Lambda 函数
  • CloudWatch 日志触发器

步骤 1:创建 SNS 主题

要创建 SNS 主题,请完成以下步骤:

  1. 打开 Amazon SNS 控制台
  2. 在左侧导航窗格中,选择主题。
  3. 选择创建主题。 对于主题名称,输入名称并选择创建主题。 您现在可以看到 MySNSTopic 页面。 详细信息部分显示主题的名称、ARN、显示名称(可选)和主题所有者的 AWS 账户 ID。
  4. 在详细信息部分中,将主题 ARN 复制到剪贴板,例如:arn:aws:sns:us-east-1:123456789012:MySNSTopic
  5. 在左侧导航窗格中,选择订阅和创建订阅。
  6. 在创建订阅页面上,执行以下操作:
    1. 输入您之前创建的主题的主题 ARN:arn:aws:sns:us-east-1:123456789012:MySNSTopic
    2. 在协议中,选择电子邮件。
    3. 在终端节点中,输入可以接收通知的电子邮件地址。
    4. 选择创建订阅。
  7. 请注意,对于电子邮件订阅,您必须通过单击您将通过电子邮件收到的确认订阅链接来确认订阅。 确认订阅后,您就可以接收电子邮件通知了。

步骤 2:创建 IAM 角色

要创建 IAM 角色,请完成以下步骤。 有关更多信息,请参阅创建 IAM 角色

  1. IAM 控制台中,从左侧导航窗格中选择策略,然后选择创建策略。
  2. 选择 JSON 选项卡并输入以下 IAM 策略,将主题 ARN 替换为您在上一步中创建的 SNS 主题 ARN:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sns:Publish",
            "Resource": "arn:<partition>:sns:<region>:<AWS account number>:<name of the SNS topic from previous step>"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:<partition>:logs:<region>:<AWS account number>:log-group:/aws/lambda/<name of the lambda function you are going to create in next step>:*"
        }
    ]
}
JSON
  1. 选择审查政策。
  2. 输入此策略的名称 (MyCloudWatchRole),然后选择创建策略。 记下此策略的名称以供后续步骤使用。
  3. 在左侧导航窗格中,选择角色,然后选择创建角色。
  4. 在选择角色类型页面上,选择 AWS 服务作为您的受信任实体,然后在常见用例下选择 Lambda。
  5. 选择下一步:权限。
  6. 按您刚刚创建的策略名称过滤策略,然后选中该复选框。
  7. 选择下一步:标签,并给它一个适当的标签。
  8. 选择下一步:查看。 给这个 IAM 角色一个适当的名称,并记下它以备将来使用。
  9. 选择创建角色。

步骤 3:创建 Lambda 函数

要创建 Lambda 函数,请完成以下步骤。 有关更多信息,请参阅使用控制台创建 Lambda 函数

  1. Lambda 控制台中,选择从头开始创作。
  2. 对于”函数名称”,请输入函数的名称。
  3. 对于”运行时”,请选择”Python 3.7″。
  4. 对于执行角色,选择使用现有角色,然后选择在上一步中创建的 IAM 角色。
  5. 选择”创建函数”,删除默认函数,然后将以下代码复制到”函数代码”窗口中:
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at## http://thinkwithwp.com/apache2.0/
# or in the "license" file accompanying this file.
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific language governing permissions
# and limitations under the License.
# Description: This Lambda function sends an email notification to a given AWS SNS topic when a particular
#              pattern is matched in the logs of a selected Lambda function. The email subject is
#              Execution error for Lambda-<insert Lambda function name>.
#              The JSON message body of the SNS notification contains the full event details.

# Author: Sudhanshu Malhotra

import base64
import boto3
import gzip
import json
import logging
import os

from botocore.exceptions import ClientError

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def logpayload(event):
    logger.setLevel(logging.DEBUG)
    logger.debug(event['awslogs']['data'])
    compressed_payload = base64.b64decode(event['awslogs']['data'])
    uncompressed_payload = gzip.decompress(compressed_payload)
    log_payload = json.loads(uncompressed_payload)
    return log_payload


def error_details(payload):
    error_msg = ""
    log_events = payload['logEvents']
    logger.debug(payload)
    loggroup = payload['logGroup']
    logstream = payload['logStream']
    lambda_func_name = loggroup.split('/')
    logger.debug(f'LogGroup: {loggroup}')
    logger.debug(f'Logstream: {logstream}')
    logger.debug(f'Function name: {lambda_func_name[3]}')
    logger.debug(log_events)
    for log_event in log_events:
        error_msg += log_event['message']
    logger.debug('Message: %s' % error_msg.split("\n"))
    return loggroup, logstream, error_msg, lambda_func_name


def publish_message(loggroup, logstream, error_msg, lambda_func_name):
    sns_arn = os.environ['snsARN']  # Getting the SNS Topic ARN passed in by the environment variables.
    snsclient = boto3.client('sns')
    try:
        message = ""
        message += "\nLambda error  summary" + "\n\n"
        message += "##########################################################\n"
        message += "# LogGroup Name:- " + str(loggroup) + "\n"
        message += "# LogStream:- " + str(logstream) + "\n"
        message += "# Log Message:- " + "\n"
        message += "# \t\t" + str(error_msg.split("\n")) + "\n"
        message += "##########################################################\n"

        # Sending the notification...
        snsclient.publish(
            TargetArn=sns_arn,
            Subject=f'Execution error for Lambda - {lambda_func_name[3]}',
            Message=message
        )
    except ClientError as e:
        logger.error("An error occured: %s" % e)


def lambda_handler(event, context):
    pload = logpayload(event)
    lgroup, lstream, errmessage, lambdaname = error_details(pload)
    publish_message(lgroup, lstream, errmessage, lambdaname)
Python

6. 在环境变量部分,输入以下键值对:

    • Key= snsARN
    • Value= the ARN of the MySNSTopic created earlier

7. 选择保存。

 

步骤 4. 创建 CloudWatch 日志触发器

  1. 要添加触发器,请选择添加触发器,然后从下拉列表中选择 CloudWatch 日志。
  2. 在日志组下,选择您希望从中获得错误通知的 Lambda 函数的 CloudWatch 日志组名称。 在我们的示例中,这将是上面讨论的示例错误生成 Lambda 函数的日志组。
  3. 为过滤器名称输入适当的值,然后在过滤器模式下,输入您想要通知的日志的过滤器值。 例如 – “?ERROR ?WARN ?5xx” 将过滤日志中的 ERROR、WARN 或 5xx 等术语。 日志过滤器和模式语法文档包含更多其他复杂模式的示例。

4. 启用触发器,然后添加。

 

解决方案验证

为了验证我的解决方案,我将运行示例错误生成 Lambda 函数并过滤“?ERROR ?WARN ?5xx”模式以获取电子邮件通知,如下所示:

同样,我可以为任何特定错误创建过滤模式,例如,如图所示的错误 5xx,并仅针对该错误消息获得以下通知:

清理

为避免持续产生费用,请删除在前面的步骤中创建的资源,包括 CloudWatch Events 规则Lambda 函数SNS 主题

总结

本篇文章演示了如何使用 CloudWatch Log 过滤器来解析 Lambda 函数的日志并获取有关该特定错误的电子邮件通知。 如需进一步阅读,请参阅:

本篇作者

Sudhanshu Malhotra

Sudhanshu Malhotra 是 AWS 的解决方案架构师。 Sudhanshu 喜欢与客户合作,并帮助他们在 AWS 中交付 DevOps、基础设施即代码和 AWS Config 管理领域的复杂解决方案。 在业余时间,Sudhanshu 喜欢与家人共度时光、远足和修理汽车。

Rajat Mathur

Rajat Mathur 是 Amazon Web Services 的企业解决方案架构师。 Rajat 是一位充满激情的技术专家,他喜欢为 AWS 客户构建创新的解决方案。 他关注的核心领域是物联网、网络和无服务器计算。 在业余时间,Rajat 喜欢长途驾驶、旅行和烹饪。