Skip to content

Commit d0e9b90

Browse files
committed
feat(python): add state machine to collect metrics for dashboard
* update the hard-coded Python-Version for the Lambda Function * Lambda Function code is now inline * uv-ready with pyproject.toml * new Stack: StepFunction state machine to automatically collect metrics for the dashboard * python code ruff formated
1 parent 02652d5 commit d0e9b90

File tree

11 files changed

+407
-161
lines changed

11 files changed

+407
-161
lines changed

python/lambda-cloudwatch-dashboard/README.md

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,66 @@ CloudWatch dashboards are used to create customized views of the metrics and ala
77
This CDK sample uses an AWS Lambda Function, as an example, for the source of CloudWatch metrics. This
88
approach can used with AWS Services that create [CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html) or even [Custom CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html) that you publish yourself.
99

10-
The following resources are defined in the CDK Stack:
11-
- [AWS Lambda Function](https://aws.amazon.com/lambda/)
10+
The following resources are defined in the main CDK Stack:
1211
- [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/)
12+
- [AWS Lambda Function](https://aws.amazon.com/lambda/)
13+
14+
To automatically trigger the Lambda Function we use an
15+
[AWS StepFunctions](https://aws.amazon.com/step-functions/), started after provisioning by a Custom Resource(another Lambda Function).
1316

14-
After deploying solution, you will have created a CloudWatch Dashboard, like the one shown below:
17+
After deploying the CDK Stacks the StepFunctions state machine will run 20+ minutes to generate sample metrics.
18+
19+
In CloudWatch you see the provisioned dashboard, like the one shown below:
1520

1621
![Sample Dashboard](img/sample_cloudwatch_dashboard.png)
1722

18-
---
19-
### Requirements:
23+
## Setup
24+
25+
This project is set up like a standard Python project.
2026

21-
- git
22-
- npm (node.js)
23-
- python 3.x
24-
- AWS access key & secret for AWS user with permissions to create resources listed above
27+
## Use uv
28+
Create a virtualenv and install all dependencies
29+
```
30+
uv sync
31+
```
32+
At this point you can now synthesize the CloudFormation template for this code.
33+
```
34+
uv run cdk synth
35+
```
36+
Or simple proceed to deployment of the stack.
37+
```
38+
uv run cdk deploy --all
39+
```
2540

26-
---
41+
### View CloudWatch Dashboard
2742

28-
## Setup
43+
1) Sign in to the AWS Console
44+
2) Navigate to the URL in this CDK Stack Output: `LambdaCloudwatchDashboardStack.DashboardOutput`
45+
3) Please note, the metrics are aggregated for a period of 5 minutes before being displayed on the Dashboard. The value of the period can be configured, please see the [CDK documentation](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_cloudwatch/MetricProps.html) for further details.
2946

30-
This project is set up like a standard Python project. The initialization process also creates
31-
a virtualenv within this project, stored under the .env directory. To create the virtualenv
32-
it assumes that there is a `python3` executable in your path with access to the `venv` package.
33-
If for any reason the automatic creation of the virtualenv fails, you can create the virtualenv
34-
manually once the init process completes.
47+
To clean up, issue this command:
48+
```
49+
uv run cdk destroy --all
50+
```
3551

52+
## Or use the default deployment
3653
To manually create a virtualenv on MacOS and Linux:
3754

3855
```
39-
$ python3 -m venv .env
56+
$ python3 -m venv .venv
4057
```
4158

4259
After the init process completes and the virtualenv is created, you can use the following
4360
step to activate your virtualenv.
4461

4562
```
46-
$ source .env/bin/activate
63+
$ source .venv/bin/activate
4764
```
4865

4966
If you are a Windows platform, you would activate the virtualenv like this:
5067

5168
```
52-
$ .env\Scripts\activate.bat
69+
% .venv\Scripts\activate.bat
5370
```
5471

5572
Once the virtualenv is activated, you can install the required dependencies.
@@ -58,15 +75,6 @@ Once the virtualenv is activated, you can install the required dependencies.
5875
$ pip install -r requirements.txt
5976
```
6077

61-
62-
Install the latest version of the AWS CDK CLI:
63-
64-
```
65-
$ npm i -g aws-cdk
66-
```
67-
68-
## Deployment
69-
7078
At this point you can now synthesize the CloudFormation template for this code.
7179
```
7280
cdk synth
@@ -76,36 +84,8 @@ Or simple proceed to deployment of the stack.
7684
```
7785
cdk deploy
7886
```
79-
80-
## Test
81-
82-
### Invoke Lambda Function
83-
In order to generate some metrics, you can invoke the sample Lambda Function:
84-
85-
Replace `<NAME_OF_FUNCTION>` with the value of this CDK Stack Output: `LambdaCloudwatchDashboardStack.LambdaName`
86-
```
87-
aws lambda invoke --function-name <NAME_OF_FUNCTION> text_output.txt
88-
```
89-
90-
### View CloudWatch Dashboard
91-
92-
1) Sign into to the AWS Console
93-
2) Navigate to the URL in this CDK Stack Output: `LambdaCloudwatchDashboardStack.DashboardOutput`
94-
3) Please note, the metrics are aggregated for a period of 5 minutes before being displayed on the Dashboard. The value of the period can be configured, please see the [CDK documentation](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_cloudwatch/MetricProps.html) for further details.
95-
96-
9787
## Clean Up
9888
To clean up, issue this command:
9989
```
10090
cdk destroy
101-
```
102-
103-
## Useful commands
104-
105-
* `cdk ls` list all stacks in the app
106-
* `cdk synth` emits the synthesized CloudFormation template
107-
* `cdk deploy` deploy this stack to your default AWS account/region
108-
* `cdk diff` compare deployed stack with current state
109-
* `cdk docs` open CDK documentation
110-
111-
Enjoy!
91+
```
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
#!/usr/bin/env python3
2+
23
from aws_cdk import App
3-
from lambda_cloudwatch_dashboard.lambda_cloudwatch_dashboard_stack import LambdaCloudwatchDashboardStack
44

5+
from lambda_cloudwatch_dashboard.lambda_cloudwatch_dashboard_stack import (
6+
LambdaCloudwatchDashboardStack,
7+
)
8+
from lambda_cloudwatch_dashboard.stepfunctions_invoker_stack import (
9+
StepfunctionsInvokerStack,
10+
)
511

612
app = App()
7-
LambdaCloudwatchDashboardStack(app, "LambdaCloudwatchDashboardStack")
13+
14+
lambdastack = LambdaCloudwatchDashboardStack(app, "LambdaCloudwatchDashboardStack")
15+
16+
stepfunctionsstack = StepfunctionsInvokerStack(app, "StepfunctionsInvokerStack")
17+
stepfunctionsstack.add_dependency(lambdastack)
18+
819
app.synth()
Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,117 @@
11
{
2-
"app": "python3 app.py"
2+
"app": "python3 app.py",
3+
"staging": "false",
4+
"watch": {
5+
"include": [
6+
"**"
7+
],
8+
"exclude": [
9+
"README.md",
10+
"cdk*.json",
11+
"pyproject.toml",
12+
"requirements*.txt",
13+
"source.bat",
14+
"**/__init__.py",
15+
"**/__pycache__",
16+
"tests"
17+
]
18+
},
19+
"context": {
20+
"@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true,
21+
"@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true,
22+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
23+
"@aws-cdk/core:checkSecretUsage": true,
24+
"@aws-cdk/core:target-partitions": [
25+
"aws",
26+
"aws-cn"
27+
],
28+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
29+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
30+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
31+
"@aws-cdk/aws-iam:minimizePolicies": true,
32+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
33+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
34+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
35+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
36+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
37+
"@aws-cdk/core:enablePartitionLiterals": true,
38+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
39+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
40+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
41+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
42+
"@aws-cdk/aws-route53-patters:useCertificate": true,
43+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
44+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
45+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
46+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
47+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
48+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
49+
"@aws-cdk/aws-redshift:columnId": true,
50+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
51+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
52+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
53+
"@aws-cdk/aws-kms:aliasNameRef": true,
54+
"@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true,
55+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
56+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
57+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
58+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
59+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
60+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
61+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
62+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
63+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
64+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
65+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
66+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
67+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
68+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
69+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
70+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
71+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
72+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
73+
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
74+
"@aws-cdk/core:explicitStackTags": true,
75+
"@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false,
76+
"@aws-cdk/aws-ecs:disableEcsImdsBlocking": true,
77+
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
78+
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
79+
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
80+
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
81+
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
82+
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
83+
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
84+
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
85+
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
86+
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
87+
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
88+
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
89+
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
90+
"@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false,
91+
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
92+
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
93+
"@aws-cdk/core:aspectPrioritiesMutating": true,
94+
"@aws-cdk/aws-dynamodb:retainTableReplica": true,
95+
"@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true,
96+
"@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true,
97+
"@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true,
98+
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true,
99+
"@aws-cdk/aws-lambda:useCdkManagedLogGroup": true,
100+
"@aws-cdk/core:newStyleStackSynthesis": true,
101+
"@aws-cdk/core:stackRelativeExports": true,
102+
"@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
103+
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
104+
"@aws-cdk/aws-lambda:recognizeVersionProps": true,
105+
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
106+
"@aws-cdk/pipelines:reduceAssetRoleTrustScope": true,
107+
"@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": true,
108+
"@aws-cdk/core:aspectStabilization": true,
109+
"@aws-cdk/pipelines:reduceStageRoleTrustScope": true,
110+
"@aws-cdk/cognito:logUserPoolClientSecretValue": false,
111+
"@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": true,
112+
"@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": false,
113+
"@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": true,
114+
"@aws-cdk/aws-stepfunctions-tasks:httpInvokeDynamicJsonPathEndpoint": true,
115+
"@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": true
116+
}
3117
}
81.2 KB
Loading
Binary file not shown.

python/lambda-cloudwatch-dashboard/lambda/lambda-handler.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)