Skip to content

Commit

Permalink
feat: adding monitoring support for CloudWatch Canary (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
voho authored Mar 15, 2022
1 parent a14bc1a commit 7460d4e
Show file tree
Hide file tree
Showing 13 changed files with 1,844 additions and 4 deletions.
665 changes: 664 additions & 1 deletion API.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ You can also browse the documentation at https://constructs.dev/packages/cdk-mon
| AWS Billing (`.monitorBilling()`) | AWS account cost | | [Requires enabling](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/gs_monitor_estimated_charges_with_cloudwatch.html#gs_turning_on_billing_metrics) the **Receive Billing Alerts** option in AWS Console / Billing Preferences |
| AWS Certificate Manager (`.monitorCertificate()`) | Certificate expiration | Days until expiration | |
| AWS CloudFront (`.monitorCloudFrontDistribution()`) | TPS, traffic, latency, errors | Error rate, low/high TPS | |
| AWS CloudWatch Synthetics Canary (`.monitorSyntheticsCanary()`) | Latency, error count/rate | Error count/rate, latency | |
| AWS CodeBuild (`.monitorCodeBuildProject()`) | Build counts (total, successful, failed), failed rate, duration | Failed build count/rate, duration | |
| AWS DynamoDB (`.monitorDynamoTable()`) | Read and write capacity provisioned / used | Consumed capacity, throttling, latency, errors | |
| AWS DynamoDB Global Secondary Index (`.monitorDynamoTableGlobalSecondaryIndex()`) | Read and write capacity, indexing progress, throttled events | | |
Expand Down
18 changes: 16 additions & 2 deletions lib/facade/MonitoringAspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import * as secretsmanager from "monocdk/aws-secretsmanager";
import * as sns from "monocdk/aws-sns";
import * as sqs from "monocdk/aws-sqs";
import * as stepfunctions from "monocdk/aws-stepfunctions";
import * as synthetics from "monocdk/aws-synthetics";

import { ElastiCacheClusterType } from "../monitoring";
import { MonitoringAspectProps, MonitoringAspectType } from "./aspect-types";
Expand Down Expand Up @@ -61,7 +62,8 @@ export class MonitoringAspect implements IAspect {
this.monitorSecretsManager(node);
this.monitorSns(node);
this.monitorSqs(node);
this.monitorStepFuntions(node);
this.monitorStepFunctions(node);
this.monitorSyntheticsCanaries(node);

if (!this.addedNodeIndependentMonitoringToScope) {
this.addedNodeIndependentMonitoringToScope = true;
Expand Down Expand Up @@ -340,7 +342,7 @@ export class MonitoringAspect implements IAspect {
}
}

private monitorStepFuntions(node: IConstruct) {
private monitorStepFunctions(node: IConstruct) {
const [isEnabled, props] = this.getMonitoringDetails(
this.props.stepFunctions
);
Expand All @@ -351,6 +353,18 @@ export class MonitoringAspect implements IAspect {
});
}
}

private monitorSyntheticsCanaries(node: IConstruct) {
const [isEnabled, props] = this.getMonitoringDetails(
this.props.syntheticsCanaries
);
if (isEnabled && node instanceof synthetics.Canary) {
this.monitoringFacade.monitorSyntheticsCanary({
canary: node,
...props,
});
}
}
}

export * from "./aspect-types";
8 changes: 8 additions & 0 deletions lib/facade/MonitoringFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ import {
StepFunctionServiceIntegrationMonitoringProps,
getQueueProcessingEc2ServiceMonitoring,
getQueueProcessingFargateServiceMonitoring,
SyntheticsCanaryMonitoringProps,
SyntheticsCanaryMonitoring,
} from "../monitoring";
import { MonitoringAspect, MonitoringAspectProps } from "./MonitoringAspect";

Expand Down Expand Up @@ -605,6 +607,12 @@ export class MonitoringFacade extends MonitoringScope {
return this;
}

monitorSyntheticsCanary(props: SyntheticsCanaryMonitoringProps) {
const segment = new SyntheticsCanaryMonitoring(this, props);
this.addSegment(segment, props);
return this;
}

monitorBilling(props?: BillingMonitoringProps) {
const segment = new BillingMonitoring(this, props ?? {});
this.addSegment(segment, props);
Expand Down
2 changes: 2 additions & 0 deletions lib/facade/aspect-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
SnsTopicMonitoringOptions,
SqsQueueMonitoringOptions,
StepFunctionMonitoringOptions,
SyntheticsCanaryMonitoringOptions,
} from "../monitoring";

export interface MonitoringAspectType<T> {
Expand Down Expand Up @@ -64,4 +65,5 @@ export interface MonitoringAspectProps {
readonly sns?: MonitoringAspectType<SnsTopicMonitoringOptions>;
readonly sqs?: MonitoringAspectType<SqsQueueMonitoringOptions>;
readonly stepFunctions?: MonitoringAspectType<StepFunctionMonitoringOptions>;
readonly syntheticsCanaries?: MonitoringAspectType<SyntheticsCanaryMonitoringOptions>;
}
101 changes: 101 additions & 0 deletions lib/monitoring/aws-synthetics/SyntheticsCanaryMetricFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { DimensionHash } from "monocdk/aws-cloudwatch";
import { Canary } from "monocdk/aws-synthetics";
import {
MetricFactory,
MetricStatistic,
RateComputationMethod,
} from "../../common/index";

const MetricNamespace = "CloudWatchSynthetics";

export interface SyntheticsCanaryMetricFactoryProps {
/**
* CloudWatch Canary to monitor
*/
readonly canary: Canary;
/**
* Method used to calculate relative rates
* @default average
*/
readonly rateComputationMethod?: RateComputationMethod;
}

export class SyntheticsCanaryMetricFactory {
protected readonly canary: Canary;
protected readonly metricFactory: MetricFactory;
protected readonly rateComputationMethod: RateComputationMethod;
protected readonly dimensions: DimensionHash;

constructor(
metricFactory: MetricFactory,
props: SyntheticsCanaryMetricFactoryProps
) {
this.canary = props.canary;
this.metricFactory = metricFactory;
this.rateComputationMethod =
props.rateComputationMethod ?? RateComputationMethod.AVERAGE;
this.dimensions = {
CanaryName: props.canary.canaryName,
};
}

metricLatencyAverageInMillis() {
return this.metricFactory.adaptMetric(
this.canary.metricDuration({
label: "Average",
statistic: MetricStatistic.AVERAGE,
})
);
}

metricSuccessInPercent() {
return this.metricFactory.adaptMetric(
this.canary.metricSuccessPercent({
label: "Success Rate",
statistic: MetricStatistic.AVERAGE,
})
);
}

metric4xxErrorCount() {
return this.metricFactory.createMetric(
"4xx",
MetricStatistic.SUM,
"4xx",
this.dimensions,
undefined,
MetricNamespace
);
}

metric4xxErrorRate() {
const metric = this.metric4xxErrorCount();
return this.metricFactory.toRate(
metric,
this.rateComputationMethod,
false,
"errors"
);
}

metric5xxFaultCount() {
return this.metricFactory.createMetric(
"5xx",
MetricStatistic.SUM,
"5xx",
this.dimensions,
undefined,
MetricNamespace
);
}

metric5xxFaultRate() {
const metric = this.metric5xxFaultCount();
return this.metricFactory.toRate(
metric,
this.rateComputationMethod,
false,
"faults"
);
}
}
Loading

0 comments on commit 7460d4e

Please sign in to comment.