From 32a88fd3341938643439b9b29522aa6a0b3b9ed6 Mon Sep 17 00:00:00 2001 From: Connor Koch Date: Tue, 17 Sep 2024 00:12:23 -0500 Subject: [PATCH] feat(lambda): add isOffsetLag prop and add support for generating an alarm and widget for the Lambda OffsetLag metric Lambda has added support for connecting to Kafka streams via Event Source Mappings (see: https://docs.aws.amazon.com/lambda/latest/dg/with-msk.html). This comes with the addition of a new CW metric under the AWS/Lambda namespace, `OffsetLag` (see: https://aws.amazon.com/blogs/compute/offset-lag-metric-for-amazon-msk-as-an-event-source-for-lambda/). This metric is different than the existing IteratorAge metric used for Kinesis streams. OffsetLag represents the difference between the last record written to a Kafka topic and the last record that the function's consumer group has processed (note the metric is in # of records, it's not a time metric). See here: https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html. Defaulted the monitor to `false` since it's a new prop and is not widely used. --- API.md | 493 ++++++++++++++++++ .../monitoring/alarms/AgeAlarmFactory.ts | 25 + .../aws-lambda/LambdaFunctionMetricFactory.ts | 11 + .../aws-lambda/LambdaFunctionMonitoring.ts | 82 ++- .../MonitoringAspect.test.ts.snap | 38 +- .../MonitoringFacade.test.ts.snap | 14 +- .../LambdaFunctionMonitoring.test.ts | 37 +- .../LambdaFunctionMonitoring.test.ts.snap | 237 ++------- 8 files changed, 695 insertions(+), 242 deletions(-) diff --git a/API.md b/API.md index fc3ce7d5..51668985 100644 --- a/API.md +++ b/API.md @@ -26280,12 +26280,14 @@ const lambdaFunctionMonitoringOptions: LambdaFunctionMonitoringOptions = { ... } | addLowTpsAlarm | {[ key: string ]: LowTpsThreshold} | *No description.* | | addMaxIteratorAgeAlarm | {[ key: string ]: MaxAgeThreshold} | *No description.* | | addMaxLatencyAlarm | {[ key: string ]: LatencyThreshold} | *No description.* | +| addMaxOffsetLagAlarm | {[ key: string ]: MaxOffsetLagThreshold} | *No description.* | | addMinInvocationsCountAlarm | {[ key: string ]: MinUsageCountThreshold} | *No description.* | | addProvisionedConcurrencySpilloverInvocationsCountAlarm | {[ key: string ]: RunningTaskCountThreshold} | *No description.* | | addProvisionedConcurrencySpilloverInvocationsRateAlarm | {[ key: string ]: RunningTaskRateThreshold} | *No description.* | | addThrottlesCountAlarm | {[ key: string ]: ErrorCountThreshold} | *No description.* | | addThrottlesRateAlarm | {[ key: string ]: ErrorRateThreshold} | *No description.* | | isIterator | boolean | Indicates that the Lambda function handles an event source (e.g. DynamoDB event stream). This impacts what widgets are shown, as well as validates the ability to use addMaxIteratorAgeAlarm. | +| isOffsetLag | boolean | Indicates that the Lambda function handles an event source which uses offsets for records (e.g. Kafka streams). This impacts what widgets are shown, as well as validates the ability to use addMaxOffsetLagAlarm. | --- @@ -26577,6 +26579,16 @@ public readonly addMaxLatencyAlarm: {[ key: string ]: LatencyThreshold}; --- +##### `addMaxOffsetLagAlarm`Optional + +```typescript +public readonly addMaxOffsetLagAlarm: {[ key: string ]: MaxOffsetLagThreshold}; +``` + +- *Type:* {[ key: string ]: MaxOffsetLagThreshold} + +--- + ##### `addMinInvocationsCountAlarm`Optional ```typescript @@ -26640,6 +26652,19 @@ Indicates that the Lambda function handles an event source (e.g. DynamoDB event --- +##### `isOffsetLag`Optional + +```typescript +public readonly isOffsetLag: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Indicates that the Lambda function handles an event source which uses offsets for records (e.g. Kafka streams). This impacts what widgets are shown, as well as validates the ability to use addMaxOffsetLagAlarm. + +--- + ### LambdaFunctionMonitoringProps #### Initializer @@ -26683,12 +26708,14 @@ const lambdaFunctionMonitoringProps: LambdaFunctionMonitoringProps = { ... } | addLowTpsAlarm | {[ key: string ]: LowTpsThreshold} | *No description.* | | addMaxIteratorAgeAlarm | {[ key: string ]: MaxAgeThreshold} | *No description.* | | addMaxLatencyAlarm | {[ key: string ]: LatencyThreshold} | *No description.* | +| addMaxOffsetLagAlarm | {[ key: string ]: MaxOffsetLagThreshold} | *No description.* | | addMinInvocationsCountAlarm | {[ key: string ]: MinUsageCountThreshold} | *No description.* | | addProvisionedConcurrencySpilloverInvocationsCountAlarm | {[ key: string ]: RunningTaskCountThreshold} | *No description.* | | addProvisionedConcurrencySpilloverInvocationsRateAlarm | {[ key: string ]: RunningTaskRateThreshold} | *No description.* | | addThrottlesCountAlarm | {[ key: string ]: ErrorCountThreshold} | *No description.* | | addThrottlesRateAlarm | {[ key: string ]: ErrorRateThreshold} | *No description.* | | isIterator | boolean | Indicates that the Lambda function handles an event source (e.g. DynamoDB event stream). This impacts what widgets are shown, as well as validates the ability to use addMaxIteratorAgeAlarm. | +| isOffsetLag | boolean | Indicates that the Lambda function handles an event source which uses offsets for records (e.g. Kafka streams). This impacts what widgets are shown, as well as validates the ability to use addMaxOffsetLagAlarm. | --- @@ -27028,6 +27055,16 @@ public readonly addMaxLatencyAlarm: {[ key: string ]: LatencyThreshold}; --- +##### `addMaxOffsetLagAlarm`Optional + +```typescript +public readonly addMaxOffsetLagAlarm: {[ key: string ]: MaxOffsetLagThreshold}; +``` + +- *Type:* {[ key: string ]: MaxOffsetLagThreshold} + +--- + ##### `addMinInvocationsCountAlarm`Optional ```typescript @@ -27091,6 +27128,19 @@ Indicates that the Lambda function handles an event source (e.g. DynamoDB event --- +##### `isOffsetLag`Optional + +```typescript +public readonly isOffsetLag: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Indicates that the Lambda function handles an event source which uses offsets for records (e.g. Kafka streams). This impacts what widgets are shown, as well as validates the ability to use addMaxOffsetLagAlarm. + +--- + ### LatencyThreshold #### Initializer @@ -31631,6 +31681,365 @@ public readonly maxMessageCount: number; --- +### MaxOffsetLagThreshold + +#### Initializer + +```typescript +import { MaxOffsetLagThreshold } from 'cdk-monitoring-constructs' + +const maxOffsetLagThreshold: MaxOffsetLagThreshold = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| actionOverride | IAlarmActionStrategy | Allows to override the default alarm action. | +| actionsEnabled | boolean | Enables the configured CloudWatch alarm ticketing actions. | +| alarmDescriptionOverride | string | A text included in the generated ticket description body, which fully replaces the generated text. | +| alarmNameOverride | string | If this is defined, the alarm name is set to this exact value. | +| comparisonOperatorOverride | aws-cdk-lib.aws_cloudwatch.ComparisonOperator | Comparison operator used to compare actual value against the threshold. | +| customParams | {[ key: string ]: any} | This allows user to attach custom parameters to this alarm, which can later be accessed from the "useCreatedAlarms" method. | +| customTags | string[] | This allows user to attach custom values to this alarm, which can later be accessed from the "useCreatedAlarms" method. | +| datapointsToAlarm | number | Number of breaches required to transition into an ALARM state. | +| dedupeStringOverride | string | If this is defined, the alarm dedupe string is set to this exact value. | +| documentationLink | string | An optional link included in the generated ticket description body. | +| evaluateLowSampleCountPercentile | boolean | Used only for alarms based on percentiles. | +| evaluationPeriods | number | Number of periods to consider when checking the number of breaching datapoints. | +| fillAlarmRange | boolean | Indicates whether the alarming range of values should be highlighted in the widget. | +| metricAdjuster | IMetricAdjuster | If specified, adjusts the metric before creating an alarm from it. | +| minMetricSamplesToAlarm | number | Specifies how many samples (N) of the metric is needed to trigger the alarm. | +| minSampleCountToEvaluateDatapoint | number | Specifies how many samples (N) of the metric is needed in a datapoint to be evaluated for alarming. | +| overrideAnnotationColor | string | If specified, it modifies the final alarm annotation color. | +| overrideAnnotationLabel | string | If specified, it modifies the final alarm annotation label. | +| overrideAnnotationVisibility | boolean | If specified, it modifies the final alarm annotation visibility. | +| period | aws-cdk-lib.Duration | Period override for the metric to alarm on. | +| runbookLink | string | An optional link included in the generated ticket description body. | +| treatMissingDataOverride | aws-cdk-lib.aws_cloudwatch.TreatMissingData | Behaviour in case the metric data is missing. | +| maxOffsetLag | number | *No description.* | + +--- + +##### `actionOverride`Optional + +```typescript +public readonly actionOverride: IAlarmActionStrategy; +``` + +- *Type:* IAlarmActionStrategy +- *Default:* undefined (default action will be used, if any) + +Allows to override the default alarm action. + +--- + +##### `actionsEnabled`Optional + +```typescript +public readonly actionsEnabled: boolean; +``` + +- *Type:* boolean +- *Default:* the same as monitoring facade default + +Enables the configured CloudWatch alarm ticketing actions. + +--- + +##### `alarmDescriptionOverride`Optional + +```typescript +public readonly alarmDescriptionOverride: string; +``` + +- *Type:* string +- *Default:* default auto-generated content only + +A text included in the generated ticket description body, which fully replaces the generated text. + +--- + +##### `alarmNameOverride`Optional + +```typescript +public readonly alarmNameOverride: string; +``` + +- *Type:* string + +If this is defined, the alarm name is set to this exact value. + +Please be aware that you need to specify prefix for different stages (Beta, Prod...) and regions (EU, NA...) manually. + +--- + +##### `comparisonOperatorOverride`Optional + +```typescript +public readonly comparisonOperatorOverride: ComparisonOperator; +``` + +- *Type:* aws-cdk-lib.aws_cloudwatch.ComparisonOperator +- *Default:* alarm-specific default + +Comparison operator used to compare actual value against the threshold. + +--- + +##### `customParams`Optional + +```typescript +public readonly customParams: {[ key: string ]: any}; +``` + +- *Type:* {[ key: string ]: any} +- *Default:* no parameters + +This allows user to attach custom parameters to this alarm, which can later be accessed from the "useCreatedAlarms" method. + +--- + +##### `customTags`Optional + +```typescript +public readonly customTags: string[]; +``` + +- *Type:* string[] +- *Default:* no tags + +This allows user to attach custom values to this alarm, which can later be accessed from the "useCreatedAlarms" method. + +--- + +##### `datapointsToAlarm`Optional + +```typescript +public readonly datapointsToAlarm: number; +``` + +- *Type:* number +- *Default:* the same as monitoring facade default + +Number of breaches required to transition into an ALARM state. + +--- + +##### `dedupeStringOverride`Optional + +```typescript +public readonly dedupeStringOverride: string; +``` + +- *Type:* string +- *Default:* undefined (no override) + +If this is defined, the alarm dedupe string is set to this exact value. + +Please be aware that you need to handle deduping for different stages (Beta, Prod...) and regions (EU, NA...) manually. + +--- + +##### `documentationLink`Optional + +```typescript +public readonly documentationLink: string; +``` + +- *Type:* string +- *Default:* no additional link will be added + +An optional link included in the generated ticket description body. + +--- + +##### `evaluateLowSampleCountPercentile`Optional + +```typescript +public readonly evaluateLowSampleCountPercentile: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Used only for alarms based on percentiles. + +If you specify false, the alarm state does not change during periods with too few data points to be statistically significant. +If you specify true, the alarm is always evaluated and possibly changes state no matter how many data points are available. + +--- + +##### `evaluationPeriods`Optional + +```typescript +public readonly evaluationPeriods: number; +``` + +- *Type:* number +- *Default:* the same as monitoring facade default + +Number of periods to consider when checking the number of breaching datapoints. + +--- + +##### `fillAlarmRange`Optional + +```typescript +public readonly fillAlarmRange: boolean; +``` + +- *Type:* boolean +- *Default:* false + +Indicates whether the alarming range of values should be highlighted in the widget. + +--- + +##### `metricAdjuster`Optional + +```typescript +public readonly metricAdjuster: IMetricAdjuster; +``` + +- *Type:* IMetricAdjuster +- *Default:* no adjuster + +If specified, adjusts the metric before creating an alarm from it. + +--- + +##### ~~`minMetricSamplesToAlarm`~~Optional + +- *Deprecated:* Use minSampleCountToEvaluateDatapoint instead. minMetricSamplesAlarm uses different evaluation +period for its child alarms, so it doesn't guarantee that each datapoint in the evaluation period has +sufficient number of samples + +```typescript +public readonly minMetricSamplesToAlarm: number; +``` + +- *Type:* number +- *Default:* default behaviour - no condition on sample count will be added to the alarm + +Specifies how many samples (N) of the metric is needed to trigger the alarm. + +If this property is specified, a composite alarm is created of the following: + +This composite alarm will be returned as a result and uses the specified alarm actions. + +--- + +##### `minSampleCountToEvaluateDatapoint`Optional + +```typescript +public readonly minSampleCountToEvaluateDatapoint: number; +``` + +- *Type:* number +- *Default:* default behaviour - no condition on sample count will be used + +Specifies how many samples (N) of the metric is needed in a datapoint to be evaluated for alarming. + +If this property is specified, your metric will be subject to MathExpression that will add an IF condition +to your metric to make sure that each datapoint is evaluated only if it has sufficient number of samples. +If the number of samples is not sufficient, the datapoint will be treated as missing data and will be evaluated +according to the treatMissingData parameter. +If specified, deprecated minMetricSamplesToAlarm has no effect. + +--- + +##### `overrideAnnotationColor`Optional + +```typescript +public readonly overrideAnnotationColor: string; +``` + +- *Type:* string +- *Default:* no override (default color) + +If specified, it modifies the final alarm annotation color. + +--- + +##### `overrideAnnotationLabel`Optional + +```typescript +public readonly overrideAnnotationLabel: string; +``` + +- *Type:* string +- *Default:* no override (default label) + +If specified, it modifies the final alarm annotation label. + +--- + +##### `overrideAnnotationVisibility`Optional + +```typescript +public readonly overrideAnnotationVisibility: boolean; +``` + +- *Type:* boolean +- *Default:* no override (default visibility) + +If specified, it modifies the final alarm annotation visibility. + +--- + +##### `period`Optional + +```typescript +public readonly period: Duration; +``` + +- *Type:* aws-cdk-lib.Duration +- *Default:* the default specified in MetricFactory + +Period override for the metric to alarm on. + +--- + +##### `runbookLink`Optional + +```typescript +public readonly runbookLink: string; +``` + +- *Type:* string +- *Default:* no additional link will be added + +An optional link included in the generated ticket description body. + +--- + +##### `treatMissingDataOverride`Optional + +```typescript +public readonly treatMissingDataOverride: TreatMissingData; +``` + +- *Type:* aws-cdk-lib.aws_cloudwatch.TreatMissingData +- *Default:* alarm-specific default + +Behaviour in case the metric data is missing. + +--- + +##### `maxOffsetLag`Required + +```typescript +public readonly maxOffsetLag: number; +``` + +- *Type:* number + +--- + ### MaxSecretCountThreshold #### Initializer @@ -50889,6 +51298,7 @@ new AgeAlarmFactory(alarmFactory: AlarmFactory) | addDaysSinceUpdateAlarm | *No description.* | | addDaysToExpiryAlarm | *No description.* | | addIteratorMaxAgeAlarm | *No description.* | +| addMaxOffsetLagAlarm | *No description.* | --- @@ -50964,6 +51374,30 @@ public addIteratorMaxAgeAlarm(metric: Metric | MathExpression, props: MaxAgeThre --- +##### `addMaxOffsetLagAlarm` + +```typescript +public addMaxOffsetLagAlarm(metric: Metric | MathExpression, props: MaxOffsetLagThreshold, disambiguator?: string): AlarmWithAnnotation +``` + +###### `metric`Required + +- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression + +--- + +###### `props`Required + +- *Type:* MaxOffsetLagThreshold + +--- + +###### `disambiguator`Optional + +- *Type:* string + +--- + @@ -64488,6 +64922,7 @@ new LambdaFunctionMetricFactory(metricFactory: MetricFactory, props: LambdaFunct | metricLatencyP90InMillis | *No description.* | | metricLatencyP99InMillis | *No description.* | | metricMaxIteratorAgeInMillis | *No description.* | +| metricMaxOffsetLagInNumberOfRecords | *No description.* | | metricProvisionedConcurrencySpilloverInvocations | *No description.* | | metricProvisionedConcurrencySpilloverRate | *No description.* | | metricThrottlesCount | *No description.* | @@ -64562,6 +64997,12 @@ public metricLatencyP99InMillis(): Metric | MathExpression public metricMaxIteratorAgeInMillis(): Metric | MathExpression ``` +##### `metricMaxOffsetLagInNumberOfRecords` + +```typescript +public metricMaxOffsetLagInNumberOfRecords(): Metric | MathExpression +``` + ##### `metricProvisionedConcurrencySpilloverInvocations` ```typescript @@ -64645,6 +65086,7 @@ new LambdaFunctionMonitoring(scope: MonitoringScope, props: LambdaFunctionMonito | createLambdaInsightsFunctionCostWidget | *No description.* | | createLambdaInsightsMemoryWidget | *No description.* | | createLatencyWidget | *No description.* | +| createOffsetLagWidget | *No description.* | | createRateWidget | *No description.* | | createTitleWidget | *No description.* | | createTpsWidget | *No description.* | @@ -64893,6 +65335,24 @@ public createLatencyWidget(width: number, height: number): GraphWidget --- +##### `createOffsetLagWidget` + +```typescript +public createOffsetLagWidget(width: number, height: number): GraphWidget +``` + +###### `width`Required + +- *Type:* number + +--- + +###### `height`Required + +- *Type:* number + +--- + ##### `createRateWidget` ```typescript @@ -64953,12 +65413,15 @@ public createTpsWidget(width: number, height: number): GraphWidget | invocationCountMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | invocationRateAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | | isIterator | boolean | *No description.* | +| isOffsetLag | boolean | *No description.* | | lambdaInsightsEnabled | boolean | *No description.* | | latencyAlarmFactory | LatencyAlarmFactory | *No description.* | | latencyAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | | maxIteratorAgeAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | | maxIteratorAgeMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | maxLatencyMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | +| maxOffsetLagAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | +| maxOffsetLagMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | memoryUsageAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | | metricFactory | LambdaFunctionMetricFactory | *No description.* | | namingStrategy | MonitoringNamingStrategy | *No description.* | @@ -65117,6 +65580,16 @@ public readonly isIterator: boolean; --- +##### `isOffsetLag`Required + +```typescript +public readonly isOffsetLag: boolean; +``` + +- *Type:* boolean + +--- + ##### `lambdaInsightsEnabled`Required ```typescript @@ -65177,6 +65650,26 @@ public readonly maxLatencyMetric: Metric | MathExpression; --- +##### `maxOffsetLagAnnotations`Required + +```typescript +public readonly maxOffsetLagAnnotations: HorizontalAnnotation[]; +``` + +- *Type:* aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] + +--- + +##### `maxOffsetLagMetric`Required + +```typescript +public readonly maxOffsetLagMetric: Metric | MathExpression; +``` + +- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression + +--- + ##### `memoryUsageAnnotations`Required ```typescript diff --git a/lib/common/monitoring/alarms/AgeAlarmFactory.ts b/lib/common/monitoring/alarms/AgeAlarmFactory.ts index 0aacafda..130cda9b 100644 --- a/lib/common/monitoring/alarms/AgeAlarmFactory.ts +++ b/lib/common/monitoring/alarms/AgeAlarmFactory.ts @@ -14,6 +14,10 @@ export interface MaxAgeThreshold extends CustomAlarmThreshold { readonly maxAgeInMillis: number; } +export interface MaxOffsetLagThreshold extends CustomAlarmThreshold { + readonly maxOffsetLag: number; +} + export interface DaysSinceUpdateThreshold extends CustomAlarmThreshold { readonly maxDaysSinceUpdate: number; } @@ -65,6 +69,27 @@ export class AgeAlarmFactory { }); } + addMaxOffsetLagAlarm( + metric: MetricWithAlarmSupport, + props: MaxOffsetLagThreshold, + disambiguator?: string, + ) { + return this.alarmFactory.addAlarm(metric, { + treatMissingData: + props.treatMissingDataOverride ?? TreatMissingData.MISSING, + comparisonOperator: + props.comparisonOperatorOverride ?? + ComparisonOperator.GREATER_THAN_THRESHOLD, + ...props, + disambiguator, + threshold: props.maxOffsetLag, + alarmNameSuffix: "Offset-Lag-Max", + alarmDescription: "Max Offset Lag is too high.", + // Dedupe all iterator max age to the same ticket + alarmDedupeStringSuffix: "AnyMaxOffsetLag", + }); + } + addDaysSinceUpdateAlarm( metric: MetricWithAlarmSupport, props: DaysSinceUpdateThreshold, diff --git a/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts b/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts index 9a0c612f..bb61f005 100644 --- a/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts +++ b/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts @@ -194,4 +194,15 @@ export class LambdaFunctionMetricFactory extends BaseMetricFactory; readonly addLatencyP90Alarm?: Record; @@ -92,6 +100,8 @@ export interface LambdaFunctionMonitoringOptions extends BaseMonitoringProps { >; readonly addMaxIteratorAgeAlarm?: Record; + readonly addMaxOffsetLagAlarm?: Record; + // Enhanced CPU metrics that are all time-based and not percent based readonly addEnhancedMonitoringMaxCpuTotalTimeAlarm?: Record< string, @@ -148,6 +158,7 @@ export class LambdaFunctionMonitoring extends Monitoring { readonly cpuTotalTimeAnnotations: HorizontalAnnotation[]; readonly memoryUsageAnnotations: HorizontalAnnotation[]; readonly maxIteratorAgeAnnotations: HorizontalAnnotation[]; + readonly maxOffsetLagAnnotations: HorizontalAnnotation[]; readonly tpsMetric: MetricWithAlarmSupport; readonly p50LatencyMetric: MetricWithAlarmSupport; @@ -165,6 +176,8 @@ export class LambdaFunctionMonitoring extends Monitoring { readonly isIterator: boolean; readonly maxIteratorAgeMetric: MetricWithAlarmSupport; + readonly isOffsetLag: boolean; + readonly maxOffsetLagMetric: MetricWithAlarmSupport; readonly lambdaInsightsEnabled: boolean; readonly enhancedMetricFactory?: LambdaFunctionEnhancedMetricFactory; @@ -209,6 +222,7 @@ export class LambdaFunctionMonitoring extends Monitoring { this.cpuTotalTimeAnnotations = []; this.memoryUsageAnnotations = []; this.maxIteratorAgeAnnotations = []; + this.maxOffsetLagAnnotations = []; this.metricFactory = new LambdaFunctionMetricFactory( scope.createMetricFactory(), @@ -242,6 +256,9 @@ export class LambdaFunctionMonitoring extends Monitoring { this.isIterator = props.isIterator ?? true; this.maxIteratorAgeMetric = this.metricFactory.metricMaxIteratorAgeInMillis(); + this.isOffsetLag = props.isOffsetLag ?? false; + this.maxOffsetLagMetric = + this.metricFactory.metricMaxOffsetLagInNumberOfRecords(); this.lambdaInsightsEnabled = props.lambdaInsightsEnabled ?? false; if (props.lambdaInsightsEnabled) { @@ -521,6 +538,22 @@ export class LambdaFunctionMonitoring extends Monitoring { this.maxIteratorAgeAnnotations.push(createdAlarm.annotation); this.addAlarm(createdAlarm); } + for (const disambiguator in props.addMaxOffsetLagAlarm) { + if (!this.isOffsetLag) { + throw new Error( + "addMaxOffsetLagAlarm is not applicable if isOffsetLag is not true", + ); + } + + const alarmProps = props.addMaxOffsetLagAlarm[disambiguator]; + const createdAlarm = this.ageAlarmFactory.addMaxOffsetLagAlarm( + this.maxOffsetLagMetric, + alarmProps, + disambiguator, + ); + this.maxOffsetLagAnnotations.push(createdAlarm.annotation); + this.addAlarm(createdAlarm); + } props.useCreatedAlarms?.consume(this.createdAlarms()); } @@ -545,19 +578,37 @@ export class LambdaFunctionMonitoring extends Monitoring { ), ]; + let secondRowWidgetWidth: number; + if (this.isIterator && this.isOffsetLag) { + secondRowWidgetWidth = QuarterWidth; + } else if (this.isIterator || this.isOffsetLag) { + secondRowWidgetWidth = ThirdWidth; + } else { + secondRowWidgetWidth = HalfWidth; + } + const secondRow: Row = new Row( + this.createInvocationWidget( + secondRowWidgetWidth, + DefaultGraphWidgetHeight, + ), + this.createErrorCountWidget( + secondRowWidgetWidth, + DefaultGraphWidgetHeight, + ), + ); if (this.isIterator) { - widgets.push( - new Row( - this.createInvocationWidget(ThirdWidth, DefaultGraphWidgetHeight), - this.createIteratorAgeWidget(ThirdWidth, DefaultGraphWidgetHeight), - this.createErrorCountWidget(ThirdWidth, DefaultGraphWidgetHeight), + secondRow.addWidget( + this.createIteratorAgeWidget( + secondRowWidgetWidth, + DefaultGraphWidgetHeight, ), ); - } else { - widgets.push( - new Row( - this.createInvocationWidget(HalfWidth, DefaultGraphWidgetHeight), - this.createErrorCountWidget(HalfWidth, DefaultGraphWidgetHeight), + } + if (this.isOffsetLag) { + secondRow.addWidget( + this.createOffsetLagWidget( + secondRowWidgetWidth, + DefaultGraphWidgetHeight, ), ); } @@ -681,6 +732,17 @@ export class LambdaFunctionMonitoring extends Monitoring { }); } + createOffsetLagWidget(width: number, height: number) { + return new GraphWidget({ + width, + height, + title: "OffsetLag", + left: [this.maxOffsetLagMetric], + leftYAxis: CountAxisFromZero, + leftAnnotations: this.maxOffsetLagAnnotations, + }); + } + createLambdaInsightsCpuWidget(width: number, height: number) { return new GraphWidget({ width, diff --git a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap index 526dbbc0..4ab34258 100644 --- a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap +++ b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap @@ -5255,43 +5255,7 @@ Object { Object { "Ref": "DummyFunction3BB5AE03", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Iterator Age\\",\\"stat\\":\\"Maximum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "DummyFunction3BB5AE03", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, diff --git a/test/facade/__snapshots__/MonitoringFacade.test.ts.snap b/test/facade/__snapshots__/MonitoringFacade.test.ts.snap index e4385a69..ae621ce6 100644 --- a/test/facade/__snapshots__/MonitoringFacade.test.ts.snap +++ b/test/facade/__snapshots__/MonitoringFacade.test.ts.snap @@ -72,19 +72,7 @@ Object { Object { "Ref": "AWS::Region", }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Throttles (avg)\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":21,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Invocations\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Throttles\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Concurrent\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":21,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Iterator Age\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Maximum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":21,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Faults\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}", + "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Throttles (avg)\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"MyFunction\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\",\\"accountId\\":\\"01234567890\\",\\"region\\":\\"us-west-2\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, diff --git a/test/monitoring/aws-lambda/LambdaFunctionMonitoring.test.ts b/test/monitoring/aws-lambda/LambdaFunctionMonitoring.test.ts index 79bc366f..0f773337 100644 --- a/test/monitoring/aws-lambda/LambdaFunctionMonitoring.test.ts +++ b/test/monitoring/aws-lambda/LambdaFunctionMonitoring.test.ts @@ -83,6 +83,7 @@ test("snapshot test: all alarms", () => { lambdaFunction, humanReadableName: "Dummy Lambda for testing", alarmFriendlyName: "DummyLambda", + isOffsetLag: true, addFaultRateAlarm: { Warning: { maxErrorRate: 1, @@ -165,6 +166,11 @@ test("snapshot test: all alarms", () => { maxAgeInMillis: 1_000_000, }, }, + addMaxOffsetLagAlarm: { + Warning: { + maxOffsetLag: 100, + }, + }, useCreatedAlarms: { consume(alarms: AlarmWithAnnotation[]) { numAlarmsCreated = alarms.length; @@ -173,7 +179,7 @@ test("snapshot test: all alarms", () => { }); addMonitoringDashboardsToStack(stack, monitoring); - expect(numAlarmsCreated).toStrictEqual(14); + expect(numAlarmsCreated).toStrictEqual(15); expect(Template.fromStack(stack)).toMatchSnapshot(); }); @@ -536,6 +542,35 @@ test("throws error if attempting to create iterator age alarm if not an iterator ); }); +test("throws error if attempting to create offsetLag alarm if not an offsetLag Lambda", () => { + const stack = new Stack(); + + const scope = new TestMonitoringScope(stack, "Scope"); + + const lambdaFunction = new Function(stack, "Function", { + functionName: "DummyLambda", + runtime: Runtime.NODEJS_18_X, + code: InlineCode.fromInline("{}"), + handler: "Dummy::handler", + }); + + expect( + () => + new LambdaFunctionMonitoring(scope, { + lambdaFunction, + humanReadableName: "Dummy Lambda for testing", + alarmFriendlyName: "DummyLambda", + addMaxOffsetLagAlarm: { + Warning: { + maxOffsetLag: 100, + }, + }, + }), + ).toThrow( + "addMaxOffsetLagAlarm is not applicable if isOffsetLag is not true", + ); +}); + test("doesn't create alarms for enhanced Lambda Insights metrics if not enabled", () => { const stack = new Stack(); diff --git a/test/monitoring/aws-lambda/__snapshots__/LambdaFunctionMonitoring.test.ts.snap b/test/monitoring/aws-lambda/__snapshots__/LambdaFunctionMonitoring.test.ts.snap index d987778e..811305b8 100644 --- a/test/monitoring/aws-lambda/__snapshots__/LambdaFunctionMonitoring.test.ts.snap +++ b/test/monitoring/aws-lambda/__snapshots__/LambdaFunctionMonitoring.test.ts.snap @@ -170,6 +170,17 @@ Object { "Arn", ], }, + "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":12,\\"y\\":12,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "ScopeTestDummyLambdaOffsetLagMaxWarning0F49F0E0", + "Arn", + ], + }, "\\"]},\\"yAxis\\":{}}}]}", ], ], @@ -282,43 +293,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles > 2 for 20 datapoints within 100 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Invocations < 5 for 30 datapoints within 150 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Concurrent > 10 for 3 datapoints within 15 minutes\\",\\"value\\":10,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Provisioned Concurrency Spillovers > 5 for 3 datapoints within 15 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Iterator Age\\",\\"stat\\":\\"Maximum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Iterator Age > 1000000 for 3 datapoints within 15 minutes\\",\\"value\\":1000000,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Faults > 2 for 20 datapoints within 100 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, @@ -659,6 +634,42 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, + "ScopeTestDummyLambdaOffsetLagMaxWarning0F49F0E0": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "Max Offset Lag is too high.", + "AlarmName": "Test-DummyLambda-Offset-Lag-Max-Warning", + "ComparisonOperator": "GreaterThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "Offset Lag", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "FunctionName", + "Value": Object { + "Ref": "Function76856677", + }, + }, + ], + "MetricName": "OffsetLag", + "Namespace": "AWS/Lambda", + }, + "Period": 300, + "Stat": "Maximum", + }, + "ReturnData": true, + }, + ], + "Threshold": 100, + "TreatMissingData": "missing", + }, + "Type": "AWS::CloudWatch::Alarm", + }, "ScopeTestDummyLambdaRunningTasksHighCritical357223A5": Object { "Properties": Object { "ActionsEnabled": true, @@ -1388,43 +1399,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles > 2 for 20 datapoints within 100 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Invocations < 5 for 30 datapoints within 150 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Concurrent > 10 for 3 datapoints within 15 minutes\\",\\"value\\":10,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Provisioned Concurrency Spillovers > 5 for 3 datapoints within 15 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Iterator Age\\",\\"stat\\":\\"Maximum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Iterator Age > 1000000 for 3 datapoints within 15 minutes\\",\\"value\\":1000000,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Custom annotation label\\",\\"value\\":2,\\"color\\":\\"#8c564b\\",\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU Total Time\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU Total Time\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -1440,7 +1415,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"CPUTotalTime.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"CPUTotalTime.Max > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.P90 > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.Avg > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Memory Utilization\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"CPUTotalTime.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"CPUTotalTime.Max > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.P90 > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.Avg > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Memory Utilization\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -1456,7 +1431,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"MemoryUtilization.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"MemoryUtilization.Max > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.P90 > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.Avg > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Function Cost\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"MemoryUtilization.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"MemoryUtilization.Max > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.P90 > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.Avg > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Function Cost\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -2633,43 +2608,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles > 2 for 20 datapoints within 100 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Invocations < 5 for 30 datapoints within 150 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Concurrent > 10 for 3 datapoints within 15 minutes\\",\\"value\\":10,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Provisioned Concurrency Spillovers > 5 for 3 datapoints within 15 minutes\\",\\"value\\":5,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Iterator Age\\",\\"stat\\":\\"Maximum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Iterator Age > 1000000 for 3 datapoints within 15 minutes\\",\\"value\\":1000000,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Faults > 2 for 20 datapoints within 100 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU Total Time\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Throttles (avg) > 1 for 10 datapoints within 50 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU Total Time\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -2685,7 +2624,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"CPUTotalTime.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"CPUTotalTime.Max > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.P90 > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.Avg > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Memory Utilization\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"CPUTotalTime.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"CPUTotalTime.Max > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.P90 > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPUTotalTime.Avg > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Memory Utilization\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -2701,7 +2640,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"MemoryUtilization.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"MemoryUtilization.Max > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.P90 > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.Avg > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":11,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Function Cost\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"MemoryUtilization.Avg\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"MemoryUtilization.Max > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.P90 > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"MemoryUtilization.Avg > 50 for 3 datapoints within 15 minutes\\",\\"value\\":50,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Function Cost\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -3651,43 +3590,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":8,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Iterator\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"IteratorAge\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Iterator Age\\",\\"stat\\":\\"Maximum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, @@ -3895,35 +3798,7 @@ Object { Object { "Ref": "Function76856677", }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":5,\\"x\\":0,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Invocations\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Invocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Invocations\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"Throttles\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Throttles\\",\\"stat\\":\\"Sum\\"}],[\\"AWS/Lambda\\",\\"ConcurrentExecutions\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Concurrent\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/Lambda\\",\\"ProvisionedConcurrencySpilloverInvocations\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":5,\\"x\\":12,\\"y\\":6,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"", - Object { - "Ref": "AWS::Region", - }, - "\\",\\"metrics\\":[[\\"AWS/Lambda\\",\\"Errors\\",\\"FunctionName\\",\\"", - Object { - "Ref": "Function76856677", - }, - "\\",{\\"label\\":\\"Faults\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}", + "\\",{\\"label\\":\\"Provisioned Concurrency Spillovers (avg)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], },