├── .eslintrc.json
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── pull_request_template.md
└── workflows
│ ├── auto-approve.yml
│ ├── build.yml
│ ├── pull-request-lint.yml
│ ├── release.yml
│ └── upgrade-main.yml
├── .gitignore
├── .mergify.yml
├── .npmignore
├── .prettierignore
├── .prettierrc.json
├── .projen
├── deps.json
├── files.json
└── tasks.json
├── .projenrc.ts
├── .vscode
├── launch.json
└── settings.json
├── API.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── SECURITY.md
├── assets
├── BitmapWidgetRenderingSupport
│ └── index.js
└── SecretsManagerMetricsPublisher
│ └── index.js
├── lib
├── common
│ ├── alarm
│ │ ├── AlarmFactory.ts
│ │ ├── AlarmNamingStrategy.ts
│ │ ├── CustomAlarmThreshold.ts
│ │ ├── IAlarmAnnotationStrategy.ts
│ │ ├── IAlarmDedupeStringProcessor.ts
│ │ ├── IAlarmNamingStrategy.ts
│ │ ├── ScaleAlarms.ts
│ │ ├── action
│ │ │ ├── IAlarmActionStrategy.ts
│ │ │ ├── LambdaAlarmActionStrategy.ts
│ │ │ ├── MultipleAlarmActionStrategy.ts
│ │ │ ├── NoopAlarmActionStrategy.ts
│ │ │ ├── OpsItemAlarmActionStrategy.ts
│ │ │ ├── SnsAlarmActionStrategy.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ └── metric-adjuster
│ │ │ ├── CompositeMetricAdjuster.ts
│ │ │ ├── DefaultMetricAdjuster.ts
│ │ │ ├── IMetricAdjuster.ts
│ │ │ ├── Route53HealthCheckMetricAdjuster.ts
│ │ │ └── index.ts
│ ├── index.ts
│ ├── metric
│ │ ├── AnomalyDetectionMathExpression.ts
│ │ ├── BaseMetricFactory.ts
│ │ ├── MetricFactory.ts
│ │ ├── MetricStatistic.ts
│ │ ├── MetricWithAlarmSupport.ts
│ │ ├── RateComputationMethod.ts
│ │ └── index.ts
│ ├── monitoring
│ │ ├── Monitoring.ts
│ │ ├── MonitoringScope.ts
│ │ ├── alarms
│ │ │ ├── AgeAlarmFactory.ts
│ │ │ ├── AnomalyDetectingAlarmFactory.ts
│ │ │ ├── AuroraAlarmFactory.ts
│ │ │ ├── ConnectionAlarmFactory.ts
│ │ │ ├── CustomAlarmFactory.ts
│ │ │ ├── DynamoAlarmFactory.ts
│ │ │ ├── ElastiCacheAlarmFactory.ts
│ │ │ ├── ErrorAlarmFactory.ts
│ │ │ ├── KinesisAlarmFactory.ts
│ │ │ ├── KinesisDataAnalyticsAlarmFactory.ts
│ │ │ ├── LatencyAlarmFactory.ts
│ │ │ ├── LogLevelAlarmFactory.ts
│ │ │ ├── OpenSearchClusterAlarmFactory.ts
│ │ │ ├── QueueAlarmFactory.ts
│ │ │ ├── SecretsManagerAlarmFactory.ts
│ │ │ ├── TaskHealthAlarmFactory.ts
│ │ │ ├── ThroughputAlarmFactory.ts
│ │ │ ├── TopicAlarmFactory.ts
│ │ │ ├── TpsAlarmFactory.ts
│ │ │ ├── UsageAlarmFactory.ts
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── strings.ts
│ ├── url
│ │ ├── AwsConsoleUrlFactory.ts
│ │ └── index.ts
│ └── widget
│ │ ├── axis.ts
│ │ ├── color.ts
│ │ ├── index.ts
│ │ ├── size.ts
│ │ └── types.ts
├── dashboard
│ ├── BitmapDashboard.ts
│ ├── DashboardRenderingPreference.ts
│ ├── DashboardSegment.ts
│ ├── DashboardWithBitmapCopy.ts
│ ├── DefaultDashboardFactory.ts
│ ├── DefaultWidgetFactory.ts
│ ├── DynamicDashboardFactory.ts
│ ├── DynamicDashboardSegment.ts
│ ├── IDashboardFactory.ts
│ ├── IDynamicDashboardFactory.ts
│ ├── IWidgetFactory.ts
│ ├── MonitoringNamingStrategy.ts
│ ├── SingleWidgetDashboardSegment.ts
│ ├── index.ts
│ └── widget
│ │ ├── AlarmMatrixWidget.ts
│ │ ├── BitmapWidget.ts
│ │ ├── CustomWidget.ts
│ │ ├── HeaderWidget.ts
│ │ ├── KeyValueTableWidget.ts
│ │ ├── KeyValueTableWidgetV2.ts
│ │ ├── MonitoringHeaderWidget.ts
│ │ ├── StrictGraphWidget.ts
│ │ ├── UnofficialWidgets.ts
│ │ └── index.ts
├── facade
│ ├── IMonitoringAspect.ts
│ ├── MonitoringAspect.ts
│ ├── MonitoringFacade.ts
│ └── index.ts
├── index.ts
└── monitoring
│ ├── aws-acm
│ ├── CertificateManagerMetricFactory.ts
│ ├── CertificateManagerMonitoring.ts
│ └── index.ts
│ ├── aws-apigateway
│ ├── ApiGatewayMetricFactory.ts
│ ├── ApiGatewayMonitoring.ts
│ └── index.ts
│ ├── aws-apigatewayv2
│ ├── ApiGatewayV2HttpApiMetricFactory.ts
│ ├── ApiGatewayV2HttpApiMonitoring.ts
│ └── index.ts
│ ├── aws-appsync
│ ├── AppSyncMetricFactory.ts
│ ├── AppSyncMonitoring.ts
│ └── index.ts
│ ├── aws-billing
│ ├── BillingMetricFactory.ts
│ ├── BillingMonitoring.ts
│ └── index.ts
│ ├── aws-cloudfront
│ ├── CloudFrontDistributionMetricFactory.ts
│ ├── CloudFrontDistributionMonitoring.ts
│ └── index.ts
│ ├── aws-cloudwatch
│ ├── CloudWatchLogsMetricFactory.ts
│ ├── LogMonitoring.ts
│ └── index.ts
│ ├── aws-codebuild
│ ├── CodeBuildProjectMetricFactory.ts
│ ├── CodeBuildProjectMonitoring.ts
│ └── index.ts
│ ├── aws-docdb
│ ├── DocumentDbMetricFactory.ts
│ ├── DocumentDbMonitoring.ts
│ └── index.ts
│ ├── aws-dynamo
│ ├── DynamoTableGlobalSecondaryIndexMetricFactory.ts
│ ├── DynamoTableGlobalSecondaryIndexMonitoring.ts
│ ├── DynamoTableMetricFactory.ts
│ ├── DynamoTableMonitoring.ts
│ └── index.ts
│ ├── aws-ec2
│ ├── AutoScalingGroupMetricFactory.ts
│ ├── AutoScalingGroupMonitoring.ts
│ ├── EC2MetricFactory.ts
│ ├── EC2Monitoring.ts
│ └── index.ts
│ ├── aws-ecs-patterns
│ ├── BaseServiceMetricFactory.ts
│ ├── Ec2ServiceMonitoring.ts
│ ├── FargateServiceMonitoring.ts
│ ├── index.ts
│ └── misc.ts
│ ├── aws-elasticache
│ ├── ElastiCacheClusterMetricFactory.ts
│ ├── ElastiCacheClusterMonitoring.ts
│ └── index.ts
│ ├── aws-glue
│ ├── GlueJobMetricFactory.ts
│ ├── GlueJobMonitoring.ts
│ └── index.ts
│ ├── aws-kinesis
│ ├── KinesisDataStreamMetricFactory.ts
│ ├── KinesisDataStreamMonitoring.ts
│ ├── KinesisFirehoseMetricFactory.ts
│ ├── KinesisFirehoseMonitoring.ts
│ └── index.ts
│ ├── aws-kinesisanalytics
│ ├── KinesisDataAnalyticsMetricFactory.ts
│ ├── KinesisDataAnalyticsMonitoring.ts
│ └── index.ts
│ ├── aws-lambda
│ ├── LambdaFunctionEnhancedMetricFactory.ts
│ ├── LambdaFunctionMetricFactory.ts
│ ├── LambdaFunctionMonitoring.ts
│ └── index.ts
│ ├── aws-loadbalancing
│ ├── ApplicationLoadBalancerMetricFactory.ts
│ ├── LoadBalancerMetricFactory.ts
│ ├── NetworkLoadBalancerMetricFactory.ts
│ ├── NetworkLoadBalancerMonitoring.ts
│ └── index.ts
│ ├── aws-opensearch
│ ├── OpenSearchBackportedMetrics.ts
│ ├── OpenSearchClusterMetricFactory.ts
│ ├── OpenSearchClusterMonitoring.ts
│ └── index.ts
│ ├── aws-rds
│ ├── AuroraClusterMonitoring.ts
│ ├── RdsClusterMetricFactory.ts
│ ├── RdsClusterMonitoring.ts
│ ├── RdsInstanceMetricFactory.ts
│ ├── RdsInstanceMonitoring.ts
│ └── index.ts
│ ├── aws-redshift
│ ├── RedshiftClusterMetricFactory.ts
│ ├── RedshiftClusterMonitoring.ts
│ └── index.ts
│ ├── aws-s3
│ ├── S3BucketMetricFactory.ts
│ ├── S3BucketMonitoring.ts
│ └── index.ts
│ ├── aws-secretsmanager
│ ├── SecretsManagerMetricFactory.ts
│ ├── SecretsManagerMetricsPublisher.ts
│ ├── SecretsManagerMonitoring.ts
│ ├── SecretsManagerSecretMetricFactory.ts
│ ├── SecretsManagerSecretMonitoring.ts
│ └── index.ts
│ ├── aws-sns
│ ├── SnsTopicMetricFactory.ts
│ ├── SnsTopicMonitoring.ts
│ └── index.ts
│ ├── aws-sqs
│ ├── SqsQueueMetricFactory.ts
│ ├── SqsQueueMonitoring.ts
│ ├── SqsQueueMonitoringWithDlq.ts
│ └── index.ts
│ ├── aws-step-functions
│ ├── StepFunctionActivityMetricFactory.ts
│ ├── StepFunctionActivityMonitoring.ts
│ ├── StepFunctionLambdaIntegrationMetricFactory.ts
│ ├── StepFunctionLambdaIntegrationMonitoring.ts
│ ├── StepFunctionMetricFactory.ts
│ ├── StepFunctionMonitoring.ts
│ ├── StepFunctionServiceIntegrationMetricFactory.ts
│ ├── StepFunctionServiceIntegrationMonitoring.ts
│ └── index.ts
│ ├── aws-synthetics
│ ├── SyntheticsCanaryMetricFactory.ts
│ ├── SyntheticsCanaryMonitoring.ts
│ └── index.ts
│ ├── aws-wafv2
│ ├── WafV2MetricFactory.ts
│ ├── WafV2Monitoring.ts
│ └── index.ts
│ ├── custom
│ ├── CustomMonitoring.ts
│ └── index.ts
│ ├── fluentbit
│ ├── FluentBitConstants.ts
│ ├── FluentBitMetricFactory.ts
│ ├── FluentBitMonitoring.ts
│ └── index.ts
│ └── index.ts
├── package.json
├── test
├── assets
│ └── schema.graphql
├── common
│ ├── alarm
│ │ ├── AlarmFactory.test.ts
│ │ ├── AlarmNamingStrategy.test.ts
│ │ ├── LatencyAlarmFactory.test.ts
│ │ ├── LatencyType.test.ts
│ │ ├── ScaleAlarms.test.ts
│ │ ├── __snapshots__
│ │ │ ├── AlarmFactory.test.ts.snap
│ │ │ └── ScaleAlarms.test.ts.snap
│ │ ├── action
│ │ │ ├── LambdaAlarmActionStrategy.test.ts
│ │ │ ├── MultipleAlarmActionStrategy.test.ts
│ │ │ ├── OpsItemAlarmActionStrategy.test.ts
│ │ │ ├── SnsAlarmActionStrategy.test.ts
│ │ │ ├── __snapshots__
│ │ │ │ ├── LambdaAlarmActionStrategy.test.ts.snap
│ │ │ │ ├── MultipleAlarmActionStrategy.test.ts.snap
│ │ │ │ ├── OpsItemAlarmActionStrategy.test.ts.snap
│ │ │ │ └── SnsAlarmActionStrategy.test.ts.snap
│ │ │ └── actions.test.ts
│ │ └── metric-adjuster
│ │ │ ├── CompositeMetricAdjuster.test.ts
│ │ │ ├── DefaultMetricAdjuster.test.ts
│ │ │ └── Route53HealthCheckMetricAdjuster.test.ts
│ ├── metric
│ │ ├── MetricFactory.test.ts
│ │ └── __snapshots__
│ │ │ └── MetricFactory.test.ts.snap
│ ├── strings.test.ts
│ ├── url
│ │ └── AwsConsoleUrlFactory.test.ts
│ └── widget
│ │ └── size.test.ts
├── dashboard
│ ├── BitmapDashboard.test.ts
│ ├── DashboardWithBitmapCopy.test.ts
│ ├── DefaultDashboardFactory.test.ts
│ ├── DynamicDashboardFactory.test.ts
│ ├── MonitoringNamingStrategy.test.ts
│ ├── __snapshots__
│ │ └── DefaultDashboardFactory.test.ts.snap
│ └── widget
│ │ ├── AlarmMatrixWidget.test.ts
│ │ ├── BitmapWidget.test.ts
│ │ ├── CustomWidget.test.ts
│ │ ├── HeaderWidget.test.ts
│ │ ├── KeyValueTableWidget.test.ts
│ │ ├── KeyValueTableWidgetV2.test.ts
│ │ ├── MonitoringHeaderWidget.test.ts
│ │ ├── StrictGraphWidget.test.ts
│ │ ├── UnofficialWidgets.test.ts
│ │ └── __snapshots__
│ │ ├── BitmapWidget.test.ts.snap
│ │ ├── HeaderWidget.test.ts.snap
│ │ ├── KeyValueTableWidget.test.ts.snap
│ │ ├── KeyValueTableWidgetV2.test.ts.snap
│ │ ├── MonitoringHeaderWidget.test.ts.snap
│ │ ├── StrictGraphWidget.test.ts.snap
│ │ └── UnofficialWidgets.test.ts.snap
├── facade
│ ├── MonitoringAspect.test.ts
│ ├── MonitoringFacade.test.ts
│ └── __snapshots__
│ │ ├── MonitoringAspect.test.ts.snap
│ │ └── MonitoringFacade.test.ts.snap
├── monitoring
│ ├── TestMonitoringScope.ts
│ ├── aws-acm
│ │ ├── CertificateManagerMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── CertificateManagerMonitoring.test.ts.snap
│ ├── aws-apigateway
│ │ ├── ApiGatewayMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── ApiGatewayMonitoring.test.ts.snap
│ ├── aws-apigatewayv2
│ │ ├── ApiGatewayV2HttpApiMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── ApiGatewayV2HttpApiMonitoring.test.ts.snap
│ ├── aws-appsync
│ │ ├── AppSyncMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── AppSyncMonitoring.test.ts.snap
│ ├── aws-billing
│ │ ├── BillingMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── BillingMonitoring.test.ts.snap
│ ├── aws-cloudfront
│ │ ├── CloudFrontDistribution.test.ts
│ │ └── __snapshots__
│ │ │ └── CloudFrontDistribution.test.ts.snap
│ ├── aws-cloudwatch
│ │ ├── LogMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── LogMonitoring.test.ts.snap
│ ├── aws-codebuild
│ │ ├── CodeBuildProjectMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── CodeBuildProjectMonitoring.test.ts.snap
│ ├── aws-docdb
│ │ ├── DocumentDbMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── DocumentDbMonitoring.test.ts.snap
│ ├── aws-dynamo
│ │ ├── DynamoTableGlobalSecondaryIndexMonitoring.test.ts
│ │ ├── DynamoTableMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── DynamoTableGlobalSecondaryIndexMonitoring.test.ts.snap
│ │ │ └── DynamoTableMonitoring.test.ts.snap
│ ├── aws-ec2
│ │ ├── AutoScalingGroupMonitoring.test.ts
│ │ ├── EC2Monitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── AutoScalingGroupMonitoring.test.ts.snap
│ │ │ └── EC2Monitoring.test.ts.snap
│ ├── aws-ecs-patterns
│ │ ├── Ec2ServiceMonitoring.test.ts
│ │ ├── FargateServiceMonitoring.test.ts
│ │ ├── __snapshots__
│ │ │ ├── Ec2ServiceMonitoring.test.ts.snap
│ │ │ ├── FargateServiceMonitoring.test.ts.snap
│ │ │ └── misc.test.ts.snap
│ │ └── misc.test.ts
│ ├── aws-elasticache
│ │ ├── ElastiCacheClusterMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── ElastiCacheClusterMonitoring.test.ts.snap
│ ├── aws-glue
│ │ ├── GlueJobMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── GlueJobMonitoring.test.ts.snap
│ ├── aws-kinesis
│ │ ├── KinesisDataStreamMonitoring.test.ts
│ │ ├── KinesisFirehoseMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── KinesisDataStreamMonitoring.test.ts.snap
│ │ │ └── KinesisFirehoseMonitoring.test.ts.snap
│ ├── aws-kinesisanalytics
│ │ ├── KinesisDataAnalyticsMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── KinesisDataAnalyticsMonitoring.test.ts.snap
│ ├── aws-lambda
│ │ ├── LambdaFunctionMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── LambdaFunctionMonitoring.test.ts.snap
│ ├── aws-loadbalancing
│ │ ├── ApplicationLoadBalancerMonitoring.test.ts
│ │ ├── NetworkLoadBalancerMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── ApplicationLoadBalancerMonitoring.test.ts.snap
│ │ │ └── NetworkLoadBalancerMonitoring.test.ts.snap
│ ├── aws-opensearch
│ │ ├── OpenSearchClusterMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── OpenSearchClusterMonitoring.test.ts.snap
│ ├── aws-rds
│ │ ├── AuroraClusterMonitoring.test.ts
│ │ ├── RdsClusterMonitoring.test.ts
│ │ ├── RdsInstanceMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── AuroraClusterMonitoring.test.ts.snap
│ │ │ ├── RdsClusterMonitoring.test.ts.snap
│ │ │ └── RdsInstanceMonitoring.test.ts.snap
│ ├── aws-redshift
│ │ ├── RedshiftClusterMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── RedshiftClusterMonitoring.test.ts.snap
│ ├── aws-s3
│ │ ├── S3BucketMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── S3BucketMonitoring.test.ts.snap
│ ├── aws-secretsmanager
│ │ ├── SecretsManagerMonitoring.test.ts
│ │ ├── SecretsManagerSecretMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── SecretsManagerMonitoring.test.ts.snap
│ │ │ └── SecretsManagerSecretMonitoring.test.ts.snap
│ ├── aws-sns
│ │ ├── SnsTopicMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── SnsTopicMonitoring.test.ts.snap
│ ├── aws-sqs
│ │ ├── SqsQueueMonitoring.test.ts
│ │ ├── SqsQueueMonitoringWithDlq.test.ts
│ │ └── __snapshots__
│ │ │ ├── SqsQueueMonitoring.test.ts.snap
│ │ │ └── SqsQueueMonitoringWithDlq.test.ts.snap
│ ├── aws-step-functions
│ │ ├── StepFunctionActivityMonitoring.test.ts
│ │ ├── StepFunctionLambdaIntegrationMonitoring.test.ts
│ │ ├── StepFunctionMonitoring.test.ts
│ │ ├── StepFunctionServiceIntegrationMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ ├── StepFunctionActivityMonitoring.test.ts.snap
│ │ │ ├── StepFunctionLambdaIntegrationMonitoring.test.ts.snap
│ │ │ ├── StepFunctionMonitoring.test.ts.snap
│ │ │ └── StepFunctionServiceIntegrationMonitoring.test.ts.snap
│ ├── aws-synthetics
│ │ ├── SyntheticsCanaryMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── SyntheticsCanaryMonitoring.test.ts.snap
│ ├── aws-wafv2
│ │ ├── WafV2Monitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── WafV2Monitoring.test.ts.snap
│ ├── custom
│ │ ├── CustomMonitoring.test.ts
│ │ └── __snapshots__
│ │ │ └── CustomMonitoring.test.ts.snap
│ └── fluentbit
│ │ ├── FluentBitMonitoring.test.ts
│ │ └── __snapshots__
│ │ └── FluentBitMonitoring.test.ts.snap
├── setup
│ └── setup.ts
└── utils
│ └── SnapshotUtil.ts
├── tsconfig.dev.json
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
3 | * text=auto eol=lf
4 | *.snap linguist-generated
5 | /.eslintrc.json linguist-generated
6 | /.gitattributes linguist-generated
7 | /.github/pull_request_template.md linguist-generated
8 | /.github/workflows/auto-approve.yml linguist-generated
9 | /.github/workflows/build.yml linguist-generated
10 | /.github/workflows/pull-request-lint.yml linguist-generated
11 | /.github/workflows/release.yml linguist-generated
12 | /.github/workflows/upgrade-main.yml linguist-generated
13 | /.gitignore linguist-generated
14 | /.mergify.yml linguist-generated
15 | /.npmignore linguist-generated
16 | /.prettierignore linguist-generated
17 | /.prettierrc.json linguist-generated
18 | /.projen/** linguist-generated
19 | /.projen/deps.json linguist-generated
20 | /.projen/files.json linguist-generated
21 | /.projen/tasks.json linguist-generated
22 | /API.md linguist-generated
23 | /LICENSE linguist-generated
24 | /package.json linguist-generated
25 | /tsconfig.dev.json linguist-generated
26 | /yarn.lock linguist-generated
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: Report an issue
3 | labels: [bug]
4 | body:
5 |
6 | - type: input
7 | id: bug-version
8 | attributes:
9 | label: Version
10 | description: The version of cdk-monitoring-constructs you're using.
11 | placeholder: |
12 | Example: "v0.0.20"
13 | validations:
14 | required: true
15 |
16 | - type: textarea
17 | id: bug-reproduce-steps
18 | attributes:
19 | label: Steps and/or minimal code example to reproduce
20 | description: Provide an example of the issue.
21 | placeholder: |
22 | Example:
23 | 1. First step
24 | 2. Second step
25 | 3. Issue here
26 | validations:
27 | required: true
28 |
29 | - type: textarea
30 | id: bug-expected-behavior
31 | attributes:
32 | label: Expected behavior
33 | description: Explain what you expect to happen.
34 | placeholder: |
35 | Example:
36 | "This should happen..."
37 | validations:
38 | required: true
39 |
40 | - type: textarea
41 | id: bug-actual-behavior
42 | attributes:
43 | label: Actual behavior
44 | description: Explain what actually happens.
45 | placeholder: |
46 | Example:
47 | "This happened instead..."
48 | validations:
49 | required: true
50 |
51 | - type: textarea
52 | id: bug-other-details
53 | attributes:
54 | label: Other details
55 | placeholder: |
56 | Additional details and attachments.
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Report a security vulnerability
4 | url: http://aws.amazon.com/security/vulnerability-reporting/
5 | about: Please report security vulnerabilities to AWS/Amazon Security instead of on GitHub.
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest a new feature or enhancement
3 | labels: [feature-request]
4 | body:
5 |
6 | - type: input
7 | id: feature-scope
8 | attributes:
9 | label: Feature scope
10 | description: The relevant metric namespace.
11 | placeholder: |
12 | Example: "DynamoDB"
13 | validations:
14 | required: true
15 |
16 | - type: textarea
17 | id: feature-description
18 | attributes:
19 | label: Describe your suggested feature
20 | description: What new feature or enhancement should be added?
21 | validations:
22 | required: true
23 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Fixes #
2 |
3 | ---
4 |
5 | _By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_
--------------------------------------------------------------------------------
/.github/workflows/auto-approve.yml:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
3 | name: auto-approve
4 | on:
5 | pull_request_target:
6 | types:
7 | - labeled
8 | - opened
9 | - synchronize
10 | - reopened
11 | - ready_for_review
12 | jobs:
13 | approve:
14 | runs-on: ubuntu-latest
15 | permissions:
16 | pull-requests: write
17 | if: contains(github.event.pull_request.labels.*.name, 'auto-approve') && (github.event.pull_request.user.login == 'cdklabs-automation')
18 | steps:
19 | - uses: hmarr/auto-approve-action@v2.2.1
20 | with:
21 | github-token: ${{ secrets.GITHUB_TOKEN }}
22 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request-lint.yml:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
3 | name: pull-request-lint
4 | on:
5 | pull_request_target:
6 | types:
7 | - labeled
8 | - opened
9 | - synchronize
10 | - reopened
11 | - ready_for_review
12 | - edited
13 | merge_group: {}
14 | jobs:
15 | validate:
16 | name: Validate PR title
17 | runs-on: ubuntu-latest
18 | permissions:
19 | pull-requests: write
20 | if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target')
21 | steps:
22 | - uses: amannn/action-semantic-pull-request@v5.4.0
23 | env:
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 | with:
26 | types: |-
27 | feat
28 | fix
29 | chore
30 | requireScope: false
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 | !/.gitattributes
3 | !/.projen/tasks.json
4 | !/.projen/deps.json
5 | !/.projen/files.json
6 | !/.github/workflows/pull-request-lint.yml
7 | !/.github/workflows/auto-approve.yml
8 | !/package.json
9 | !/LICENSE
10 | !/.npmignore
11 | logs
12 | *.log
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | lerna-debug.log*
17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
18 | pids
19 | *.pid
20 | *.seed
21 | *.pid.lock
22 | lib-cov
23 | coverage
24 | *.lcov
25 | .nyc_output
26 | build/Release
27 | node_modules/
28 | jspm_packages/
29 | *.tsbuildinfo
30 | .eslintcache
31 | *.tgz
32 | .yarn-integrity
33 | .cache
34 | /test-reports/
35 | junit.xml
36 | /coverage/
37 | !/.github/workflows/build.yml
38 | /dist/changelog.md
39 | /dist/version.txt
40 | !/.github/workflows/release.yml
41 | !/.mergify.yml
42 | !/.github/workflows/upgrade-main.yml
43 | !/.github/pull_request_template.md
44 | !/.prettierignore
45 | !/.prettierrc.json
46 | !/test/
47 | !/tsconfig.dev.json
48 | !/lib/
49 | /lib/**/*.js
50 | /lib/**/*.d.ts
51 | /lib/**/*.d.ts.map
52 | /dist/
53 | !/.eslintrc.json
54 | .jsii
55 | tsconfig.json
56 | !/API.md
57 | !/.projenrc.ts
58 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
3 | queue_rules:
4 | - name: default
5 | update_method: merge
6 | conditions:
7 | - "#approved-reviews-by>=1"
8 | - -label~=(do-not-merge)
9 | - status-success=build
10 | - status-success=package-js
11 | - status-success=package-java
12 | - status-success=package-python
13 | - status-success=package-dotnet
14 | merge_method: squash
15 | commit_message_template: |-
16 | {{ title }} (#{{ number }})
17 |
18 | {{ body }}
19 | pull_request_rules:
20 | - name: Automatic merge on approval and successful build
21 | actions:
22 | delete_head_branch: {}
23 | queue:
24 | name: default
25 | conditions:
26 | - "#approved-reviews-by>=1"
27 | - -label~=(do-not-merge)
28 | - status-success=build
29 | - status-success=package-js
30 | - status-success=package-java
31 | - status-success=package-python
32 | - status-success=package-dotnet
33 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 | /.projen/
3 | /test-reports/
4 | junit.xml
5 | /coverage/
6 | permissions-backup.acl
7 | /dist/changelog.md
8 | /dist/version.txt
9 | /.mergify.yml
10 | /.prettierignore
11 | /.prettierrc.json
12 | /test/
13 | /tsconfig.dev.json
14 | !/lib/
15 | !/lib/**/*.js
16 | !/lib/**/*.d.ts
17 | dist
18 | /tsconfig.json
19 | /.github/
20 | /.vscode/
21 | /.idea/
22 | /.projenrc.js
23 | tsconfig.tsbuildinfo
24 | /.eslintrc.json
25 | !.jsii
26 | *.ts
27 | !*.d.ts
28 | /.gitattributes
29 | /.projenrc.ts
30 | /projenrc
31 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "overrides": []
4 | }
5 |
--------------------------------------------------------------------------------
/.projen/deps.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": [
3 | {
4 | "name": "@types/jest",
5 | "type": "build"
6 | },
7 | {
8 | "name": "@types/node",
9 | "type": "build"
10 | },
11 | {
12 | "name": "@typescript-eslint/eslint-plugin",
13 | "version": "^8",
14 | "type": "build"
15 | },
16 | {
17 | "name": "@typescript-eslint/parser",
18 | "version": "^8",
19 | "type": "build"
20 | },
21 | {
22 | "name": "commit-and-tag-version",
23 | "version": "^12",
24 | "type": "build"
25 | },
26 | {
27 | "name": "eslint-config-prettier",
28 | "type": "build"
29 | },
30 | {
31 | "name": "eslint-import-resolver-typescript",
32 | "type": "build"
33 | },
34 | {
35 | "name": "eslint-plugin-import",
36 | "type": "build"
37 | },
38 | {
39 | "name": "eslint-plugin-prettier",
40 | "type": "build"
41 | },
42 | {
43 | "name": "eslint",
44 | "version": "^9",
45 | "type": "build"
46 | },
47 | {
48 | "name": "jest",
49 | "type": "build"
50 | },
51 | {
52 | "name": "jest-junit",
53 | "version": "^15",
54 | "type": "build"
55 | },
56 | {
57 | "name": "jsii-diff",
58 | "type": "build"
59 | },
60 | {
61 | "name": "jsii-docgen",
62 | "version": "^10.5.0",
63 | "type": "build"
64 | },
65 | {
66 | "name": "jsii-pacmak",
67 | "type": "build"
68 | },
69 | {
70 | "name": "jsii-rosetta",
71 | "version": "1.x",
72 | "type": "build"
73 | },
74 | {
75 | "name": "jsii",
76 | "version": "1.x",
77 | "type": "build"
78 | },
79 | {
80 | "name": "prettier",
81 | "type": "build"
82 | },
83 | {
84 | "name": "projen",
85 | "type": "build"
86 | },
87 | {
88 | "name": "ts-jest",
89 | "type": "build"
90 | },
91 | {
92 | "name": "ts-node",
93 | "type": "build"
94 | },
95 | {
96 | "name": "typescript",
97 | "type": "build"
98 | },
99 | {
100 | "name": "@aws-cdk/aws-redshift-alpha",
101 | "version": "2.160.0-alpha.0",
102 | "type": "devenv"
103 | },
104 | {
105 | "name": "aws-cdk-lib",
106 | "version": "^2.160.0",
107 | "type": "peer"
108 | },
109 | {
110 | "name": "constructs",
111 | "version": "^10.0.5",
112 | "type": "peer"
113 | }
114 | ],
115 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
116 | }
117 |
--------------------------------------------------------------------------------
/.projen/files.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | ".eslintrc.json",
4 | ".gitattributes",
5 | ".github/pull_request_template.md",
6 | ".github/workflows/auto-approve.yml",
7 | ".github/workflows/build.yml",
8 | ".github/workflows/pull-request-lint.yml",
9 | ".github/workflows/release.yml",
10 | ".github/workflows/upgrade-main.yml",
11 | ".gitignore",
12 | ".mergify.yml",
13 | ".prettierignore",
14 | ".prettierrc.json",
15 | ".projen/deps.json",
16 | ".projen/files.json",
17 | ".projen/tasks.json",
18 | "LICENSE",
19 | "tsconfig.dev.json"
20 | ],
21 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
22 | }
23 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "configurations": [
4 | {
5 | "type": "node",
6 | "request": "launch",
7 | "name": "Jest: current file",
8 | "program": "${workspaceFolder}/node_modules/.bin/jest",
9 | "args": [
10 | "${fileBasenameNoExtension}"
11 | ],
12 | "console": "integratedTerminal"
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.codeActionsOnSave": {
3 | "source.fixAll.eslint": "explicit"
4 | },
5 | "eslint.validate": ["javascript", "typescript"]
6 | }
7 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | We only provide support for the latest version of the library.
6 |
7 | ## Reporting a Vulnerability
8 |
9 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/).
10 |
11 | Please do **not** create a public GitHub issue.
12 |
--------------------------------------------------------------------------------
/assets/BitmapWidgetRenderingSupport/index.js:
--------------------------------------------------------------------------------
1 | const { CloudWatchClient, GetMetricWidgetImageCommand } = require('@aws-sdk/client-cloudwatch');
2 |
3 | const DOCS = `
4 | ## Display a CloudWatch bitmap graph
5 | Displays CloudWatch metrics as a bitmap, for faster display of metrics.
6 |
7 | ### Widget parameters
8 | Param | Description
9 | ---|---
10 | **graph** | The graph definition. Use the parameters from the **Source** tab in CloudWatch Console's **Metrics** page.
11 |
12 | ### Example parameters
13 | \`\`\` yaml
14 | graph:
15 | view: timeSeries
16 | metrics:
17 | - [ AWS/Lambda, Invocations ]
18 | region: ${process.env.AWS_REGION}
19 | \`\`\`
20 | `;
21 |
22 | exports.handler = async (event) => {
23 | async function renderUsingCloudWatch(graph, width, height) {
24 | const client = new CloudWatchClient({
25 | signingRegion: graph.region,
26 | retryMode: 'standard',
27 | });
28 | const command = new GetMetricWidgetImageCommand({
29 | MetricWidget: JSON.stringify(graph),
30 | });
31 | const response = await client.send(command);
32 | const base64Image = Buffer.from(response.MetricWidgetImage).toString('base64');
33 | return ``;
34 | }
35 |
36 | if (event.describe) {
37 | return DOCS;
38 | }
39 |
40 | const widgetContext = event.widgetContext;
41 | const timeRange = widgetContext.timeRange.zoom || widgetContext.timeRange;
42 | const start = new Date(timeRange.start).toISOString();
43 | const end = new Date(timeRange.end).toISOString();
44 | const width = widgetContext.width;
45 | const height = widgetContext.height;
46 | const graph = Object.assign(event.graph, {start, end, width, height});
47 |
48 | return renderUsingCloudWatch(graph, width, height);
49 | };
50 |
--------------------------------------------------------------------------------
/assets/SecretsManagerMetricsPublisher/index.js:
--------------------------------------------------------------------------------
1 | const { CloudWatchClient, PutMetricDataCommand } = require('@aws-sdk/client-cloudwatch');
2 | const { SecretsManagerClient, DescribeSecretCommand } = require('@aws-sdk/client-secrets-manager');
3 |
4 | const region = process.env.AWS_REGION;
5 | const millisPerDay = 1000 * 60 * 60 * 24;
6 |
7 | const clientOptions = {
8 | signingRegion: region,
9 | retryMode: 'standard',
10 | };
11 |
12 | const cloudwatchClient = new CloudWatchClient(clientOptions);
13 | const secretsManagerClient = new SecretsManagerClient(clientOptions);
14 |
15 | function daysSince(date, now = Date.now()) {
16 | const millis = now - date.getTime();
17 | const days = millis / millisPerDay;
18 | return Math.floor(days);
19 | }
20 |
21 | exports.handler = async (event, context) => {
22 | console.info(`Retrieving secret for event ${JSON.stringify(event)}`);
23 | console.debug(`context: ${JSON.stringify(context)}`);
24 |
25 | const secret = await secretsManagerClient.send(
26 | new DescribeSecretCommand({
27 | SecretId: event.secretId,
28 | })
29 | );
30 |
31 | console.debug(`Found secret: ${JSON.stringify(secret)}`);
32 | if (!secret.Name || !secret.CreatedDate) {
33 | throw new Error("Invalid secret response");
34 | }
35 |
36 | // use retrieved secret name in case secretId was an arn
37 | const secretName = secret.Name;
38 | const lastChangedDate = secret.LastChangedDate ?? secret.CreatedDate;
39 | const lastRotatedDate = secret.LastRotatedDate ?? secret.CreatedDate;
40 | const now = Date.now();
41 |
42 | const params = {
43 | Namespace: "SecretsManager",
44 | MetricData: [
45 | {
46 | MetricName: "DaysSinceLastChange",
47 | Dimensions: [
48 | {
49 | Name: "SecretName",
50 | Value: secretName,
51 | },
52 | ],
53 | Unit: "Count",
54 | Value: daysSince(lastChangedDate, now),
55 | },
56 | {
57 | MetricName: "DaysSinceLastRotation",
58 | Dimensions: [
59 | {
60 | Name: "SecretName",
61 | Value: secretName,
62 | },
63 | ],
64 | Unit: "Count",
65 | Value: daysSince(lastRotatedDate, now),
66 | },
67 | ],
68 | };
69 | console.debug(`putMetricData params: ${JSON.stringify(params)}`);
70 | console.info(`Publishing metrics for secret "${event.secretId}"`);
71 | const command = new PutMetricDataCommand(params);
72 | await cloudwatchClient.send(command);
73 |
74 | return Promise.resolve();
75 | };
76 |
--------------------------------------------------------------------------------
/lib/common/alarm/IAlarmDedupeStringProcessor.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Strategy used to finalize dedupe string.
3 | */
4 | export interface IAlarmDedupeStringProcessor {
5 | /**
6 | * Process the dedupe string which was specified by the user as an override.
7 | *
8 | * @param dedupeString
9 | * @return final dedupe string
10 | */
11 | processDedupeStringOverride(dedupeString: string): string;
12 |
13 | /**
14 | * Process the dedupe string which was auto-generated.
15 | *
16 | * @param dedupeString
17 | * @return final dedupe string
18 | */
19 | processDedupeString(dedupeString: string): string;
20 | }
21 |
22 | /**
23 | * Dedupe string processor that adds prefix and/or suffix to the dedupe string.
24 | */
25 | export class ExtendDedupeString implements IAlarmDedupeStringProcessor {
26 | private readonly prefix: string;
27 | private readonly suffix: string;
28 |
29 | constructor(prefix?: string, suffix?: string) {
30 | this.prefix = prefix ?? "";
31 | this.suffix = suffix ?? "";
32 | }
33 |
34 | processDedupeString(dedupeString: string): string {
35 | return this.prefix + dedupeString + this.suffix;
36 | }
37 |
38 | processDedupeStringOverride(dedupeString: string): string {
39 | return this.prefix + dedupeString + this.suffix;
40 | }
41 | }
42 |
43 | /**
44 | * Default dedupe strategy - does not add any prefix nor suffix.
45 | */
46 | export class DoNotModifyDedupeString extends ExtendDedupeString {
47 | // default constructor = no prefix, no suffix
48 | }
49 |
--------------------------------------------------------------------------------
/lib/common/alarm/IAlarmNamingStrategy.ts:
--------------------------------------------------------------------------------
1 | import { IAlarmActionStrategy } from "./action";
2 |
3 | export interface AlarmNamingInput {
4 | // TODO: make this required
5 | readonly action?: IAlarmActionStrategy;
6 | readonly alarmNameSuffix: string;
7 | readonly alarmNameOverride?: string;
8 | readonly alarmDedupeStringSuffix?: string;
9 | readonly dedupeStringOverride?: string;
10 | readonly disambiguator?: string;
11 | }
12 |
13 | /**
14 | * Strategy used to name alarms, their widgets, and their dedupe strings.
15 | */
16 | export interface IAlarmNamingStrategy {
17 | /**
18 | * How to generate the name of an alarm.
19 | *
20 | * @param props AlarmNamingInput
21 | */
22 | getName(props: AlarmNamingInput): string;
23 |
24 | /**
25 | * How to generate the label for the alarm displayed on a widget.
26 | *
27 | * @param props AlarmNamingInput
28 | */
29 | getWidgetLabel(props: AlarmNamingInput): string;
30 |
31 | /**
32 | * How to generate the deduplication string for an alarm.
33 | */
34 | getDedupeString(props: AlarmNamingInput): string | undefined;
35 | }
36 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/IAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import { AlarmBase } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | import { AlarmMetadata } from "../AlarmFactory";
4 |
5 | /**
6 | * Properties necessary to append actions to an alarm.
7 | */
8 | export interface AlarmActionStrategyProps extends AlarmMetadata {
9 | readonly alarm: AlarmBase;
10 | }
11 |
12 | /**
13 | * An object that appends actions to alarms.
14 | */
15 | export interface IAlarmActionStrategy {
16 | addAlarmActions(props: AlarmActionStrategyProps): void;
17 | }
18 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/LambdaAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import { LambdaAction } from "aws-cdk-lib/aws-cloudwatch-actions";
2 | import { IAlias, IFunction, IVersion } from "aws-cdk-lib/aws-lambda";
3 |
4 | import {
5 | AlarmActionStrategyProps,
6 | IAlarmActionStrategy,
7 | } from "./IAlarmActionStrategy";
8 |
9 | export function triggerLambda(
10 | lambdaFunction: IAlias | IVersion | IFunction,
11 | ): IAlarmActionStrategy {
12 | return new LambdaAlarmActionStrategy(lambdaFunction);
13 | }
14 |
15 | /**
16 | * Alarm action strategy that triggers a Lambda function.
17 | */
18 | export class LambdaAlarmActionStrategy implements IAlarmActionStrategy {
19 | protected readonly lambdaFunction: IAlias | IVersion | IFunction;
20 |
21 | constructor(lambdaFunction: IAlias | IVersion | IFunction) {
22 | this.lambdaFunction = lambdaFunction;
23 | }
24 |
25 | addAlarmActions(props: AlarmActionStrategyProps): void {
26 | props.alarm.addAlarmAction(new LambdaAction(this.lambdaFunction));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/MultipleAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AlarmActionStrategyProps,
3 | IAlarmActionStrategy,
4 | } from "./IAlarmActionStrategy";
5 |
6 | export function multipleActions(...actions: IAlarmActionStrategy[]) {
7 | return new MultipleAlarmActionStrategy(actions);
8 | }
9 |
10 | export function isMultipleAlarmActionStrategy(
11 | obj?: any,
12 | ): obj is MultipleAlarmActionStrategy {
13 | return !!(obj && obj instanceof MultipleAlarmActionStrategy);
14 | }
15 |
16 | /**
17 | * Alarm action strategy that combines multiple actions in the same order as they were given.
18 | */
19 | export class MultipleAlarmActionStrategy implements IAlarmActionStrategy {
20 | readonly actions: IAlarmActionStrategy[];
21 |
22 | constructor(actions: IAlarmActionStrategy[]) {
23 | this.actions = actions;
24 | }
25 |
26 | addAlarmActions(props: AlarmActionStrategyProps): void {
27 | this.actions.forEach((action) => action.addAlarmActions(props));
28 | }
29 |
30 | /**
31 | * Returns list of alarm actions where any nested instances of MultipleAlarmActionStrategy
32 | * are flattened.
33 | *
34 | * @returns flattened list of alarm actions.
35 | */
36 | flattenedAlarmActions(): IAlarmActionStrategy[] {
37 | return this._flattenedAlarmActions(...this.actions);
38 | }
39 |
40 | private _flattenedAlarmActions(
41 | ...actions: IAlarmActionStrategy[]
42 | ): IAlarmActionStrategy[] {
43 | return actions.flatMap((action) => {
44 | if (isMultipleAlarmActionStrategy(action)) {
45 | return this._flattenedAlarmActions(action);
46 | }
47 |
48 | return [action];
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/NoopAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AlarmActionStrategyProps,
3 | IAlarmActionStrategy,
4 | } from "./IAlarmActionStrategy";
5 |
6 | export function noopAction() {
7 | return new NoopAlarmActionStrategy();
8 | }
9 |
10 | /**
11 | * Alarm action strategy that does not add any actions.
12 | */
13 | export class NoopAlarmActionStrategy implements IAlarmActionStrategy {
14 | addAlarmActions(_props: AlarmActionStrategyProps): void {
15 | // No action to create.
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/OpsItemAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import {
2 | OpsItemCategory,
3 | OpsItemSeverity,
4 | SsmAction,
5 | } from "aws-cdk-lib/aws-cloudwatch-actions";
6 | import {
7 | AlarmActionStrategyProps,
8 | IAlarmActionStrategy,
9 | } from "./IAlarmActionStrategy";
10 |
11 | /**
12 | * Creates an AWS OpsCenter OpsItem with critical severity.
13 | *
14 | * @param category optional category (no category by default)
15 | */
16 | export function createCriticalSeverityOpsItem(category?: OpsItemCategory) {
17 | return createOpsItem(OpsItemSeverity.CRITICAL, category);
18 | }
19 |
20 | /**
21 | * Creates an AWS OpsCenter OpsItem with high severity.
22 | *
23 | * @param category optional category (no category by default)
24 | */
25 | export function createHighSeverityOpsItem(category?: OpsItemCategory) {
26 | return createOpsItem(OpsItemSeverity.HIGH, category);
27 | }
28 |
29 | /**
30 | * Creates an AWS OpsCenter OpsItem with medium severity.
31 | *
32 | * @param category optional category (no category by default)
33 | */
34 | export function createMediumSeverityOpsItem(category?: OpsItemCategory) {
35 | return createOpsItem(OpsItemSeverity.MEDIUM, category);
36 | }
37 |
38 | /**
39 | * Creates an AWS OpsCenter OpsItem with low severity.
40 | *
41 | * @param category optional category (no category by default)
42 | */
43 | export function createLowSeverityOpsItem(category?: OpsItemCategory) {
44 | return createOpsItem(OpsItemSeverity.LOW, category);
45 | }
46 |
47 | /**
48 | * Creates an AWS OpsCenter OpsItem.
49 | *
50 | * @param severity desired item severity
51 | * @param category optional category (no category by default)
52 | */
53 | export function createOpsItem(
54 | severity: OpsItemSeverity,
55 | category?: OpsItemCategory,
56 | ) {
57 | return new OpsItemAlarmActionStrategy(severity, category);
58 | }
59 |
60 | /**
61 | * Alarm action strategy that creates an AWS OpsCenter OpsItem.
62 | */
63 | export class OpsItemAlarmActionStrategy implements IAlarmActionStrategy {
64 | /**
65 | * OPS Item Severity
66 | */
67 | readonly severity: OpsItemSeverity;
68 |
69 | /**
70 | * OPS Item Category
71 | */
72 | readonly category?: OpsItemCategory;
73 |
74 | constructor(severity: OpsItemSeverity, category?: OpsItemCategory) {
75 | this.severity = severity;
76 | this.category = category;
77 | }
78 |
79 | addAlarmActions(props: AlarmActionStrategyProps): void {
80 | props.alarm.addAlarmAction(new SsmAction(this.severity, this.category));
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/SnsAlarmActionStrategy.ts:
--------------------------------------------------------------------------------
1 | import { SnsAction } from "aws-cdk-lib/aws-cloudwatch-actions";
2 | import { ITopic } from "aws-cdk-lib/aws-sns";
3 |
4 | import {
5 | AlarmActionStrategyProps,
6 | IAlarmActionStrategy,
7 | } from "./IAlarmActionStrategy";
8 |
9 | export function notifySns(
10 | onAlarmTopic: ITopic,
11 | onOkTopic?: ITopic,
12 | onInsufficientDataTopic?: ITopic,
13 | ): IAlarmActionStrategy {
14 | return new SnsAlarmActionStrategy({
15 | onAlarmTopic,
16 | onOkTopic,
17 | onInsufficientDataTopic,
18 | });
19 | }
20 |
21 | export interface SnsAlarmActionStrategyProps {
22 | /**
23 | * Target topic used when the alarm is triggered.
24 | */
25 | readonly onAlarmTopic: ITopic;
26 |
27 | /**
28 | * Optional target topic for when the alarm goes into the OK state.
29 | *
30 | * @default - no notification sent
31 | */
32 | readonly onOkTopic?: ITopic;
33 |
34 | /**
35 | * Optional target topic for when the alarm goes into the INSUFFICIENT_DATA state.
36 | *
37 | * @default - no notification sent
38 | */
39 | readonly onInsufficientDataTopic?: ITopic;
40 | }
41 |
42 | /**
43 | * Alarm action strategy that sends a notification to the specified SNS topic.
44 | */
45 | export class SnsAlarmActionStrategy implements IAlarmActionStrategy {
46 | protected readonly onAlarmTopic: ITopic;
47 | protected readonly onOkTopic?: ITopic;
48 | protected readonly onInsufficientDataTopic?: ITopic;
49 |
50 | constructor(props: SnsAlarmActionStrategyProps) {
51 | this.onAlarmTopic = props.onAlarmTopic;
52 | this.onOkTopic = props.onOkTopic;
53 | this.onInsufficientDataTopic = props.onInsufficientDataTopic;
54 | }
55 |
56 | addAlarmActions(props: AlarmActionStrategyProps): void {
57 | props.alarm.addAlarmAction(new SnsAction(this.onAlarmTopic));
58 |
59 | if (this.onOkTopic) {
60 | props.alarm.addOkAction(new SnsAction(this.onOkTopic));
61 | }
62 |
63 | if (this.onInsufficientDataTopic) {
64 | props.alarm.addInsufficientDataAction(
65 | new SnsAction(this.onInsufficientDataTopic),
66 | );
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/common/alarm/action/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./IAlarmActionStrategy";
2 | export * from "./LambdaAlarmActionStrategy";
3 | export * from "./MultipleAlarmActionStrategy";
4 | export * from "./NoopAlarmActionStrategy";
5 | export * from "./OpsItemAlarmActionStrategy";
6 | export * from "./SnsAlarmActionStrategy";
7 |
--------------------------------------------------------------------------------
/lib/common/alarm/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./action";
2 | export * from "./metric-adjuster";
3 | export * from "./AlarmFactory";
4 | export * from "./AlarmNamingStrategy";
5 | export * from "./CustomAlarmThreshold";
6 | export * from "./IAlarmAnnotationStrategy";
7 | export * from "./IAlarmDedupeStringProcessor";
8 | export * from "./IAlarmNamingStrategy";
9 | export * from "./ScaleAlarms";
10 |
--------------------------------------------------------------------------------
/lib/common/alarm/metric-adjuster/CompositeMetricAdjuster.ts:
--------------------------------------------------------------------------------
1 | import { Construct } from "constructs";
2 | import { IMetricAdjuster } from "./IMetricAdjuster";
3 | import { MetricWithAlarmSupport } from "../../metric";
4 | import { AddAlarmProps } from "../AlarmFactory";
5 |
6 | /**
7 | * Allows to apply a collection of {@link IMetricAdjuster} to a metric.
8 | */
9 | export class CompositeMetricAdjuster implements IMetricAdjuster {
10 | constructor(private readonly adjusters: IMetricAdjuster[]) {}
11 |
12 | static of(...adjusters: IMetricAdjuster[]) {
13 | return new CompositeMetricAdjuster(adjusters);
14 | }
15 |
16 | /** @inheritdoc */
17 | adjustMetric(
18 | metric: MetricWithAlarmSupport,
19 | alarmScope: Construct,
20 | props: AddAlarmProps,
21 | ): MetricWithAlarmSupport {
22 | let adjustedMetric = metric;
23 | for (const adjuster of this.adjusters) {
24 | adjustedMetric = adjuster.adjustMetric(adjustedMetric, alarmScope, props);
25 | }
26 |
27 | return adjustedMetric;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/common/alarm/metric-adjuster/DefaultMetricAdjuster.ts:
--------------------------------------------------------------------------------
1 | import { Construct } from "constructs";
2 | import { IMetricAdjuster } from "./IMetricAdjuster";
3 | import { MetricWithAlarmSupport } from "../../metric";
4 | import { removeBracketsWithDynamicLabels } from "../../strings";
5 | import { AddAlarmProps } from "../AlarmFactory";
6 |
7 | /**
8 | * Applies the default metric adjustments.
9 | * These adjustments are always applied last, regardless the value configured in {@link AddAlarmProps.metricAdjuster}.
10 | */
11 | export class DefaultMetricAdjuster implements IMetricAdjuster {
12 | static readonly INSTANCE = new DefaultMetricAdjuster();
13 |
14 | /** @inheritdoc */
15 | adjustMetric(
16 | metric: MetricWithAlarmSupport,
17 | _: Construct,
18 | props: AddAlarmProps,
19 | ): MetricWithAlarmSupport {
20 | let adjustedMetric = metric;
21 | if (props.period) {
22 | // Adjust metric period for the alarm
23 | adjustedMetric = adjustedMetric.with({ period: props.period });
24 | }
25 |
26 | if (adjustedMetric.label) {
27 | // Annotations do not support dynamic labels, so we have to remove them from metric name
28 | adjustedMetric = adjustedMetric.with({
29 | label: removeBracketsWithDynamicLabels(adjustedMetric.label),
30 | });
31 | }
32 |
33 | return adjustedMetric;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/common/alarm/metric-adjuster/IMetricAdjuster.ts:
--------------------------------------------------------------------------------
1 | import { Construct } from "constructs";
2 | import { MetricWithAlarmSupport } from "../../metric";
3 | import { AddAlarmProps } from "../AlarmFactory";
4 |
5 | /**
6 | * Adjusts a metric before creating adding an alarm to it.
7 | */
8 | export interface IMetricAdjuster {
9 | /**
10 | * Adjusts a metric.
11 | * @param metric The metric to adjust.
12 | * @param alarmScope The alarm scope.
13 | * @param props The props specified for adding the alarm.
14 | * @returns The adjusted metric.
15 | */
16 | adjustMetric(
17 | metric: MetricWithAlarmSupport,
18 | alarmScope: Construct,
19 | props: AddAlarmProps,
20 | ): MetricWithAlarmSupport;
21 | }
22 |
--------------------------------------------------------------------------------
/lib/common/alarm/metric-adjuster/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./CompositeMetricAdjuster";
2 | export * from "./DefaultMetricAdjuster";
3 | export * from "./IMetricAdjuster";
4 | export * from "./Route53HealthCheckMetricAdjuster";
5 |
--------------------------------------------------------------------------------
/lib/common/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./alarm";
2 | export * from "./metric";
3 | export * from "./monitoring";
4 | export * from "./url";
5 | export * from "./widget";
6 | export * from "./strings";
7 |
--------------------------------------------------------------------------------
/lib/common/metric/AnomalyDetectionMathExpression.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Alarm,
3 | CfnAlarm,
4 | CreateAlarmOptions,
5 | MathExpression,
6 | MathExpressionOptions,
7 | MathExpressionProps,
8 | } from "aws-cdk-lib/aws-cloudwatch";
9 | import { Construct } from "constructs";
10 |
11 | /**
12 | * Captures specific MathExpression for anomaly detection, for which alarm generation is different.
13 | * Added to overcome certain CDK limitations at the time of writing.
14 | * @see https://github.com/aws/aws-cdk/issues/10540
15 | */
16 | export class AnomalyDetectionMathExpression extends MathExpression {
17 | constructor(props: MathExpressionProps) {
18 | super(props);
19 | }
20 |
21 | with(props: MathExpressionOptions): MathExpression {
22 | return new AnomalyDetectionMathExpression({
23 | expression: this.expression,
24 | usingMetrics: this.usingMetrics,
25 | label: props.label ?? this.label,
26 | color: props.color ?? this.color,
27 | period: props.period ?? this.period,
28 | });
29 | }
30 |
31 | createAlarm(scope: Construct, id: string, props: CreateAlarmOptions): Alarm {
32 | const alarm = super.createAlarm(scope, id, props);
33 |
34 | // `usingMetrics` of an anomaly detection alarm can only ever have one entry.
35 | // Should the entry be a math expression, the math expression can have its own `usingMetrics`.
36 | const finalExpressionId = Object.keys(this.usingMetrics)[0];
37 |
38 | // https://github.com/aws/aws-cdk/issues/10540#issuecomment-725222564
39 | const cfnAlarm = alarm.node.defaultChild as CfnAlarm;
40 | cfnAlarm.addPropertyDeletionOverride("Threshold");
41 | (cfnAlarm.metrics as CfnAlarm.MetricDataQueryProperty[]).forEach(
42 | (metric, index) => {
43 | // To create an anomaly detection alarm, returned data should be set to true on two MetricDataQueryProperty(s):
44 | // 1. The metric or math expression that is being evaluated for anomaly detection (eg. expr_1)
45 | // 2. The actual expression of anomaly detection (eg. ANOMALY_DETECTION_BAND(expr_1, 1))
46 | let returnData = false;
47 |
48 | if (metric.expression?.includes("ANOMALY_DETECTION_BAND")) {
49 | // thresholdMetricId is the ID of the ANOMALY_DETECTION_BAND function used as the threshold for the alarm.
50 | cfnAlarm.thresholdMetricId = metric.id;
51 | returnData = true;
52 | } else if (metric.id === finalExpressionId) {
53 | returnData = true;
54 | }
55 |
56 | cfnAlarm.addPropertyOverride(`Metrics.${index}.ReturnData`, returnData);
57 | },
58 | );
59 |
60 | return alarm;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/common/metric/BaseMetricFactory.ts:
--------------------------------------------------------------------------------
1 | import { MetricFactory } from "./MetricFactory";
2 |
3 | export interface BaseMetricFactoryProps {
4 | /**
5 | * Region where the metrics exist.
6 | *
7 | * @default The region configured by the construct holding the Monitoring construct
8 | * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Cross-Account-Cross-Region.html
9 | */
10 | readonly region?: string;
11 |
12 | /**
13 | * Account where the metrics exist.
14 | *
15 | * @default The account configured by the construct holding the Monitoring construct
16 | * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Cross-Account-Cross-Region.html
17 | */
18 | readonly account?: string;
19 | }
20 |
21 | export abstract class BaseMetricFactory<
22 | PropsType extends BaseMetricFactoryProps,
23 | > {
24 | protected readonly metricFactory: MetricFactory;
25 | protected readonly account?: string;
26 | protected readonly region?: string;
27 |
28 | constructor(metricFactory: MetricFactory, props: PropsType) {
29 | this.metricFactory = metricFactory;
30 | this.account = props.account;
31 | this.region = props.region;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/common/metric/MetricWithAlarmSupport.ts:
--------------------------------------------------------------------------------
1 | import { MathExpression, Metric } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | /**
4 | * Any metric we can create an alarm on.
5 | *
6 | * Cannot be an IMetric, as it does not have support for alarms.
7 | */
8 | export type MetricWithAlarmSupport = Metric | MathExpression;
9 |
--------------------------------------------------------------------------------
/lib/common/metric/RateComputationMethod.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Enumeration of different rate computation methods.
3 | */
4 | export enum RateComputationMethod {
5 | /**
6 | * Number of occurrences relative to requests.
7 | * Less sensitive than per-second when TPS > 1.
8 | */
9 | AVERAGE,
10 | /**
11 | * Number of occurrences per second.
12 | * More sensitive than average when TPS > 1.
13 | */
14 | PER_SECOND,
15 | /**
16 | * Number of occurrences per minute.
17 | */
18 | PER_MINUTE,
19 | /**
20 | * Number of occurrences per hour.
21 | */
22 | PER_HOUR,
23 | /**
24 | * Number of occurrences per day.
25 | */
26 | PER_DAY,
27 | }
28 |
--------------------------------------------------------------------------------
/lib/common/metric/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./AnomalyDetectionMathExpression";
2 | export * from "./BaseMetricFactory";
3 | export * from "./MetricFactory";
4 | export * from "./MetricStatistic";
5 | export * from "./MetricWithAlarmSupport";
6 | export * from "./RateComputationMethod";
7 |
--------------------------------------------------------------------------------
/lib/common/monitoring/MonitoringScope.ts:
--------------------------------------------------------------------------------
1 | import { Construct } from "constructs";
2 |
3 | import { IWidgetFactory } from "../../dashboard";
4 | import { AlarmFactory } from "../alarm";
5 | import { MetricFactory } from "../metric";
6 | import { AwsConsoleUrlFactory } from "../url";
7 |
8 | /**
9 | * A scope where all monitored constructs are managed from (i.e., alarms, dashboards, etc.).
10 | *
11 | * Standard usages will use {@link MonitoringFacade}.
12 | */
13 | export abstract class MonitoringScope extends Construct {
14 | /**
15 | * Creates a new widget factory.
16 | */
17 | abstract createWidgetFactory(): IWidgetFactory;
18 |
19 | /**
20 | * Creates a new metric factory.
21 | */
22 | abstract createMetricFactory(): MetricFactory;
23 |
24 | /**
25 | * Creates a new alarm factory.
26 | * Alarms created will be named with the given prefix, unless a local name override is present.
27 | *
28 | * @param alarmNamePrefix alarm name prefix
29 | */
30 | abstract createAlarmFactory(alarmNamePrefix: string): AlarmFactory;
31 |
32 | /**
33 | * Creates a new factory that creates AWS Console URLs.
34 | */
35 | abstract createAwsConsoleUrlFactory(): AwsConsoleUrlFactory;
36 | }
37 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/AnomalyDetectingAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface AnomalyDetectionThreshold extends CustomAlarmThreshold {
10 | readonly standardDeviationForAlarm: number;
11 | readonly alarmWhenAboveTheBand: boolean;
12 | readonly alarmWhenBelowTheBand: boolean;
13 | readonly additionalDescription?: string;
14 | }
15 |
16 | export class AnomalyDetectingAlarmFactory {
17 | protected readonly alarmFactory: AlarmFactory;
18 |
19 | constructor(alarmFactory: AlarmFactory) {
20 | this.alarmFactory = alarmFactory;
21 | }
22 |
23 | addAlarmWhenOutOfBand(
24 | metric: MetricWithAlarmSupport,
25 | alarmNameSuffix: string,
26 | disambiguator: string,
27 | props: AnomalyDetectionThreshold,
28 | ) {
29 | return this.alarmFactory.addAlarm(metric, {
30 | ...props,
31 | disambiguator,
32 | treatMissingData:
33 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
34 | // Dummy threshold value. This gets removed later.
35 | threshold: 0,
36 | comparisonOperator: this.getComparisonOperator(props),
37 | alarmDedupeStringSuffix: props.dedupeStringOverride,
38 | alarmNameSuffix,
39 | alarmDescription:
40 | props.additionalDescription ?? this.getDefaultDescription(props),
41 | });
42 | }
43 |
44 | private getDefaultDescription(props: AnomalyDetectionThreshold) {
45 | if (props.alarmWhenAboveTheBand && props.alarmWhenBelowTheBand) {
46 | return "Anomaly detection: value is outside of the expected band.";
47 | } else if (props.alarmWhenAboveTheBand) {
48 | return "Anomaly detection: value is above the expected band.";
49 | } else if (props.alarmWhenBelowTheBand) {
50 | return "Anomaly detection: value is below the expected band.";
51 | } else {
52 | throw new Error(
53 | "You need to alarm when the value is above or below the band, or both.",
54 | );
55 | }
56 | }
57 |
58 | private getComparisonOperator(props: AnomalyDetectionThreshold) {
59 | if (props.alarmWhenAboveTheBand && props.alarmWhenBelowTheBand) {
60 | return ComparisonOperator.LESS_THAN_LOWER_OR_GREATER_THAN_UPPER_THRESHOLD;
61 | } else if (props.alarmWhenAboveTheBand) {
62 | return ComparisonOperator.GREATER_THAN_UPPER_THRESHOLD;
63 | } else if (props.alarmWhenBelowTheBand) {
64 | return ComparisonOperator.LESS_THAN_LOWER_THRESHOLD;
65 | } else {
66 | throw new Error(
67 | "You need to alarm when the value is above or below the band, or both.",
68 | );
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/AuroraAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface HighServerlessDatabaseCapacityThreshold
10 | extends CustomAlarmThreshold {
11 | readonly maxServerlessDatabaseCapacity: number;
12 | }
13 |
14 | export class AuroraAlarmFactory {
15 | protected readonly alarmFactory: AlarmFactory;
16 |
17 | constructor(alarmFactory: AlarmFactory) {
18 | this.alarmFactory = alarmFactory;
19 | }
20 |
21 | addMaxServerlessDatabaseCapacity(
22 | metric: MetricWithAlarmSupport,
23 | props: HighServerlessDatabaseCapacityThreshold,
24 | disambiguator?: string,
25 | ) {
26 | return this.alarmFactory.addAlarm(metric, {
27 | treatMissingData:
28 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
29 | comparisonOperator:
30 | props.comparisonOperatorOverride ??
31 | ComparisonOperator.GREATER_THAN_THRESHOLD,
32 | ...props,
33 | disambiguator,
34 | threshold: props.maxServerlessDatabaseCapacity,
35 | alarmNameSuffix: "Serverless-Database-Capacity-High",
36 | alarmDescription: "Serverless Database Capacity usage is too high.",
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/ConnectionAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface LowConnectionCountThreshold extends CustomAlarmThreshold {
10 | readonly minConnectionCount: number;
11 | }
12 |
13 | export interface HighConnectionCountThreshold extends CustomAlarmThreshold {
14 | readonly maxConnectionCount: number;
15 | }
16 |
17 | export class ConnectionAlarmFactory {
18 | protected readonly alarmFactory: AlarmFactory;
19 |
20 | constructor(alarmFactory: AlarmFactory) {
21 | this.alarmFactory = alarmFactory;
22 | }
23 |
24 | addMinConnectionCountAlarm(
25 | metric: MetricWithAlarmSupport,
26 | props: LowConnectionCountThreshold,
27 | disambiguator?: string,
28 | ) {
29 | return this.alarmFactory.addAlarm(metric, {
30 | treatMissingData:
31 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
32 | comparisonOperator:
33 | props.comparisonOperatorOverride ??
34 | ComparisonOperator.LESS_THAN_THRESHOLD,
35 | ...props,
36 | disambiguator,
37 | threshold: props.minConnectionCount,
38 | alarmNameSuffix: "Connection-Count-Low",
39 | alarmDescription: `Number of connections is too low.`,
40 | });
41 | }
42 |
43 | addMaxConnectionCountAlarm(
44 | metric: MetricWithAlarmSupport,
45 | props: HighConnectionCountThreshold,
46 | disambiguator?: string,
47 | ) {
48 | return this.alarmFactory.addAlarm(metric, {
49 | treatMissingData:
50 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
51 | comparisonOperator:
52 | props.comparisonOperatorOverride ??
53 | ComparisonOperator.GREATER_THAN_THRESHOLD,
54 | ...props,
55 | disambiguator,
56 | threshold: props.maxConnectionCount,
57 | alarmNameSuffix: "Connection-Count-High",
58 | alarmDescription: `Number of connections is too high.`,
59 | });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/CustomAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface CustomThreshold extends CustomAlarmThreshold {
10 | readonly threshold: number;
11 | readonly comparisonOperator: ComparisonOperator;
12 | readonly dedupeString?: string;
13 | readonly additionalDescription?: string;
14 | }
15 |
16 | export class CustomAlarmFactory {
17 | protected readonly alarmFactory: AlarmFactory;
18 |
19 | constructor(alarmFactory: AlarmFactory) {
20 | this.alarmFactory = alarmFactory;
21 | }
22 |
23 | addCustomAlarm(
24 | metric: MetricWithAlarmSupport,
25 | alarmNameSuffix: string,
26 | disambiguator: string,
27 | props: CustomThreshold,
28 | ) {
29 | return this.alarmFactory.addAlarm(metric, {
30 | ...props,
31 | disambiguator,
32 | treatMissingData:
33 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
34 | threshold: props.threshold,
35 | comparisonOperator:
36 | props.comparisonOperatorOverride ?? props.comparisonOperator,
37 | alarmDedupeStringSuffix: props.dedupeString,
38 | alarmNameSuffix,
39 | alarmDescription:
40 | props.additionalDescription ??
41 | `Threshold of ${props.threshold} has been breached.`,
42 | });
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/DynamoAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export enum CapacityType {
10 | READ = "Read",
11 | WRITE = "Write",
12 | }
13 |
14 | export interface ConsumedCapacityThreshold extends CustomAlarmThreshold {
15 | readonly maxConsumedCapacityUnits: number;
16 | }
17 |
18 | export interface ThrottledEventsThreshold extends CustomAlarmThreshold {
19 | readonly maxThrottledEventsThreshold: number;
20 | }
21 |
22 | export class DynamoAlarmFactory {
23 | protected readonly alarmFactory: AlarmFactory;
24 |
25 | constructor(alarmFactory: AlarmFactory) {
26 | this.alarmFactory = alarmFactory;
27 | }
28 |
29 | addConsumedCapacityAlarm(
30 | metric: MetricWithAlarmSupport,
31 | capacityType: CapacityType,
32 | props: ConsumedCapacityThreshold,
33 | disambiguator?: string,
34 | ) {
35 | return this.alarmFactory.addAlarm(metric, {
36 | treatMissingData:
37 | props.treatMissingDataOverride ?? TreatMissingData.NOT_BREACHING,
38 | comparisonOperator:
39 | props.comparisonOperatorOverride ??
40 | ComparisonOperator.GREATER_THAN_THRESHOLD,
41 | ...props,
42 | disambiguator,
43 | threshold: props.maxConsumedCapacityUnits,
44 | alarmNameSuffix: `${capacityType}-Consumed-Capacity`,
45 | // we will dedupe any kind of error to the same ticket
46 | alarmDedupeStringSuffix: "ConsumedCapacity",
47 | alarmDescription: `${capacityType} consumed capacity is too high.`,
48 | });
49 | }
50 |
51 | addThrottledEventsAlarm(
52 | metric: MetricWithAlarmSupport,
53 | capacityType: CapacityType,
54 | props: ThrottledEventsThreshold,
55 | disambiguator?: string,
56 | ) {
57 | return this.alarmFactory.addAlarm(metric, {
58 | treatMissingData:
59 | props.treatMissingDataOverride ?? TreatMissingData.NOT_BREACHING,
60 | comparisonOperator:
61 | props.comparisonOperatorOverride ??
62 | ComparisonOperator.GREATER_THAN_THRESHOLD,
63 | ...props,
64 | disambiguator,
65 | threshold: props.maxThrottledEventsThreshold,
66 | alarmNameSuffix: `${capacityType}-Throttled-Events`,
67 | // we will dedupe any kind of error to the same ticket
68 | alarmDedupeStringSuffix: "ThrottledEvents",
69 | alarmDescription: `${capacityType} throttled events above threshold.`,
70 | });
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/KinesisDataAnalyticsAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface MaxDowntimeThreshold extends CustomAlarmThreshold {
10 | readonly maxDowntimeInMillis: number;
11 | }
12 |
13 | export interface FullRestartCountThreshold extends CustomAlarmThreshold {
14 | readonly maxFullRestartCount: number;
15 | }
16 |
17 | export class KinesisDataAnalyticsAlarmFactory {
18 | protected readonly alarmFactory: AlarmFactory;
19 |
20 | constructor(alarmFactory: AlarmFactory) {
21 | this.alarmFactory = alarmFactory;
22 | }
23 |
24 | addDowntimeAlarm(
25 | metric: MetricWithAlarmSupport,
26 | props: MaxDowntimeThreshold,
27 | disambiguator?: string,
28 | ) {
29 | return this.alarmFactory.addAlarm(metric, {
30 | treatMissingData:
31 | props.treatMissingDataOverride ?? TreatMissingData.BREACHING,
32 | comparisonOperator:
33 | props.comparisonOperatorOverride ??
34 | ComparisonOperator.GREATER_THAN_THRESHOLD,
35 | ...props,
36 | disambiguator,
37 | threshold: props.maxDowntimeInMillis,
38 | alarmNameSuffix: "Downtime",
39 | alarmDescription: "Application has too much downtime",
40 | // we will dedupe any kind of message count issue to the same ticket
41 | alarmDedupeStringSuffix: "KDADowntimeAlarm",
42 | });
43 | }
44 |
45 | addFullRestartAlarm(
46 | metric: MetricWithAlarmSupport,
47 | props: FullRestartCountThreshold,
48 | disambiguator?: string,
49 | ) {
50 | return this.alarmFactory.addAlarm(metric, {
51 | treatMissingData:
52 | props.treatMissingDataOverride ?? TreatMissingData.BREACHING,
53 | comparisonOperator:
54 | props.comparisonOperatorOverride ??
55 | ComparisonOperator.GREATER_THAN_THRESHOLD,
56 | ...props,
57 | disambiguator,
58 | threshold: props.maxFullRestartCount,
59 | alarmNameSuffix: "FullRestart",
60 | alarmDescription: "Last submitted job is restarting more than usual",
61 | alarmDedupeStringSuffix: "KDAFullRestartAlarm",
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/LogLevelAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | /**
10 | * Level of a given log
11 | */
12 | export enum LogLevel {
13 | ERROR = "ERROR",
14 | CRITICAL = "CRITICAL",
15 | FATAL = "FATAL",
16 | }
17 |
18 | export interface LogLevelCountThreshold extends CustomAlarmThreshold {
19 | /**
20 | * Threshold for the number of logs to alarm on
21 | */
22 | readonly maxLogCount: number;
23 | }
24 |
25 | export class LogLevelAlarmFactory {
26 | protected readonly alarmFactory: AlarmFactory;
27 |
28 | constructor(alarmFactory: AlarmFactory) {
29 | this.alarmFactory = alarmFactory;
30 | }
31 |
32 | addLogCountAlarm(
33 | metric: MetricWithAlarmSupport,
34 | logLevel: LogLevel,
35 | props: LogLevelCountThreshold,
36 | disambiguator?: string,
37 | ) {
38 | return this.alarmFactory.addAlarm(metric, {
39 | treatMissingData:
40 | props.treatMissingDataOverride ?? TreatMissingData.NOT_BREACHING,
41 | comparisonOperator:
42 | props.comparisonOperatorOverride ??
43 | ComparisonOperator.GREATER_THAN_THRESHOLD,
44 | ...props,
45 | disambiguator,
46 | threshold: props.maxLogCount,
47 | alarmNameSuffix: `${LogLevel[logLevel]}-Logs-Count`,
48 | // we will dedupe any kind of error to the same ticket
49 | alarmDedupeStringSuffix: `${LogLevel[logLevel].toLowerCase()}`,
50 | alarmDescription: `${LogLevel[logLevel]} logs count is too high.`,
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/ThroughputAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface MinProcessedBytesThreshold extends CustomAlarmThreshold {
10 | /**
11 | * Threshold for the least number of bytes processed
12 | */
13 | readonly minProcessedBytes: number;
14 | }
15 |
16 | export class ThroughputAlarmFactory {
17 | protected readonly alarmFactory: AlarmFactory;
18 |
19 | constructor(alarmFactory: AlarmFactory) {
20 | this.alarmFactory = alarmFactory;
21 | }
22 |
23 | addMinProcessedBytesAlarm(
24 | metric: MetricWithAlarmSupport,
25 | props: MinProcessedBytesThreshold,
26 | disambiguator?: string,
27 | ) {
28 | return this.alarmFactory.addAlarm(metric, {
29 | treatMissingData:
30 | props.treatMissingDataOverride ?? TreatMissingData.NOT_BREACHING,
31 | comparisonOperator:
32 | props.comparisonOperatorOverride ??
33 | ComparisonOperator.LESS_THAN_THRESHOLD,
34 | ...props,
35 | disambiguator,
36 | threshold: props.minProcessedBytes,
37 | alarmNameSuffix: "Processed-Bytes-Min",
38 | alarmDescription: `Minimum number of processed bytes is too low.`,
39 | });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/TpsAlarmFactory.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComparisonOperator,
3 | TreatMissingData,
4 | } from "aws-cdk-lib/aws-cloudwatch";
5 |
6 | import { AlarmFactory, CustomAlarmThreshold } from "../../alarm";
7 | import { MetricWithAlarmSupport } from "../../metric";
8 |
9 | export interface LowTpsThreshold extends CustomAlarmThreshold {
10 | readonly minTps: number;
11 | }
12 |
13 | export interface HighTpsThreshold extends CustomAlarmThreshold {
14 | readonly maxTps: number;
15 | }
16 |
17 | export class TpsAlarmFactory {
18 | protected readonly alarmFactory: AlarmFactory;
19 |
20 | constructor(alarmFactory: AlarmFactory) {
21 | this.alarmFactory = alarmFactory;
22 | }
23 |
24 | addMinTpsAlarm(
25 | metric: MetricWithAlarmSupport,
26 | props: LowTpsThreshold,
27 | disambiguator?: string,
28 | ) {
29 | return this.alarmFactory.addAlarm(metric, {
30 | treatMissingData:
31 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
32 | comparisonOperator:
33 | props.comparisonOperatorOverride ??
34 | ComparisonOperator.LESS_THAN_THRESHOLD,
35 | ...props,
36 | disambiguator,
37 | threshold: props.minTps,
38 | alarmNameSuffix: `MinTPS`,
39 | alarmDedupeStringSuffix: "Tps-Min",
40 | alarmDescription: `TPS is too low.`,
41 | });
42 | }
43 |
44 | addMaxTpsAlarm(
45 | metric: MetricWithAlarmSupport,
46 | props: HighTpsThreshold,
47 | disambiguator?: string,
48 | ) {
49 | return this.alarmFactory.addAlarm(metric, {
50 | treatMissingData:
51 | props.treatMissingDataOverride ?? TreatMissingData.MISSING,
52 | comparisonOperator:
53 | props.comparisonOperatorOverride ??
54 | ComparisonOperator.GREATER_THAN_THRESHOLD,
55 | ...props,
56 | disambiguator,
57 | threshold: props.maxTps,
58 | alarmNameSuffix: `MaxTPS`,
59 | alarmDedupeStringSuffix: "Tps-Max",
60 | alarmDescription: `TPS is too high.`,
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/common/monitoring/alarms/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./AgeAlarmFactory";
2 | export * from "./AnomalyDetectingAlarmFactory";
3 | export * from "./AuroraAlarmFactory";
4 | export * from "./CustomAlarmFactory";
5 | export * from "./ConnectionAlarmFactory";
6 | export * from "./DynamoAlarmFactory";
7 | export * from "./ElastiCacheAlarmFactory";
8 | export * from "./ErrorAlarmFactory";
9 | export * from "./KinesisAlarmFactory";
10 | export * from "./KinesisDataAnalyticsAlarmFactory";
11 | export * from "./LatencyAlarmFactory";
12 | export * from "./LogLevelAlarmFactory";
13 | export * from "./OpenSearchClusterAlarmFactory";
14 | export * from "./QueueAlarmFactory";
15 | export * from "./SecretsManagerAlarmFactory";
16 | export * from "./TaskHealthAlarmFactory";
17 | export * from "./ThroughputAlarmFactory";
18 | export * from "./TopicAlarmFactory";
19 | export * from "./TpsAlarmFactory";
20 | export * from "./UsageAlarmFactory";
21 |
--------------------------------------------------------------------------------
/lib/common/monitoring/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./alarms";
2 | export * from "./Monitoring";
3 | export * from "./MonitoringScope";
4 |
--------------------------------------------------------------------------------
/lib/common/url/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./AwsConsoleUrlFactory";
2 |
--------------------------------------------------------------------------------
/lib/common/widget/color.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * color to indicate healthy state
3 | */
4 | export const HealthyMetricColor = "#2ca02c";
5 | /**
6 | * color to indicate unhealthy state
7 | */
8 | export const UnhealthyMetricColor = "#d62728";
9 | /**
10 | * color to indicate a warning
11 | */
12 | export const WarningColor = "#ff9900";
13 | /**
14 | * color to indicate an error
15 | */
16 | export const ErrorColor = "#d13212";
17 | /**
18 | * color to indicate neutral information
19 | */
20 | export const NeutralColor = "#999999";
21 | /**
22 | * color to indicate throttled state
23 | */
24 | export const ThrottledColor = "#5928ed";
25 | /**
26 | * color to indicate a started state (e.g. Step Function executions)
27 | */
28 | export const StartedColor = "#0073e6";
29 | /**
30 | * color to indicate a timed out state
31 | */
32 | export const TimedOutColor = "#333333";
33 |
--------------------------------------------------------------------------------
/lib/common/widget/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./axis";
2 | export * from "./color";
3 | export * from "./size";
4 | export * from "./types";
5 |
--------------------------------------------------------------------------------
/lib/common/widget/size.ts:
--------------------------------------------------------------------------------
1 | export const FullWidth = 24;
2 | export const HalfWidth = FullWidth / 2;
3 | export const ThirdWidth = FullWidth / 3;
4 | export const QuarterWidth = FullWidth / 4;
5 | export const HalfQuarterWidth = QuarterWidth / 2;
6 | export const SixthWidth = FullWidth / 6;
7 | export const TwoThirdsWidth = 2 * ThirdWidth;
8 | export const ThreeQuartersWidth = 3 * QuarterWidth;
9 |
10 | // Widget Heights
11 |
12 | export const DefaultGraphWidgetHeight = 5;
13 | export const DefaultTwoLinerGraphWidgetHeight = 6;
14 | export const DefaultTwoLinerGraphWidgetHalfHeight = 3;
15 | export const DefaultSummaryWidgetHeight = 6;
16 | export const DefaultAlarmWidgetWidth = 6;
17 | export const DefaultAlarmWidgetHeight = 4;
18 | export const DefaultLogWidgetHeight = 7;
19 |
20 | /**
21 | * Suggests the best widget width, given the total number of widgets.
22 | * The main point is to make widgets as wide as possible, while saving vertical space and minimizing number of gaps.
23 | *
24 | * @param numTotalWidgets total number of widgets to be placed
25 | */
26 | export function recommendedWidgetWidth(numTotalWidgets: number) {
27 | function numRowsTaken(numItems: number, itemSize: number) {
28 | return Math.ceil((numItems * itemSize) / FullWidth);
29 | }
30 |
31 | const numItemsFixed = Math.max(1, numTotalWidgets);
32 | const widths = [QuarterWidth, ThirdWidth, HalfWidth, FullWidth];
33 | let i = 0;
34 | while (
35 | i < widths.length - 1 &&
36 | numRowsTaken(numItemsFixed, widths[i + 1]) ===
37 | numRowsTaken(numItemsFixed, widths[i])
38 | ) {
39 | i++;
40 | }
41 | return widths[i];
42 | }
43 |
--------------------------------------------------------------------------------
/lib/common/widget/types.ts:
--------------------------------------------------------------------------------
1 | import {
2 | GraphWidget,
3 | GraphWidgetProps,
4 | GraphWidgetView,
5 | IWidget,
6 | SingleValueWidget,
7 | TableWidget,
8 | } from "aws-cdk-lib/aws-cloudwatch";
9 |
10 | export enum GraphWidgetType {
11 | BAR = "Bar",
12 | LINE = "Line",
13 | PIE = "Pie",
14 | SINGLE_VALUE = "SingleValue",
15 | STACKED_AREA = "StackedArea",
16 | TABLE = "Table",
17 | }
18 |
19 | /**
20 | * Creates a graph widget of the desired type.
21 | *
22 | * @param type graph type (e.g. Pie or Bar)
23 | * @param props graph widget properties
24 | */
25 | export function createGraphWidget(
26 | type: GraphWidgetType,
27 | props: GraphWidgetProps,
28 | ): IWidget {
29 | switch (type) {
30 | case GraphWidgetType.BAR:
31 | return new GraphWidget({
32 | ...props,
33 | view: GraphWidgetView.BAR,
34 | });
35 |
36 | case GraphWidgetType.LINE:
37 | return new GraphWidget(props);
38 |
39 | case GraphWidgetType.PIE:
40 | return new GraphWidget({
41 | ...props,
42 | view: GraphWidgetView.PIE,
43 | });
44 |
45 | case GraphWidgetType.SINGLE_VALUE:
46 | return new SingleValueWidget({
47 | ...props,
48 | metrics: [...(props.left ?? []), ...(props.right ?? [])],
49 | });
50 |
51 | case GraphWidgetType.STACKED_AREA:
52 | return new GraphWidget({
53 | ...props,
54 | stacked: true,
55 | });
56 |
57 | case GraphWidgetType.TABLE:
58 | return new TableWidget({
59 | ...props,
60 | metrics: [...(props.left ?? []), ...(props.right ?? [])],
61 | });
62 |
63 | default:
64 | throw new Error(`Unsupported graph type: ${type}`);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/dashboard/BitmapDashboard.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Column,
3 | Dashboard,
4 | DashboardProps,
5 | GraphWidget,
6 | IWidget,
7 | Row,
8 | } from "aws-cdk-lib/aws-cloudwatch";
9 | import { Construct } from "constructs";
10 |
11 | import { BitmapWidgetRenderingSupport } from "./widget";
12 |
13 | /**
14 | * Specific subtype of dashboard that renders supported widgets as bitmaps, while preserving the overall layout.
15 | */
16 | export class BitmapDashboard extends Dashboard {
17 | protected readonly bitmapRenderingSupport: BitmapWidgetRenderingSupport;
18 |
19 | constructor(scope: Construct, id: string, props: DashboardProps) {
20 | super(scope, id, props);
21 | this.bitmapRenderingSupport = new BitmapWidgetRenderingSupport(
22 | this,
23 | "BitmapRenderingSupport",
24 | );
25 | }
26 |
27 | addWidgets(...widgets: IWidget[]) {
28 | super.addWidgets(...this.asBitmaps(...widgets));
29 | }
30 |
31 | protected asBitmap(widget: IWidget): IWidget {
32 | if (widget instanceof GraphWidget) {
33 | return this.bitmapRenderingSupport.asBitmap(widget);
34 | } else if (widget instanceof Row) {
35 | // needs this to access private property
36 | const rowWidgets = (widget as any).widgets;
37 | const rowWidgetsTyped = rowWidgets as IWidget[];
38 | return new Row(...this.asBitmaps(...rowWidgetsTyped));
39 | } else if (widget instanceof Column) {
40 | // needs this to access private property
41 | const colWidgets = (widget as any).widgets;
42 | const colWidgetsTyped = colWidgets as IWidget[];
43 | return new Column(...this.asBitmaps(...colWidgetsTyped));
44 | } else {
45 | return widget;
46 | }
47 | }
48 |
49 | protected asBitmaps(...widgets: IWidget[]): IWidget[] {
50 | return widgets.map((widget) => this.asBitmap(widget));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/dashboard/DashboardRenderingPreference.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Preferred way of rendering dashboard widgets.
3 | */
4 | export enum DashboardRenderingPreference {
5 | /**
6 | * Create standard set of dashboards with interactive widgets only
7 | */
8 | INTERACTIVE_ONLY,
9 |
10 | /**
11 | * Create standard set of dashboards with bitmap widgets only
12 | */
13 | BITMAP_ONLY,
14 |
15 | /**
16 | * Create a two sets of dashboards: standard set (interactive) and a copy (bitmap)
17 | */
18 | INTERACTIVE_AND_BITMAP,
19 | }
20 |
--------------------------------------------------------------------------------
/lib/dashboard/DashboardSegment.ts:
--------------------------------------------------------------------------------
1 | import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | export interface IDashboardSegment {
4 | /**
5 | * Returns widgets for all alarms. These should go to the runbook or service dashboard.
6 | */
7 | alarmWidgets(): IWidget[];
8 |
9 | /**
10 | * Returns widgets for the summary. These should go to the team OPS dashboard.
11 | */
12 | summaryWidgets(): IWidget[];
13 |
14 | /**
15 | * Returns all widgets. These should go to the detailed service dashboard.
16 | */
17 | widgets(): IWidget[];
18 | }
19 |
--------------------------------------------------------------------------------
/lib/dashboard/DashboardWithBitmapCopy.ts:
--------------------------------------------------------------------------------
1 | import { Dashboard, DashboardProps, IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 | import { Construct } from "constructs";
3 |
4 | import { BitmapDashboard } from "./BitmapDashboard";
5 |
6 | /**
7 | * Composite dashboard which keeps a normal dashboard with its bitmap copy.
8 | * The bitmap copy name will be derived from the primary dashboard name, if specified.
9 | */
10 | export class DashboardWithBitmapCopy extends Dashboard {
11 | protected readonly bitmapCopy: BitmapDashboard;
12 |
13 | constructor(scope: Construct, id: string, props: DashboardProps) {
14 | super(scope, id, props);
15 | let dashboardName = props.dashboardName;
16 | if (dashboardName !== undefined) {
17 | dashboardName = "Bitmap-" + dashboardName;
18 | }
19 | this.bitmapCopy = new BitmapDashboard(this, "BitmapCopy", {
20 | ...props,
21 | dashboardName,
22 | });
23 | }
24 |
25 | addWidgets(...widgets: IWidget[]): void {
26 | super.addWidgets(...widgets);
27 | this.bitmapCopy.addWidgets(...widgets);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/dashboard/DefaultWidgetFactory.ts:
--------------------------------------------------------------------------------
1 | import { AlarmWidget, IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | import { IWidgetFactory } from "./IWidgetFactory";
4 | import {
5 | AlarmWithAnnotation,
6 | DefaultAlarmWidgetHeight,
7 | DefaultAlarmWidgetWidth,
8 | } from "../common";
9 |
10 | export class DefaultWidgetFactory implements IWidgetFactory {
11 | createAlarmDetailWidget(alarm: AlarmWithAnnotation): IWidget {
12 | return new AlarmWidget({
13 | alarm: alarm.alarm,
14 | title: alarm.alarmLabel,
15 | width: DefaultAlarmWidgetWidth,
16 | height: DefaultAlarmWidgetHeight,
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/dashboard/DynamicDashboardSegment.ts:
--------------------------------------------------------------------------------
1 | import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 | import { DefaultDashboards } from "./DefaultDashboardFactory";
3 | import { IDashboardFactoryProps } from "./IDashboardFactory";
4 |
5 | export interface IDynamicDashboardSegment {
6 | /**
7 | * Returns widgets for the requested dashboard type.
8 | * @param name name of dashboard for which widgets are generated.
9 | */
10 | widgetsForDashboard(name: string): IWidget[];
11 | }
12 |
13 | export class StaticSegmentDynamicAdapter implements IDynamicDashboardSegment {
14 | protected readonly props: IDashboardFactoryProps;
15 |
16 | constructor(props: IDashboardFactoryProps) {
17 | this.props = props;
18 | }
19 |
20 | /**
21 | * Adapts an IDashboardSegment to the IDynamicDashboardSegment interface by using
22 | * overrideProps to determine if a segment should be shown on a specific dashboard.
23 | * The default values are true, so consumers must set these to false if they would
24 | * like to hide these items from dashboards
25 | */
26 | widgetsForDashboard(name: string): IWidget[] {
27 | const overrideProps = this.props.overrideProps;
28 | const addToDetailDashboard = overrideProps?.addToDetailDashboard ?? true;
29 | const addToSummaryDashboard = overrideProps?.addToSummaryDashboard ?? true;
30 | const addToAlarmsDashboard = overrideProps?.addToAlarmDashboard ?? true;
31 | if (addToDetailDashboard && name === DefaultDashboards.DETAIL) {
32 | return this.props.segment.widgets();
33 | }
34 | if (addToSummaryDashboard && name === DefaultDashboards.SUMMARY) {
35 | return this.props.segment.summaryWidgets();
36 | }
37 | if (addToAlarmsDashboard && name === DefaultDashboards.ALARMS) {
38 | return this.props.segment.alarmWidgets();
39 | }
40 | return [];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/dashboard/IDashboardFactory.ts:
--------------------------------------------------------------------------------
1 | import { Dashboard } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | import { IDashboardSegment } from "./DashboardSegment";
4 |
5 | export interface MonitoringDashboardsOverrideProps {
6 | /**
7 | * Flag indicating if the widgets should be added to detailed dashboard
8 | *
9 | * @default - true
10 | */
11 | readonly addToDetailDashboard?: boolean;
12 | /**
13 | * Flag indicating if the widgets should be added to summary dashboard
14 | *
15 | * @default - true
16 | */
17 | readonly addToSummaryDashboard?: boolean;
18 | /**
19 | * Flag indicating if the widgets should be added to alarm dashboard
20 | *
21 | * @default - true
22 | */
23 | readonly addToAlarmDashboard?: boolean;
24 | }
25 |
26 | export interface IDashboardFactoryProps {
27 | /**
28 | * Segment to be placed on the dashboard.
29 | */
30 | segment: IDashboardSegment;
31 | /**
32 | * Dashboard placement override props.
33 | *
34 | * @default - all default
35 | */
36 | overrideProps?: MonitoringDashboardsOverrideProps;
37 | }
38 |
39 | export interface IDashboardFactory {
40 | addSegment(props: IDashboardFactoryProps): void;
41 |
42 | createdDashboard(): Dashboard | undefined;
43 |
44 | createdSummaryDashboard(): Dashboard | undefined;
45 |
46 | createdAlarmDashboard(): Dashboard | undefined;
47 | }
48 |
--------------------------------------------------------------------------------
/lib/dashboard/IDynamicDashboardFactory.ts:
--------------------------------------------------------------------------------
1 | import { Dashboard } from "aws-cdk-lib/aws-cloudwatch";
2 | import { IDynamicDashboardSegment } from "./DynamicDashboardSegment";
3 |
4 | /**
5 | * This dashboard factory interface provides for dynamic dashboard generation through
6 | * IDynamicDashboard segments which will return different content depending on the
7 | * dashboard type.
8 | */
9 | export interface IDynamicDashboardFactory {
10 | /**
11 | * Adds a dynamic dashboard segment.
12 | * @param segment IDynamicDashboardSegment
13 | */
14 | addDynamicSegment(segment: IDynamicDashboardSegment): void;
15 |
16 | /**
17 | * Gets the dashboard for the requested dashboard type.
18 | * @param type
19 | */
20 | getDashboard(type: string): Dashboard | undefined;
21 | }
22 |
--------------------------------------------------------------------------------
/lib/dashboard/IWidgetFactory.ts:
--------------------------------------------------------------------------------
1 | import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | import { AlarmWithAnnotation } from "../common/alarm";
4 |
5 | /**
6 | * Strategy for creating widgets.
7 | */
8 | export interface IWidgetFactory {
9 | /**
10 | * Create widget representing an alarm detail.
11 | * @param alarm alarm to represent
12 | */
13 | createAlarmDetailWidget(alarm: AlarmWithAnnotation): IWidget;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/dashboard/SingleWidgetDashboardSegment.ts:
--------------------------------------------------------------------------------
1 | import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
2 | import { IDashboardSegment } from "./DashboardSegment";
3 | import { DefaultDashboards } from "./DefaultDashboardFactory";
4 | import { IDynamicDashboardSegment } from "./DynamicDashboardSegment";
5 |
6 | export class SingleWidgetDashboardSegment
7 | implements IDashboardSegment, IDynamicDashboardSegment
8 | {
9 | protected readonly widget: IWidget;
10 | protected readonly dashboardsToInclude: string[];
11 |
12 | /**
13 | * Create a dashboard segment representing a single widget.
14 | * @param widget widget to add
15 | * @param dashboardsToInclude list of dashboard names which to show this widget on. Defaults to the default dashboards.
16 | */
17 | constructor(widget: IWidget, dashboardsToInclude?: string[]) {
18 | this.widget = widget;
19 | this.dashboardsToInclude = dashboardsToInclude ?? [
20 | DefaultDashboards.ALARMS,
21 | DefaultDashboards.DETAIL,
22 | DefaultDashboards.SUMMARY,
23 | ];
24 | }
25 |
26 | widgetsForDashboard(name: string): IWidget[] {
27 | if (this.dashboardsToInclude.includes(name)) {
28 | return [this.widget];
29 | } else {
30 | return [];
31 | }
32 | }
33 |
34 | alarmWidgets(): IWidget[] {
35 | if (this.dashboardsToInclude.includes(DefaultDashboards.ALARMS)) {
36 | return [this.widget];
37 | } else {
38 | return [];
39 | }
40 | }
41 |
42 | summaryWidgets(): IWidget[] {
43 | if (this.dashboardsToInclude.includes(DefaultDashboards.SUMMARY)) {
44 | return [this.widget];
45 | } else {
46 | return [];
47 | }
48 | }
49 |
50 | widgets(): IWidget[] {
51 | if (this.dashboardsToInclude.includes(DefaultDashboards.DETAIL)) {
52 | return [this.widget];
53 | } else {
54 | return [];
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/dashboard/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./BitmapDashboard";
2 | export * from "./DashboardRenderingPreference";
3 | export * from "./DynamicDashboardSegment";
4 | export * from "./DashboardSegment";
5 | export * from "./DashboardWithBitmapCopy";
6 | export * from "./DefaultDashboardFactory";
7 | export * from "./DynamicDashboardFactory";
8 | export * from "./DefaultWidgetFactory";
9 | export * from "./IDashboardFactory";
10 | export * from "./IDynamicDashboardFactory";
11 | export * from "./IWidgetFactory";
12 | export * from "./MonitoringNamingStrategy";
13 | export * from "./SingleWidgetDashboardSegment";
14 | export * from "./widget";
15 |
--------------------------------------------------------------------------------
/lib/dashboard/widget/AlarmMatrixWidget.ts:
--------------------------------------------------------------------------------
1 | import { AlarmStatusWidget, IAlarm } from "aws-cdk-lib/aws-cloudwatch";
2 |
3 | import { FullWidth } from "../../common/widget";
4 |
5 | const AlarmsPerRow = 6;
6 | const MinHeight = 2;
7 | const MaxHeight = 8;
8 |
9 | export interface AlarmMatrixWidgetProps {
10 | /**
11 | * widget title
12 | * @default - no title
13 | */
14 | readonly title?: string;
15 | /**
16 | * desired height
17 | * @default - auto calculated based on alarm number (3 to 8)
18 | */
19 | readonly height?: number;
20 | /**
21 | * list of alarms to show
22 | */
23 | readonly alarms: IAlarm[];
24 | }
25 |
26 | /**
27 | * Wrapper of Alarm Status Widget which auto-calcultes height based on the number of alarms.
28 | * Always takes the maximum width.
29 | */
30 | export class AlarmMatrixWidget extends AlarmStatusWidget {
31 | constructor(props: AlarmMatrixWidgetProps) {
32 | super({
33 | alarms: props.alarms,
34 | title: props.title,
35 | width: FullWidth,
36 | height:
37 | props.height ??
38 | AlarmMatrixWidget.getRecommendedHeight(props.alarms.length),
39 | });
40 | }
41 |
42 | private static getRecommendedHeight(numAlarms: number) {
43 | const rows = Math.ceil(numAlarms / AlarmsPerRow);
44 | if (rows < MinHeight) {
45 | return MinHeight;
46 | }
47 | if (rows > MaxHeight) {
48 | return MaxHeight;
49 | }
50 | return rows;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/dashboard/widget/BitmapWidget.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 |
3 | import { Duration, Tags } from "aws-cdk-lib";
4 | import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
5 | import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
6 | import {
7 | Code,
8 | determineLatestNodeRuntime,
9 | Function,
10 | IFunction,
11 | } from "aws-cdk-lib/aws-lambda";
12 | import { RetentionDays } from "aws-cdk-lib/aws-logs";
13 | import { Construct } from "constructs";
14 |
15 | import { CustomWidget } from "./CustomWidget";
16 |
17 | /**
18 | * Support for rendering bitmap widgets on the server side.
19 | * It is a custom widget lambda with some additional roles and helper methods.
20 | */
21 | export class BitmapWidgetRenderingSupport extends Construct {
22 | readonly handler: IFunction;
23 |
24 | constructor(scope: Construct, id: string) {
25 | super(scope, id);
26 |
27 | this.handler = new Function(this, "Lambda", {
28 | code: Code.fromAsset(
29 | path.join(
30 | __dirname,
31 | "..",
32 | "..",
33 | "..",
34 | "assets",
35 | "BitmapWidgetRenderingSupport",
36 | ),
37 | ),
38 | description:
39 | "Custom Widget Render for Bitmap Widgets (cdk-monitoring-constructs)",
40 | handler: "index.handler",
41 | memorySize: 128,
42 | runtime: determineLatestNodeRuntime(this),
43 | timeout: Duration.seconds(60),
44 | logRetention: RetentionDays.ONE_DAY,
45 | });
46 |
47 | this.handler.addToRolePolicy(
48 | new PolicyStatement({
49 | actions: ["cloudwatch:GetMetricWidgetImage"],
50 | effect: Effect.ALLOW,
51 | resources: ["*"],
52 | }),
53 | );
54 |
55 | Tags.of(this.handler).add("cw-custom-widget", "describe:readOnly");
56 | }
57 |
58 | asBitmap(widget: IWidget) {
59 | const props = this.getWidgetProperties(widget);
60 | // remove the title from the graph and remember it
61 | const { title, ...graph } = props;
62 |
63 | return new CustomWidget({
64 | // move the original title here
65 | title,
66 | width: widget.width,
67 | height: widget.height,
68 | // empty the inner title since we already have it on the whole widget
69 | handlerParams: { graph: { ...graph, title: " " } },
70 | handler: this.handler,
71 | updateOnRefresh: true,
72 | updateOnResize: true,
73 | updateOnTimeRangeChange: true,
74 | });
75 | }
76 |
77 | protected getWidgetProperties(widget: IWidget): any {
78 | const graphs = widget.toJson();
79 | if (graphs.length != 1) {
80 | throw new Error(
81 | "Number of objects in the widget definition must be exactly one.",
82 | );
83 | }
84 | const graph = graphs[0];
85 | if (!graph.properties) {
86 | throw new Error("No graph properties: " + graph);
87 | }
88 | return graph.properties;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/lib/dashboard/widget/CustomWidget.ts:
--------------------------------------------------------------------------------
1 | import { ConcreteWidget } from "aws-cdk-lib/aws-cloudwatch";
2 | import { IFunction } from "aws-cdk-lib/aws-lambda";
3 |
4 | /**
5 | * Properties of a custom widget.
6 | */
7 | export interface CustomWidgetProps {
8 | /**
9 | * Title for the graph
10 | */
11 | readonly title?: string;
12 | /**
13 | * Width of the widget, in a grid of 24 units wide
14 | *
15 | * @default - 6
16 | */
17 | readonly width?: number;
18 | /**
19 | * Height of the widget
20 | *
21 | * @default - 6
22 | */
23 | readonly height?: number;
24 | /**
25 | * Lambda providing the widget contents.
26 | * The Lambda function should return HTML with widget code.
27 | * The simplest Lambda example:
28 | * ```typescript
29 | * exports.handler = function (event, context, callback) {
30 | * return callback(null, "
" + JSON.stringify(event, null, 2) + ""); 31 | * }; 32 | * ``` 33 | */ 34 | readonly handler: IFunction; 35 | /** 36 | * Arguments to pass to the Lambda. 37 | * These arguments will be available in the Lambda context. 38 | */ 39 | readonly handlerParams?: any; 40 | /** 41 | * Whether the widget should be updated (by calling the Lambda again) on refresh. 42 | * 43 | * @default - true 44 | */ 45 | readonly updateOnRefresh?: boolean; 46 | /** 47 | * Whether the widget should be updated (by calling the Lambda again) on resize. 48 | * 49 | * @default - true 50 | */ 51 | readonly updateOnResize?: boolean; 52 | /** 53 | * Whether the widget should be updated (by calling the Lambda again) on time range change. 54 | * 55 | * @default - true 56 | */ 57 | readonly updateOnTimeRangeChange?: boolean; 58 | } 59 | 60 | /** 61 | * A dashboard widget that can be customized using a Lambda. 62 | */ 63 | export class CustomWidget extends ConcreteWidget { 64 | private readonly props: CustomWidgetProps; 65 | 66 | constructor(props: CustomWidgetProps) { 67 | super(props.width || 6, props.height || 6); 68 | this.props = props; 69 | } 70 | 71 | toJson(): any[] { 72 | return [ 73 | { 74 | type: "custom", 75 | width: this.width, 76 | height: this.height, 77 | x: this.x, 78 | y: this.y, 79 | properties: { 80 | title: this.props.title, 81 | endpoint: this.props.handler.functionArn, 82 | params: this.props.handlerParams || {}, 83 | updateOn: { 84 | refresh: this.props.updateOnRefresh ?? true, 85 | resize: this.props.updateOnResize ?? true, 86 | timeRange: this.props.updateOnTimeRangeChange ?? true, 87 | }, 88 | }, 89 | }, 90 | ]; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/dashboard/widget/HeaderWidget.ts: -------------------------------------------------------------------------------- 1 | import { TextWidget } from "aws-cdk-lib/aws-cloudwatch"; 2 | 3 | import { FullWidth } from "../../common/widget"; 4 | 5 | export enum HeaderLevel { 6 | LARGE, 7 | MEDIUM, 8 | SMALL, 9 | } 10 | 11 | export class HeaderWidget extends TextWidget { 12 | constructor( 13 | text: string, 14 | level?: HeaderLevel, 15 | description?: string, 16 | descriptionHeight?: number, 17 | ) { 18 | super({ 19 | width: FullWidth, 20 | height: HeaderWidget.calculateHeight(description, descriptionHeight), 21 | markdown: HeaderWidget.toMarkdown( 22 | text, 23 | level ?? HeaderLevel.LARGE, 24 | description, 25 | ), 26 | }); 27 | } 28 | 29 | private static calculateHeight( 30 | description?: string, 31 | descriptionHeight?: number, 32 | ) { 33 | let result = 1; 34 | if (description) { 35 | result += descriptionHeight ?? 1; 36 | } 37 | return result; 38 | } 39 | 40 | private static toMarkdown( 41 | text: string, 42 | level: HeaderLevel, 43 | description?: string, 44 | ) { 45 | const parts = [this.toHeaderMarkdown(text, level)]; 46 | if (description) { 47 | parts.push(description); 48 | } 49 | return parts.join("\n\n"); 50 | } 51 | 52 | private static toHeaderMarkdown(text: string, level: HeaderLevel) { 53 | return "#".repeat(level + 1) + " " + text; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/dashboard/widget/KeyValueTableWidget.ts: -------------------------------------------------------------------------------- 1 | import { KeyValueTableWidgetV2 } from "./KeyValueTableWidgetV2"; 2 | 3 | /** 4 | * @deprecated Use {@link KeyValueTableWidgetV2} instead. 5 | */ 6 | export class KeyValueTableWidget extends KeyValueTableWidgetV2 { 7 | constructor(data: [string, string][]) { 8 | super(data.map(([key, value]) => ({ key, value }))); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/dashboard/widget/KeyValueTableWidgetV2.ts: -------------------------------------------------------------------------------- 1 | import { TextWidget } from "aws-cdk-lib/aws-cloudwatch"; 2 | 3 | import { FullWidth } from "../../common/widget"; 4 | 5 | export interface KeyValue { 6 | readonly key: string; 7 | readonly value: string; 8 | } 9 | 10 | export class KeyValueTableWidgetV2 extends TextWidget { 11 | constructor(data: KeyValue[]) { 12 | super({ 13 | width: FullWidth, 14 | height: 3, 15 | markdown: KeyValueTableWidgetV2.toMarkdown(data), 16 | }); 17 | } 18 | 19 | private static toMarkdown(data: KeyValue[]) { 20 | let headerRow = ""; 21 | let subHeaderRow = ""; 22 | let valueRow = ""; 23 | 24 | data.forEach(({ key, value }) => { 25 | headerRow += "| " + key; 26 | subHeaderRow += "|---"; 27 | valueRow += "| " + value; 28 | }); 29 | 30 | return `${headerRow}\n${subHeaderRow}\n${valueRow}`; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/dashboard/widget/MonitoringHeaderWidget.ts: -------------------------------------------------------------------------------- 1 | import { HeaderLevel, HeaderWidget } from "./HeaderWidget"; 2 | 3 | export interface MonitoringHeaderWidgetProps { 4 | readonly title: string; 5 | readonly family?: string; 6 | readonly goToLinkUrl?: string; 7 | readonly description?: string; 8 | readonly descriptionHeight?: number; 9 | } 10 | 11 | export class MonitoringHeaderWidget extends HeaderWidget { 12 | constructor(props: MonitoringHeaderWidgetProps) { 13 | super( 14 | MonitoringHeaderWidget.getText(props), 15 | HeaderLevel.SMALL, 16 | props.description, 17 | props.descriptionHeight, 18 | ); 19 | } 20 | 21 | private static getText(props: MonitoringHeaderWidgetProps): string { 22 | let title = props.title; 23 | 24 | if (props.goToLinkUrl) { 25 | title = `[${title}](${props.goToLinkUrl})`; 26 | } 27 | 28 | if (props.family) { 29 | title = `${props.family} **${title}**`; 30 | } 31 | 32 | return title; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/dashboard/widget/UnofficialWidgets.ts: -------------------------------------------------------------------------------- 1 | import { ConcreteWidget, MetricWidgetProps } from "aws-cdk-lib/aws-cloudwatch"; 2 | 3 | import { FullWidth } from "../../common/widget"; 4 | 5 | export interface AlarmSummaryMatrixWidgetProps extends MetricWidgetProps { 6 | readonly alarmArns: string[]; 7 | } 8 | 9 | export interface AlarmSummaryMatrixWidgetPropertiesJson { 10 | readonly title?: string; 11 | readonly alarms: string[]; 12 | } 13 | 14 | export class AlarmSummaryMatrixWidget extends ConcreteWidget { 15 | protected readonly props: AlarmSummaryMatrixWidgetProps; 16 | 17 | constructor(props: AlarmSummaryMatrixWidgetProps) { 18 | super(props.width ?? FullWidth, props.height ?? 2); 19 | this.props = props; 20 | } 21 | 22 | toJson(): any[] { 23 | return [ 24 | { 25 | type: "alarm", 26 | width: this.width, 27 | height: this.height, 28 | x: this.x, 29 | y: this.y, 30 | properties: { 31 | title: this.props.title, 32 | alarms: this.props.alarmArns, 33 | }, 34 | }, 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/dashboard/widget/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./AlarmMatrixWidget"; 2 | export * from "./BitmapWidget"; 3 | export * from "./CustomWidget"; 4 | export * from "./HeaderWidget"; 5 | export * from "./KeyValueTableWidget"; 6 | export * from "./KeyValueTableWidgetV2"; 7 | export * from "./MonitoringHeaderWidget"; 8 | export * from "./StrictGraphWidget"; 9 | export * from "./UnofficialWidgets"; 10 | -------------------------------------------------------------------------------- /lib/facade/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./IMonitoringAspect"; 2 | export * from "./MonitoringFacade"; 3 | export * from "./MonitoringAspect"; 4 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./common"; 2 | export * from "./dashboard"; 3 | export * from "./facade"; 4 | export * from "./monitoring"; 5 | -------------------------------------------------------------------------------- /lib/monitoring/aws-acm/CertificateManagerMetricFactory.ts: -------------------------------------------------------------------------------- 1 | import { ICertificate } from "aws-cdk-lib/aws-certificatemanager"; 2 | import { DimensionsMap } from "aws-cdk-lib/aws-cloudwatch"; 3 | 4 | import { 5 | BaseMetricFactory, 6 | BaseMetricFactoryProps, 7 | MetricFactory, 8 | MetricStatistic, 9 | MetricWithAlarmSupport, 10 | } from "../../common"; 11 | 12 | const Namespace = "AWS/CertificateManager"; 13 | 14 | export interface CertificateManagerMetricFactoryProps 15 | extends BaseMetricFactoryProps { 16 | readonly certificate: ICertificate; 17 | } 18 | 19 | export class CertificateManagerMetricFactory extends BaseMetricFactory