Skip to content

Instantly share code, notes, and snippets.

@Dicee
Created August 16, 2022 18:43
Show Gist options
  • Save Dicee/f7d5a4cc1258359a9f66f16562afb3ea to your computer and use it in GitHub Desktop.
Save Dicee/f7d5a4cc1258359a9f66f16562afb3ea to your computer and use it in GitHub Desktop.
/**
* This class' sole purpose is to use LambdaFunctionMonitoring via composition rather than inheritance. The problem with the current design
* of the library is that it tries to be one-size-fits-all and packs a lot of features into extendable template classes. The issue is that
* these classes do not allow a decent level of customization. Extending them sometimes works, but can fail short in other cases.
*
* The solution? Ditch inheritance and use composition, allowing the user to do anything they want. Now, this class just becomes a thing that
* knows about Lambda and its monitoring, but doesn't try to impose one template for monitoring, only ingredients for users to do so.
* Thus, we just make all immutable properties public rather than protected.
*
* I opened a feature request on Github to get this pattern into the library directly: https://github.com/cdklabs/cdk-monitoring-constructs/issues/218
*/
export class OpenLambdaMonitoring extends LambdaFunctionMonitoring {
public readonly title: string
public readonly functionUrl?: string
public readonly namingStrategy: MonitoringNamingStrategy
public readonly metricFactory: LambdaFunctionMetricFactory
public readonly alarmFactory: AlarmFactory
public readonly errorAlarmFactory: ErrorAlarmFactory
public readonly latencyAlarmFactory: LatencyAlarmFactory
public readonly tpsAlarmFactory: TpsAlarmFactory
public readonly taskHealthAlarmFactory: TaskHealthAlarmFactory
public readonly ageAlarmFactory: AgeAlarmFactory
public readonly usageAlarmFactory: UsageAlarmFactory
public readonly latencyAnnotations: HorizontalAnnotation[]
public readonly errorCountAnnotations: HorizontalAnnotation[]
public readonly errorRateAnnotations: HorizontalAnnotation[]
public readonly invocationCountAnnotations: HorizontalAnnotation[]
public readonly invocationRateAnnotations: HorizontalAnnotation[]
public readonly tpsAnnotations: HorizontalAnnotation[]
public readonly cpuTotalTimeAnnotations: HorizontalAnnotation[]
public readonly memoryUsageAnnotations: HorizontalAnnotation[]
public readonly maxIteratorAgeAnnotations: HorizontalAnnotation[]
public readonly tpsMetric: MetricWithAlarmSupport
public readonly p50LatencyMetric: MetricWithAlarmSupport
public readonly p90LatencyMetric: MetricWithAlarmSupport
public readonly p99LatencyMetric: MetricWithAlarmSupport
public readonly faultCountMetric: MetricWithAlarmSupport
public readonly faultRateMetric: MetricWithAlarmSupport
public readonly invocationCountMetric: MetricWithAlarmSupport
public readonly throttlesCountMetric: MetricWithAlarmSupport
public readonly throttlesRateMetric: MetricWithAlarmSupport
public readonly concurrentExecutionsCountMetric: MetricWithAlarmSupport
public readonly provisionedConcurrencySpilloverInvocationsCountMetric: MetricWithAlarmSupport
public readonly provisionedConcurrencySpilloverInvocationsRateMetric: MetricWithAlarmSupport
public readonly maxIteratorAgeMetric: MetricWithAlarmSupport
public readonly lambdaInsightsEnabled: boolean
public readonly enhancedMetricFactory?: LambdaFunctionEnhancedMetricFactory
public readonly enhancedMonitoringMaxCpuTotalTimeMetric?: MetricWithAlarmSupport
public readonly enhancedMonitoringP90CpuTotalTimeMetric?: MetricWithAlarmSupport
public readonly enhancedMonitoringAvgCpuTotalTimeMetric?: MetricWithAlarmSupport
public readonly enhancedMonitoringMaxMemoryUtilizationMetric?: MetricWithAlarmSupport
public readonly enhancedMonitoringP90MemoryUtilizationMetric?: MetricWithAlarmSupport
public readonly enhancedMonitoringAvgMemoryUtilizationMetric?: MetricWithAlarmSupport
public readonly enhancedMetricFunctionCostMetric?: MetricWithAlarmSupport
public createTitleWidget(): MonitoringHeaderWidget {
return super.createTitleWidget()
}
public createTpsWidget(width: number, height: number): GraphWidget {
return super.createTpsWidget(width, height)
}
public createLatencyWidget(width: number, height: number): GraphWidget {
return super.createLatencyWidget(width, height)
}
public createErrorCountWidget(width: number, height: number): GraphWidget {
return super.createErrorCountWidget(width, height)
}
public createErrorRateWidget(width: number, height: number): GraphWidget {
return super.createErrorRateWidget(width, height)
}
public createRateWidget(width: number, height: number): GraphWidget {
return super.createRateWidget(width, height)
}
public createInvocationWidget(width: number, height: number): GraphWidget {
return super.createInvocationWidget(width, height)
}
public createIteratorAgeWidget(width: number, height: number): GraphWidget {
return super.createIteratorAgeWidget(width, height)
}
public createLambdaInsightsCpuWidget(width: number, height: number): GraphWidget {
return super.createLambdaInsightsCpuWidget(width, height)
}
public createLambdaInsightsMemoryWidget(width: number, height: number): GraphWidget {
return super.createLambdaInsightsMemoryWidget(width, height)
}
public createLambdaInsightsFunctionCostWidget(width: number, height: number): GraphWidget {
return super.createLambdaInsightsFunctionCostWidget(width, height)
}
constructor(monitoring: AmazonMonitoringFacade, props: LambdaFunctionMonitoringProps) {
super(monitoring, props)
}
}
@Dicee
Copy link
Author

Dicee commented Aug 16, 2022

This gist is in relation to this issue: cdklabs/cdk-monitoring-constructs#218. The class thus created was used to implement highly customized monitoring for one single lambda in the application, with special properties (triggered by a single source at a known frequency):

public monitorSnapshotGenerationFunction(fn: SecureFunction) {
    const period = SNAPSHOT_POLLING_RATE;
    const lambdaMonitoring = new OpenLambdaMonitoring(this.monitoring, this.serviceHealthAlarmCollector, {
        lambdaFunction: fn,
        addFaultCountAlarm: {
            '': {maxErrorCount: 0 /* exclusive */, evaluationPeriods: 3, datapointsToAlarm: 3, period}
        }
    })

    this.monitoring.addSegment(new class {
        widgets() {
            return [
                lambdaMonitoring.createTitleWidget(),
                lambdaMonitoring.createErrorCountWidget(DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT),
                createNewSnapshotGeneratedWidget(period), // custom business metric
            ]
        }

        alarmWidgets() {return []}
        summaryWidgets() {return []}
    })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment