Package: cdk-monitoring-constructs
CDK Monitoring ConstructsEasy-to-use CDK constructs for monitoring your AWS infrastructure withAmazon CloudWatch.Easily add commonly-used alarms using predefined propertiesGenerate concise CloudWatch dashboards that indicate your alarmsExtend the library with your own extensions or custom metricsConsume the library in multiple supported languagesInstallationTypeScripthttps://www.npmjs.com/package/cdk-monitoring-constructsIn yourpackage.json:{"dependencies":{"cdk-monitoring-constructs":"^7.0.0",// peer dependencies of cdk-monitoring-constructs"@aws-cdk/aws-redshift-alpha":"^2.112.0-alpha.0","aws-cdk-lib":"^2.112.0","constructs":"^10.0.5"// ...your other dependencies...}}JavaSeehttps://mvnrepository.com/artifact/io.github.cdklabs/cdkmonitoringconstructsPythonSeehttps://pypi.org/project/cdk-monitoring-constructs/C#Seehttps://www.nuget.org/packages/Cdklabs.CdkMonitoringConstructs/FeaturesYou can browse the documentation athttps://constructs.dev/packages/cdk-monitoring-constructs/ItemMonitoringAlarmsNotesAWS API Gateway (REST API) (.monitorApiGateway())TPS, latency, errorsLatency, error count/rate, low/high TPSTo see metrics, you have to enable Advanced MonitoringAWS API Gateway V2 (HTTP API) (.monitorApiGatewayV2HttpApi())TPS, latency, errorsLatency, error count/rate, low/high TPSTo see route level metrics, you have to enable Advanced MonitoringAWS AppSync (GraphQL API) (.monitorAppSyncApi())TPS, latency, errorsLatency, error count/rate, low/high TPSAmazon Aurora (.monitorAuroraCluster())Query duration, connections, latency, CPU usage, Serverless Database CapacityConnections, Serverless Database Capacity and CPU usageAWS Billing (.monitorBilling())AWS account costTotal cost (anomaly)Requires enablingtheReceive Billing Alertsoption in AWS Console / Billing PreferencesAWS Certificate Manager (.monitorCertificate())Certificate expirationDays until expirationAWS CloudFront (.monitorCloudFrontDistribution())TPS, traffic, latency, errorsError rate, low/high TPSAWS CloudWatch Logs (.monitorLog())Patterns present in the log groupMinimum incoming logsAWS CloudWatch Synthetics Canary (.monitorSyntheticsCanary())Latency, error count/rateError count/rate, latencyAWS CodeBuild (.monitorCodeBuildProject())Build counts (total, successful, failed), failed rate, durationFailed build count/rate, durationAWS DocumentDB (.monitorDocumentDbCluster())CPU, throttling, read/write latency, transactions, cursorsCPUAWS DynamoDB (.monitorDynamoTable())Read and write capacity provisioned / usedConsumed capacity, throttling, latency, errorsAWS DynamoDB Global Secondary Index (.monitorDynamoTableGlobalSecondaryIndex())Read and write capacity, indexing progress, throttled eventsAWS EC2 (.monitorEC2Instances())CPU, disk operations, networkAWS EC2 Auto Scaling Groups (.monitorAutoScalingGroup())Group size, instance statusAWS ECS (.monitorFargateService(),.monitorEc2Service(),.monitorSimpleFargateService(),monitorSimpleEc2Service(),.monitorQueueProcessingFargateService(),.monitorQueueProcessingEc2Service())System resources and task healthUnhealthy task count, running tasks count, CPU/memory usage, and bytes processed by load balancer (if any)Use for ecs-patterns load balanced ec2/fargate constructs (NetworkLoadBalancedEc2Service, NetworkLoadBalancedFargateService, ApplicationLoadBalancedEc2Service, ApplicationLoadBalancedFargateService)AWS ElastiCache (.monitorElastiCacheCluster())CPU/memory usage, evictions and connectionsCPU, memory, items countAWS Glue (.monitorGlueJob())Traffic, job status, memory/CPU usageFailed/killed task count/rateAWS Kinesis Data Analytics (.monitorKinesisDataAnalytics)Up/Downtime, CPU/memory usage, KPU usage, checkpoint metrics, and garbage collection metricsDowntime, full restart countAWS Kinesis Data Stream (.monitorKinesisDataStream())Put/Get/Incoming Record/s and ThrottlingThrottling, throughput, iterator max ageAWS Kinesis Firehose (.monitorKinesisFirehose())Number of records, requests, latency, throttlingThrottlingAWS Lambda (.monitorLambdaFunction())Latency, errors, iterator max ageLatency, errors, throttles, iterator max ageOptional Lambda Insights metrics (opt-in) supportAWS Load Balancing (.monitorNetworkLoadBalancer(),.monitorFargateApplicationLoadBalancer(),.monitorFargateNetworkLoadBalancer(),.monitorEc2ApplicationLoadBalancer(),.monitorEc2NetworkLoadBalancer())System resources and task healthUnhealthy task count, running tasks count, (for Fargate/Ec2 apps) CPU/memory usageUse for FargateService or Ec2Service backed by a NetworkLoadBalancer or ApplicationLoadBalancerAWS OpenSearch/Elasticsearch (.monitorOpenSearchCluster(),.monitorElasticsearchCluster())Indexing and search latency, disk/memory/CPU usageIndexing and search latency, disk/memory/CPU usage, cluster status, KMS keysAWS RDS (.monitorRdsCluster())Query duration, connections, latency, disk/CPU usageConnections, disk and CPU usageAWS RDS (.monitorRdsInstance())Query duration, connections, latency, disk/CPU usageConnections, disk and CPU usageAWS Redshift (.monitorRedshiftCluster())Query duration, connections, latency, disk/CPU usageQuery duration, connections, disk and CPU usageAWS S3 Bucket (.monitorS3Bucket())Bucket size and number of objectsAWS SecretsManager (.monitorSecretsManager())Max secret count, min secret sount, secret count changeMin/max secret count or change in secret countAWS SecretsManager Secret (.monitorSecretsManagerSecret())Days since last rotationDays since last change or rotationAWS SNS Topic (.monitorSnsTopic())Message count, size, failed notificationsFailed notifications, min/max published messagesAWS SQS Queue (.monitorSqsQueue(),.monitorSqsQueueWithDlq())Message count, age, sizeMessage count, age, DLQ incoming messagesAWS Step Functions (.monitorStepFunction(),.monitorStepFunctionActivity(),monitorStepFunctionLambdaIntegration(),.monitorStepFunctionServiceIntegration())Execution count and breakdown per stateDuration, failed, failed rate, aborted, throttled, timed out executionsAWS Web Application Firewall (.monitorWebApplicationFirewallAclV2())Allowed/blocked requestsBlocked requests count/rateFluentBit (.monitorFluentBit())Num of input records, Output failures & retries, Filter metrics, Storage metricsFluentBit needs proper configuration with  metrics enabled:Official sample configuration. This function creates MetricFilters to publish all FluentBit metrics.Custom metrics (.monitorCustom())Addition of custom metrics into the dashboard (each group is a widget)Supports anomaly detectionGetting startedCreate a facadeImportant note:Please, do NOT import anything from the/dist/libpackage.This is unsupported and might break any time.Create an instance ofMonitoringFacade, which is the main entrypoint.Call methods on the facade like.monitorLambdaFunction()and chain them together to define your monitors. You can also use methods to add your own widgets, headers of various sizes, and more.For examples of monitoring different resources, refer tothe unit tests.exportinterfaceMonitoringStackPropsextendsDeploymentStackProps{//...}//Thiscouldbeinthesamestackasyourresources,asanestedstack,oraseparatestackasyouseefitexportclassMonitoringStackextendsDeploymentStack{constructor(parent:App,name:string,props:MonitoringStackProps){super(parent,name,props);constmonitoring=newMonitoringFacade(this,"Monitoring",{//Defaultsareprovidedforthese,buttheycanbecustomizedasdesiredmetricFactoryDefaults:{...},alarmFactoryDefaults:{...},dashboardFactory:{...},});//Monitoryourresourcesmonitoring.addLargeHeader("Storage").monitorDynamoTable({/*MonitoraDynamoDBtable*/}).monitorDynamoTable({/*andadifferenttable*/}).monitorLambdaFunction({/*andaLambdafunction*/}).monitorCustom({/*andsomearbitrarymetricsinCloudWatch*/})//...etc.}}Customize actionsAlarms should have an action setup, otherwise they are not very useful. Currently, we support notifying an SNS topic.constonAlarmTopic=newTopic(this,"AlarmTopic");constmonitoring=newMonitoringFacade(this,"Monitoring",{//...otherpropsalarmFactoryDefaults:{//....otherpropsaction:newSnsAlarmActionStrategy({onAlarmTopic}),},});You can override the default topic for any alarm like this:monitoring.monitorSomething(something,{addSomeAlarm:{Warning:{//...otherpropsthreshold:42,actionOverride:newSnsAlarmActionStrategy({onAlarmTopic}),}}});Custom metricsFor simply adding some custom metrics, you can use.monitorCustom()and specify your own title and metric groups.
Each metric group will be rendered as a single graph widget, and all widgets will be placed next to each other.
All the widgets will have the same size, which is chosen based on the number of groups to maximize dashboard space usage.Custom metric monitoring can be created for simple metrics, simple metrics with anomaly detection and search metrics.
The first two also support alarming.Below we are listing a couple of examples. Let us assume that there are three existing metric variables:m1,m2,m3.
They can either be created by hand (new Metric({...})) or (preferably) by usingmetricFactory(that can be obtained from facade).
The advantage of using the sharedmetricFactoryis that you do not need to worry about period, etc.//createmetricsmanuallyconstm1=newMetric(/*...*/);constmetricFactory=monitoringFacade.createMetricFactory();//createmetricsusingmetricfactoryconstm1=metricFactory.createMetric(/*...*/);Example: metric with anomaly detectionIn this case, only one metric is supported.
Multiple metrics cannot be rendered with anomaly detection in a single widget due to a CloudWatch limitation.monitorCustom({title:"Metric with anomaly detection",metrics:[{metric:m1,anomalyDetectionStandardDeviationToRender:3}]})Adding an alarm:monitorCustom({title:"Metric with anomaly detection and alarm",metrics:[{metric:m1,alarmFriendlyName:"MetricWithAnomalyDetectionAlarm",anomalyDetectionStandardDeviationToRender:3,addAlarmOnAnomaly:{Warning:{standardDeviationForAlarm:4,alarmWhenAboveTheBand:true,alarmWhenBelowTheBand:true}}}]})Example: search metricsmonitorCustom({title:"Metric search",metrics:[{searchQuery:"My.Prefix.",dimensionsMap:{FirstDimension:"FirstDimensionValue",//Allowanyvalueforthegivendimension(pardontheweirdtypingtosatisfyDimensionsMap)SecondDimension:undefinedasunknownasstring}statistic:MetricStatistic.SUM,}]})Search metrics do not support setting an alarm, which is a CloudWatch limitation.Route53 Health ChecksRoute53 hasstrict requirementsas to which alarms are allowed to be referenced in Health Checks.
You adjust the metric for an alarm so that it can be used in a Route53 Health Checks as follows:monitoring.monitorSomething(something,{addSomeAlarm:{Warning:{//...otherpropsmetricAdjuster:Route53HealthCheckMetricAdjuster.INSTANCE,}}});This will ensure the alarm can be used on a Route53 Health Check or otherwise throw anErrorindicating why the alarm can't be used.
In order to easily find your Route53 Health Check alarms later on, you can apply a custom tag to them as follows:import{CfnHealthCheck}from"aws-cdk-lib/aws-route53";monitoring.monitorSomething(something,{addSomeAlarm:{Warning:{//...otherpropscustomTags:["route53-health-check"],metricAdjuster:Route53HealthCheckMetricAdjuster.INSTANCE,}}});constalarms=monitoring.createdAlarmsWithTag("route53-health-check");consthealthChecks=alarms.map(({alarm})=>{constid=getHealthCheckConstructId(alarm);returnnewCfnHealthCheck(scope,id,{healthCheckConfig:{//...otherpropstype:"CLOUDWATCH_METRIC",alarmIdentifier:{name:alarm.alarmName,region:alarm.stack.region,},},});});Custom monitoring segmentsIf you want even more flexibility, you can create your own segment.This is a general procedure on how to do it:Extend theMonitoringclassOverride thewidgets()method (and/or similar ones)Leverage the metric factory and alarm factory provided by the base class (you can create additional factories, if you will)Add all alarms to.addAlarm()so they are visible to the user and being placed on the alarm summary dashboardBoth of these monitoring base classes are dashboard segments, so you can add them to your monitoring by calling.addSegment()on theMonitoringFacade.Modifying or omitting widgets from default dashboard segmentsWhile the dashboard widgets defined in the library are meant to cover most use cases, they might not be what you're looking for.To modify the widgets:Extend the appropriateMonitoringclass (e.g.,LambdaFunctionMonitoringformonitorLambdaFunction) and override the relevant methods (e.g.,widgets):exportclassMyCustomizedLambdaFunctionMonitoringextendsLambdaFunctionMonitoring{widgets():IWidget[]{return[//WhateverwidgetsyouwantinsteadofwhatLambdaFunctionMonitoringhas];}}Use the facade'saddSegmentmethod with your custom class:declareconstfacade:MonitoringFacade;facade.addSegment(newMyCustomizedLambdaFunctionMonitoring(facade,{//PropsforLambdaFunctionMonitoring}));Custom dashboardsIf you wantevenmore flexibility, you can take complete control over dashboard generation by leveraging dynamic dashboarding features. This allows you to create an arbitrary number of dashboards while configuring each of them separately. You can do this in three simple steps:Create a dynamic dashboard factoryCreateIDynamicDashboardSegmentimplementationsAdd Dynamic Segments to yourMonitoringFacadeCreate a dynamic dashboard factoryThe below code sample will generate two dashboards with the following names:ExampleDashboards-HostedServiceExampleDashboards-Infrastructure//createthedynamicdashboardfactory.constfactory=newDynamicDashboardFactory(stack,"DynamicDashboards",{dashboardNamePrefix:"ExampleDashboards",dashboardConfigs:[//'name'istheminimumrequiredconfiguration{name:"HostedService"},//belowisanexampleofadditionaldashboard-specificconfigoptions{name:"Infrastructure",range:Duration.hours(3),periodOverride:PeriodOverride.AUTO,renderingPreference:DashboardRenderingPreference.BITMAP_ONLY},],});CreateIDynamicDashboardSegmentimplementationsFor each construct you want monitored, you will need to create an implementation of anIDynamicDashboardSegment. The following is a basic reference implementation as an example:exportenumDashboardTypes{HostedService="HostedService",Infrastructure="Infrastructure",}classExampleSegmentimplementsIDynamicDashboardSegment{widgetsForDashboard(name:string):IWidget[]{//thislogiciswhat's responsible for allowing your dynamic segment to return//differentwidgetsfordifferentdashboardsswitch(name){caseDashboardTypes.HostedService:return[newTextWidget({markdown:"This shows metrics for your service hosted on AWS Infrastructure"})];caseDashboardTypes.Infrastructure:return[newTextWidget({markdown:"This shows metrics for the AWS Infrastructure supporting your hosted service"})];default:thrownewError("Unexpected dashboard name!");}}}Add Dynamic Segments to MonitoringFacadeWhen you have instances of anIDynamicDashboardSegmentto use, they can be added to your dashboard like this:monitoring.addDynamicSegment(newExampleSegment());Now, this widget will be added to both dashboards and will show different content depending on the dashboard. Using the above example code, two dashboards will be generated with the following content:Dashboard Name: "ExampleDashboards-HostedService"Content: "This shows metrics for your service hosted on AWS Infrastructure"Dashboard Name: "ExampleDashboards-Infrastructure"Content: "This shows metrics for the AWS Infrastructure supporting your hosted service"Monitoring scopesYou can monitor complete CDK construct scopes using an aspect. It will automatically discover all monitorable resources within the scope recursively and add them to your dashboard.monitoring.monitorScope(stack,{//Withoptionalconfigurationlambda:{props:{addLatencyP50Alarm:{Critical:{maxLatency:Duration.seconds(10)},},},},//Someresourcesthataren't dependent on nodes (e.g. general metrics across instances/account) may be included//bydefault,whichcanbeexplicitlydisabled.billing:{enabled:false},ec2:{enabled:false},elasticCache:{enabled:false},});ContributingSeeCONTRIBUTINGfor more information.Security policySeeSECURITYfor more information.LicenseThis project is licensed under the Apache-2.0 License.