@@ -30,6 +30,7 @@ import {
3030 LatencyType ,
3131 LowTpsThreshold ,
3232 MaxAgeThreshold ,
33+ MaxOffsetLagThreshold ,
3334 MegabyteMillisecondAxisFromZero ,
3435 MetricWithAlarmSupport ,
3536 MinUsageCountThreshold ,
@@ -61,6 +62,13 @@ export interface LambdaFunctionMonitoringOptions extends BaseMonitoringProps {
6162 * @default - true
6263 */
6364 readonly isIterator ?: boolean ;
65+ /**
66+ * Indicates that the Lambda function handles an event source which uses offsets for records (e.g. Kafka streams).
67+ * This impacts what widgets are shown, as well as validates the ability to use addMaxOffsetLagAlarm.
68+ *
69+ * @default - false
70+ */
71+ readonly isOffsetLag ?: boolean ;
6472
6573 readonly addLatencyP50Alarm ?: Record < string , LatencyThreshold > ;
6674 readonly addLatencyP90Alarm ?: Record < string , LatencyThreshold > ;
@@ -92,6 +100,8 @@ export interface LambdaFunctionMonitoringOptions extends BaseMonitoringProps {
92100 > ;
93101 readonly addMaxIteratorAgeAlarm ?: Record < string , MaxAgeThreshold > ;
94102
103+ readonly addMaxOffsetLagAlarm ?: Record < string , MaxOffsetLagThreshold > ;
104+
95105 // Enhanced CPU metrics that are all time-based and not percent based
96106 readonly addEnhancedMonitoringMaxCpuTotalTimeAlarm ?: Record <
97107 string ,
@@ -148,6 +158,7 @@ export class LambdaFunctionMonitoring extends Monitoring {
148158 readonly cpuTotalTimeAnnotations : HorizontalAnnotation [ ] ;
149159 readonly memoryUsageAnnotations : HorizontalAnnotation [ ] ;
150160 readonly maxIteratorAgeAnnotations : HorizontalAnnotation [ ] ;
161+ readonly maxOffsetLagAnnotations : HorizontalAnnotation [ ] ;
151162
152163 readonly tpsMetric : MetricWithAlarmSupport ;
153164 readonly p50LatencyMetric : MetricWithAlarmSupport ;
@@ -165,6 +176,8 @@ export class LambdaFunctionMonitoring extends Monitoring {
165176
166177 readonly isIterator : boolean ;
167178 readonly maxIteratorAgeMetric : MetricWithAlarmSupport ;
179+ readonly isOffsetLag : boolean ;
180+ readonly maxOffsetLagMetric : MetricWithAlarmSupport ;
168181
169182 readonly lambdaInsightsEnabled : boolean ;
170183 readonly enhancedMetricFactory ?: LambdaFunctionEnhancedMetricFactory ;
@@ -209,6 +222,7 @@ export class LambdaFunctionMonitoring extends Monitoring {
209222 this . cpuTotalTimeAnnotations = [ ] ;
210223 this . memoryUsageAnnotations = [ ] ;
211224 this . maxIteratorAgeAnnotations = [ ] ;
225+ this . maxOffsetLagAnnotations = [ ] ;
212226
213227 this . metricFactory = new LambdaFunctionMetricFactory (
214228 scope . createMetricFactory ( ) ,
@@ -242,6 +256,9 @@ export class LambdaFunctionMonitoring extends Monitoring {
242256 this . isIterator = props . isIterator ?? true ;
243257 this . maxIteratorAgeMetric =
244258 this . metricFactory . metricMaxIteratorAgeInMillis ( ) ;
259+ this . isOffsetLag = props . isOffsetLag ?? false ;
260+ this . maxOffsetLagMetric =
261+ this . metricFactory . metricMaxOffsetLagInNumberOfRecords ( ) ;
245262
246263 this . lambdaInsightsEnabled = props . lambdaInsightsEnabled ?? false ;
247264 if ( props . lambdaInsightsEnabled ) {
@@ -521,6 +538,22 @@ export class LambdaFunctionMonitoring extends Monitoring {
521538 this . maxIteratorAgeAnnotations . push ( createdAlarm . annotation ) ;
522539 this . addAlarm ( createdAlarm ) ;
523540 }
541+ for ( const disambiguator in props . addMaxOffsetLagAlarm ) {
542+ if ( ! this . isOffsetLag ) {
543+ throw new Error (
544+ "addMaxOffsetLagAlarm is not applicable if isOffsetLag is not true" ,
545+ ) ;
546+ }
547+
548+ const alarmProps = props . addMaxOffsetLagAlarm [ disambiguator ] ;
549+ const createdAlarm = this . ageAlarmFactory . addMaxOffsetLagAlarm (
550+ this . maxOffsetLagMetric ,
551+ alarmProps ,
552+ disambiguator ,
553+ ) ;
554+ this . maxOffsetLagAnnotations . push ( createdAlarm . annotation ) ;
555+ this . addAlarm ( createdAlarm ) ;
556+ }
524557
525558 props . useCreatedAlarms ?. consume ( this . createdAlarms ( ) ) ;
526559 }
@@ -545,19 +578,37 @@ export class LambdaFunctionMonitoring extends Monitoring {
545578 ) ,
546579 ] ;
547580
581+ let secondRowWidgetWidth : number ;
582+ if ( this . isIterator && this . isOffsetLag ) {
583+ secondRowWidgetWidth = QuarterWidth ;
584+ } else if ( this . isIterator || this . isOffsetLag ) {
585+ secondRowWidgetWidth = ThirdWidth ;
586+ } else {
587+ secondRowWidgetWidth = HalfWidth ;
588+ }
589+ const secondRow : Row = new Row (
590+ this . createInvocationWidget (
591+ secondRowWidgetWidth ,
592+ DefaultGraphWidgetHeight ,
593+ ) ,
594+ this . createErrorCountWidget (
595+ secondRowWidgetWidth ,
596+ DefaultGraphWidgetHeight ,
597+ ) ,
598+ ) ;
548599 if ( this . isIterator ) {
549- widgets . push (
550- new Row (
551- this . createInvocationWidget ( ThirdWidth , DefaultGraphWidgetHeight ) ,
552- this . createIteratorAgeWidget ( ThirdWidth , DefaultGraphWidgetHeight ) ,
553- this . createErrorCountWidget ( ThirdWidth , DefaultGraphWidgetHeight ) ,
600+ secondRow . addWidget (
601+ this . createIteratorAgeWidget (
602+ secondRowWidgetWidth ,
603+ DefaultGraphWidgetHeight ,
554604 ) ,
555605 ) ;
556- } else {
557- widgets . push (
558- new Row (
559- this . createInvocationWidget ( HalfWidth , DefaultGraphWidgetHeight ) ,
560- this . createErrorCountWidget ( HalfWidth , DefaultGraphWidgetHeight ) ,
606+ }
607+ if ( this . isOffsetLag ) {
608+ secondRow . addWidget (
609+ this . createOffsetLagWidget (
610+ secondRowWidgetWidth ,
611+ DefaultGraphWidgetHeight ,
561612 ) ,
562613 ) ;
563614 }
@@ -681,6 +732,17 @@ export class LambdaFunctionMonitoring extends Monitoring {
681732 } ) ;
682733 }
683734
735+ createOffsetLagWidget ( width : number , height : number ) {
736+ return new GraphWidget ( {
737+ width,
738+ height,
739+ title : "OffsetLag" ,
740+ left : [ this . maxOffsetLagMetric ] ,
741+ leftYAxis : CountAxisFromZero ,
742+ leftAnnotations : this . maxOffsetLagAnnotations ,
743+ } ) ;
744+ }
745+
684746 createLambdaInsightsCpuWidget ( width : number , height : number ) {
685747 return new GraphWidget ( {
686748 width,
0 commit comments