License: Attribution-NonCommercial-ShareAlike 4.0 International
本文出自 Suzf Blog 。 如未注明,均为 SUZF.NET 原创。
转载请注明: https://suzf.net/post/1460
这篇文章演示了如何使用 Amazon CloudWatch log subscription 自动对特定 AWS Lambda 函数错误发出警报通知。CloudWatch Logs 让您可以在日志条目与模式匹配时调用 Lambda 函数。 Amazon CloudWatch alarms 用于在错误发生时发出通知Lambda 函数;这个通知不会提供有关错误任何的细节。对于您需要在通知中显示具体说明错误的情况,您可以使用 CloudWatch Logs subscription来实现。CloudWatch Logs 订阅让您可以匹配日志中具有特定错误模式的条目,并收到有关这些错误详细信息的通知。这为您节省了额外的步骤解析日志。当在您的 Lambda 函数中检测到该错误模式时,您还可以将其用作构建自动反应措施的蓝图。
这篇文章将向您介绍如何配置触发 AWS Lambda 函数来处理匹配日志的 CloudWatch 日志订阅。Lambda 函数使用 Amazon SNS 发送包含特定错误详细信息和日志位置的电子邮件。
解决方案架构图

此解决方案的架构相对简单。您有一堆 Lambda 函数,您希望收到有关其特定严重错误的通知。CloudWatch Logs 从这些 Lambda 函数中过滤特定模式的日志。例如 ERROR、CRITICAL 或自定义错误。错误处理 Lambda 函数依次向 Amazon SNS 主题发布消息,可以订阅该主题以在发生错误时收到电子邮件。
出于本文的目的,我们将使用以下示例 Lambda 函数生成错误日志:
import logging
import os
logging.basicConfig(level=logging.DEBUG)
logger=logging.getLogger(__name__)
deflambda_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.. !!")
部署教程
前置条件
具有权限创建以下资源: IAM roles and policies, SNS topics, Lambda functions, and CloudWatch event rules.
要实施此解决方案,您必须创建:
SNS topic
IAM role
Lambda function
CloudWatch log trigger
步骤 1: 创建 SNS topic
要创建 SNS 主题,请完成以下步骤:
在左侧导航栏选择 Topics
选择创建 topic. 选择 Standard 类型,输入 topic name `MySNSTopic` 点击 Create topic. 创建 成功后自动跳转到 MySNSTopic 页面。详细信息部分显示主题的名称、ARN、显示名称(可选)和主题所有者的 AWS 账户 ID。
在详情页面,拷贝 topic ARN到粘贴板,比如: arn:aws:sns:us-east-1:123456789012:MySNSTopic
在做了导航,选择 Subscriptions and Create subscription.
在 Create subscription 页面,做一下操作:
输入之前拷贝的 topic ARN: arn:aws:sns:us-east-1:123456789012:MySNSTopic
Protocol 选择 Email
Endpoint, 输入可以接受邮件的邮件地址
选择 Create subscription.
请注意,对于电子邮件订阅,您必须通过点击电子邮件收到的确认订阅链接来确认订阅。确认订阅后,您就可以接收电子邮件通知了。
步骤 2: 创建 IAM role
创建 IAM role, 需要完成一下操作。获取更多信息,请看 Creating an IAM role。
在 IAM console 页面, 在左侧导航栏 选择 Policies, 之后选择 Create Policy.
选择 JSON 选项卡 输入下面 IAM policy, 用之前创建的SNS topic ARN 替换 Topic 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>:*"}
]
}
选择 Review policy.
给这个 policy 输入 name (MyCloudWatchRole) 并 Create policy。记下此策略的名称以供后续步骤使用
在左侧导航栏, 选择 Roles 点击 Create role.
在 Select role type 页面, 选择 AWS 服务作为您的可信实体,并在常见用例下选择 Lambda。
选择 Next: Permissions.
过滤刚刚创建的策略名称,然后选中该复选框。
选择 Next: Tags, 并给它一个合适的标签。
选择 Next: Review. 为这个 IAM 角色指定一个合适的名称,并记下来以备将来使用。
选择 Create role.
步骤 3: 创建 Lambda function
要创建 Lambda 函数,请完成以下步骤。 获取更多信息,参见 Create a Lambda Function with the console.
在 Lambda console, 选择 Author from scratch。
Function Name, 输入函数名称。
Runtime, 选择 Python 3.7.
Execution role, 选择 Use an existing role, 选择之间创建的 IAM role.
选择 Create Function, 移除 default function, 拷贝下列代码到 Function Code 窗口:
# 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://aws.amazon.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)
在 Environment variables 中,输入以下键值对:
Key= snsARN
Value= the ARN of the MySNSTopic created earlier
点击 Save.
步骤 4. 创建 CloudWatch log trigger
要添加触发器,请选择添加触发器,然后从下拉列表中选择 CloudWatch Logs。
在 Log group 下拉列表,选择要获取错误通知的 Lambda 函数的 CloudWatch 日志组名称。在我们的例子中,这将是上面讨论的示例错误生成 Lambda 函数的日志组。
在过滤器名称输入适当的值,并在过滤器模式下,输入您希望收到通知的日志的过滤器值。例如 - “?ERROR ?WARN ?5xx” 将过滤 日志中包含 ERROR、WARN 或 5xx 的日志。 Log filter and pattern syntax 中包含更多其他复杂模式的示例。

启用 trigger & 添加
解决方案验证
为验证我的解决方案,我将运行生成错误日志 Lambda 函数并过滤日志中包含 “?ERROR ?WARN ?5xx” 的日志进行邮件通知,如下所示:

同样,我可以为任何特定错误创建一个过滤器模式,例如过包含 5xx 的日志,并仅针对该错误日志获得以下通知:


卸载
为了避免持续收费,删除在前面的步骤中创建的资源,包括 CloudWatch Events rule Lambda function 和 SNS topic
结论
这篇文章演示了如何使用 CloudWatch Log 过滤器来解析 Lambda 函数的日志并通过电子邮件通知过滤到的错误信息。有关进一步阅读,请参阅:
此文为翻译 源链接为 https://aws.amazon.com/blogs/mt/get-notified-specific-lambda-function-error-patterns-using-cloudwatch/
感谢 Sudhanshu Malhotra 和 Rajat Mathur 的分享