함수 이름을 변수로 사용한 모니터링 대시보드 생성하기
함수 이름을 변수로 사용한 모니터링 대시보드 생성하기
이 코드 예제에서는 Lambda 함수 이름을 변수로 사용하는 CloudWatch 대시보드를 만드는 방법을 보여드려요.
출처: 문서
본문
다음 작업을 다루어요.
- CloudWatch 대시보드 생성
- 함수 이름 변수를 사용한 Lambda 메트릭 위젯 추가
- 대시보드 검증
- 리소스 정리
Bash (AWS CLI with Bash script)
Note GitHub에 더 많은 내용이 있어요. 전체 예제와 설정·실행 방법은 Sample developer tutorials 저장소에서 확인할 수 있어요.
이 스크립트는 Lambda 함수 이름을 변수(property variable)로 사용해 서로 다른 Lambda 함수를 전환할 수 있는 CloudWatch 대시보드를 만들어요.
#!/bin/bash
# Script to create a CloudWatch dashboard with Lambda function name as a variable
# This script creates a CloudWatch dashboard that allows you to switch between different Lambda functions
# Set up logging with secure permissions
LOG_FILE="${HOME}/.cloudwatch-dashboard-script.log"
touch "$LOG_FILE" && chmod 600 "$LOG_FILE"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "$(date): Starting CloudWatch dashboard creation script"
# Security: Set strict error handling
set -uo pipefail
trap 'handle_error "Script failed at line $LINENO"' ERR
# Function to handle errors
handle_error() {
local error_msg="${1:-Unknown error}"
echo "ERROR: $error_msg" >&2
echo "Resources created:"
echo "- CloudWatch Dashboard: LambdaMetricsDashboard"
echo ""
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
echo "An error occurred. Proceeding with automatic cleanup..."
echo "Cleaning up resources..."
aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard 2>/dev/null || true
# Clean up temporary files
if [ -n "${TEMP_DIR:-}" ] && [ -d "$TEMP_DIR" ]; then
rm -rf "$TEMP_DIR"
fi
rm -f dashboard-body.json
echo "Cleanup complete."
exit 1
}
# Security: Validate AWS CLI is installed
if ! command -v aws &> /dev/null; then
handle_error "AWS CLI is not installed. Please install it and try again."
fi
# Check if AWS CLI is installed and configured
echo "Checking AWS CLI configuration..."
if ! aws sts get-caller-identity > /dev/null 2>&1; then
handle_error "AWS CLI is not properly configured. Please configure it with 'aws configure' and try again."
fi
# Get the current region securely
REGION=$(aws configure get region 2>/dev/null || echo "")
if [ -z "$REGION" ]; then
REGION="us-east-1"
echo "No region found in AWS config, defaulting to $REGION"
fi
echo "Using region: $REGION"
# Validate region format
if ! [[ "$REGION" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}$ ]]; then
handle_error "Invalid AWS region format: $REGION"
fi
# Check if there are any Lambda functions in the account
echo "Checking for Lambda functions..."
LAMBDA_FUNCTIONS=$(aws lambda list-functions --region "$REGION" --query "Functions[*].FunctionName" --output text 2>/dev/null || echo "")
if [ -z "$LAMBDA_FUNCTIONS" ]; then
echo "No Lambda functions found in your account. Creating a simple test function..."
# Create a temporary directory for Lambda function code with secure permissions
TEMP_DIR=$(mktemp -d)
chmod 700 "$TEMP_DIR"
trap 'rm -rf "$TEMP_DIR"' EXIT
# Create a simple Lambda function
cat > "$TEMP_DIR/index.js" << 'EOF'
exports.handler = async (event) => {
console.log('Event:', JSON.stringify(event, null, 2));
return {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
};
EOF
# Zip the function code
if ! cd "$TEMP_DIR"; then
handle_error "Failed to change to temporary directory"
fi
if ! zip -q function.zip index.js; then
handle_error "Failed to create zip file"
fi
# Create a role for the Lambda function with restricted trust policy
ROLE_NAME="LambdaDashboardTestRole-$(date +%s)"
TRUST_POLICY='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
if ! ROLE_ARN=$(aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document "$TRUST_POLICY" \
--tags Key=project,Value=doc-smith Key=tutorial,Value=cloudwatch-dynamicdash \
--query "Role.Arn" \
--output text 2>/dev/null); then
handle_error "Failed to create IAM role for Lambda function"
fi
echo "Waiting for role to be available..."
sleep 10
# Attach basic Lambda execution policy
if ! aws iam attach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"; then
aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
handle_error "Failed to attach policy to IAM role"
fi
# Create the Lambda function
FUNCTION_NAME="DashboardTestFunction-$(date +%s)"
if ! aws lambda create-function \
--function-name "$FUNCTION_NAME" \
--runtime nodejs18.x \
--role "$ROLE_ARN" \
--handler index.handler \
--zip-file fileb://function.zip \
--tags project=doc-smith,tutorial=cloudwatch-dynamicdash \
--region "$REGION" > /dev/null 2>&1; then
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true
aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
handle_error "Failed to create Lambda function"
fi
# Invoke the function to generate some metrics
echo "Invoking Lambda function to generate metrics..."
for i in {1..5}; do
aws lambda invoke --function-name "$FUNCTION_NAME" --payload '{}' /dev/null --region "$REGION" > /dev/null 2>&1 || true
sleep 1
done
# Go back to original directory
cd - > /dev/null
# Set the function name for the dashboard
DEFAULT_FUNCTION="$FUNCTION_NAME"
else
# Use the first Lambda function as default
DEFAULT_FUNCTION=$(echo "$LAMBDA_FUNCTIONS" | awk '{print $1}')
echo "Found Lambda functions. Using $DEFAULT_FUNCTION as default."
FUNCTION_NAME=""
ROLE_NAME=""
fi
# Create a dashboard with Lambda metrics and a function name variable
echo "Creating CloudWatch dashboard with Lambda function name variable..."
# Create a JSON file for the dashboard body with secure permissions
DASHBOARD_JSON="dashboard-body-$$.json"
touch "$DASHBOARD_JSON" && chmod 600 "$DASHBOARD_JSON"
# Escape special characters in region and function name for JSON
REGION_ESCAPED=$(printf '%s\n' "$REGION" | sed 's:[/\\&]:\\\\&:g')
FUNCTION_ESCAPED=$(printf '%s\n' "$DEFAULT_FUNCTION" | sed 's:[/\\&]:\\\\&:g')
cat > "$DASHBOARD_JSON" << EOF
{
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[ "AWS/Lambda", "Invocations", "FunctionName", "${FunctionName}" ],
[ ".", "Errors", ".", "." ],
[ ".", "Throttles", ".", "." ]
],
"view": "timeSeries",
"stacked": false,
"region": "$REGION_ESCAPED",
"title": "Lambda Function Metrics for ${FunctionName}",
"period": 300
}
},
{
"type": "metric",
"x": 0,
"y": 6,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[ "AWS/Lambda", "Duration", "FunctionName", "${FunctionName}", { "stat": "Average" } ]
],
"view": "timeSeries",
"stacked": false,
"region": "$REGION_ESCAPED",
"title": "Duration for ${FunctionName}",
"period": 300
}
},
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[ "AWS/Lambda", "ConcurrentExecutions", "FunctionName", "${FunctionName}" ]
],
"view": "timeSeries",
"stacked": false,
"region": "$REGION_ESCAPED",
"title": "Concurrent Executions for ${FunctionName}",
"period": 300
}
}
],
"periodOverride": "auto",
"variables": [
{
"type": "property",
"id": "FunctionName",
"property": "FunctionName",
"label": "Lambda Function",
"inputType": "select",
"values": [
{
"value": "$FUNCTION_ESCAPED",
"label": "$FUNCTION_ESCAPED"
}
]
}
]
}
EOF
# Validate JSON before sending
if ! jq empty "$DASHBOARD_JSON" 2>/dev/null; then
handle_error "Invalid JSON generated for dashboard"
fi
# Create the dashboard using the JSON file
DASHBOARD_NAME="LambdaMetricsDashboard-$(date +%s)"
if ! DASHBOARD_RESULT=$(aws cloudwatch put-dashboard \
--dashboard-name "$DASHBOARD_NAME" \
--dashboard-body file://"$DASHBOARD_JSON" \
--region "$REGION" 2>&1); then
# If we created resources, clean them up
if [ -n "${FUNCTION_NAME:-}" ]; then
aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION" 2>/dev/null || true
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true
aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
fi
handle_error "Failed to create CloudWatch dashboard."
fi
# Display any validation messages but continue
if echo "$DASHBOARD_RESULT" | grep -q "DashboardValidationMessages"; then
echo "Dashboard created with validation messages:"
echo "$DASHBOARD_RESULT"
echo "These validation messages are warnings and the dashboard should still function."
else
echo "Dashboard created successfully!"
fi
# Verify the dashboard was created
echo "Verifying dashboard creation..."
if ! DASHBOARD_INFO=$(aws cloudwatch get-dashboard --dashboard-name "$DASHBOARD_NAME" --region "$REGION" 2>&1); then
# If we created resources, clean them up
if [ -n "${FUNCTION_NAME:-}" ]; then
aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION" 2>/dev/null || true
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true
aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
fi
handle_error "Failed to verify dashboard creation."
fi
echo "Dashboard verification successful!"
echo "Dashboard details:"
echo "$DASHBOARD_INFO"
# List all dashboards to confirm
echo "Listing all dashboards:"
if ! DASHBOARDS=$(aws cloudwatch list-dashboards --region "$REGION" 2>&1); then
# If we created resources, clean them up
if [ -n "${FUNCTION_NAME:-}" ]; then
aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION" 2>/dev/null || true
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true
aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
fi
handle_error "Failed to list dashboards."
fi
echo "$DASHBOARDS"
# Show instructions for accessing the dashboard
echo ""
echo "Dashboard created successfully! To access it:"
echo "1. Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/"
echo "2. In the navigation pane, choose Dashboards"
echo "3. Select $DASHBOARD_NAME"
echo "4. You should see a dropdown menu labeled 'Lambda Function' at the top of the dashboard"
echo "5. Use this dropdown to select different Lambda functions and see their metrics"
echo ""
# Create a list of resources for cleanup
RESOURCES=("- CloudWatch Dashboard: $DASHBOARD_NAME")
if [ -n "${FUNCTION_NAME:-}" ]; then
RESOURCES+=("- Lambda Function: $FUNCTION_NAME")
RESOURCES+=("- IAM Role: $ROLE_NAME")
fi
# Prompt for cleanup with automatic yes
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
echo "Resources created:"
for resource in "${RESOURCES[@]}"; do
echo "$resource"
done
echo ""
echo "Proceeding with automatic cleanup..."
CLEANUP_CHOICE="y"
if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then
echo "Cleaning up resources..."
# Delete the dashboard
if aws cloudwatch delete-dashboards --dashboard-names "$DASHBOARD_NAME" --region "$REGION" 2>/dev/null; then
echo "Dashboard deleted successfully."
else
echo "WARNING: Failed to delete dashboard. You may need to delete it manually."
fi
# If we created a Lambda function, delete it and its role
if [ -n "${FUNCTION_NAME:-}" ]; then
echo "Deleting Lambda function..."
if aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION" 2>/dev/null; then
echo "Lambda function deleted successfully."
else
echo "WARNING: Failed to delete Lambda function. You may need to delete it manually."
fi
echo "Detaching role policy..."
if aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null; then
echo "Role policy detached successfully."
else
echo "WARNING: Failed to detach role policy. You may need to detach it manually."
fi
echo "Deleting IAM role..."
if aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null; then
echo "IAM role deleted successfully."
else
echo "WARNING: Failed to delete IAM role. You may need to delete it manually."
fi
fi
# Clean up the JSON file
rm -f "$DASHBOARD_JSON"
echo "Cleanup complete."
fi
echo "Script completed successfully!"
API 상세는 AWS CLI Command Reference의 다음 항목을 참고해요.
AttachRolePolicy,CreateFunction,CreateRole,DeleteDashboards,DeleteFunction,DeleteRole,DetachRolePolicy,GetCallerIdentity,GetDashboard,Invoke,ListDashboards,ListFunctions,PutDashboard