Skip to content

Instantly share code, notes, and snippets.

@Kilowhisky
Last active October 29, 2024 19:27
Show Gist options
  • Save Kilowhisky/84cc274eff9f2048b729eedfa8d0c44a to your computer and use it in GitHub Desktop.
Save Kilowhisky/84cc274eff9f2048b729eedfa8d0c44a to your computer and use it in GitHub Desktop.
NewRelic instrumentation for AWS CDK NodeJS function
import { Stack } from "aws-cdk-lib"
import { Runtime, Architecture, ILayerVersion, LayerVersion, CfnFunction } from "aws-cdk-lib/aws-lambda"
import { NodejsFunction, NodejsFunctionProps } from "aws-cdk-lib/aws-lambda-nodejs"
import { Secret } from "aws-cdk-lib/aws-secretsmanager"
import { Construct } from "constructs"
/**
* A NodejsFunction with New Relic instrumentation.
* @see https://forum.newrelic.com/s/hubtopic/aAX8W0000008d3MWAQ/setting-up-new-relic-with-cdk
*/
export class NodejsFunctionWithNewRelic extends NodejsFunction {
constructor(scope: Construct, id: string, props: NodejsFunctionProps) {
const getLayerFromRuntimeAndArch = (
runtime: Runtime = Runtime.NODEJS_20_X,
arch: Architecture = Architecture.X86_64
): ILayerVersion => {
const region = Stack.of(scope).region
// See layers from here: https://layers.newrelic-external.com/
if (runtime === Runtime.NODEJS_18_X && arch === Architecture.X86_64) {
return LayerVersion.fromLayerVersionArn(
scope,
`${id}-newRelicLayer`,
`arn:aws:lambda:${region}:451483290750:layer:NewRelicNodeJS18X:88`
)
} else if (runtime === Runtime.NODEJS_18_X && arch === Architecture.ARM_64) {
return LayerVersion.fromLayerVersionArn(
scope,
`${id}-newRelicLayer`,
`arn:aws:lambda:${region}:451483290750:layer:NewRelicNodeJS18XARM64:88`
)
} else if (runtime === Runtime.NODEJS_20_X && arch === Architecture.X86_64) {
return LayerVersion.fromLayerVersionArn(
scope,
`${id}-newRelicLayer`,
`arn:aws:lambda:${region}:451483290750:layer:NewRelicNodeJS20X:38`
)
} else if (runtime === Runtime.NODEJS_20_X && arch === Architecture.ARM_64) {
return LayerVersion.fromLayerVersionArn(
scope,
`${id}-newRelicLayer`,
`arn:aws:lambda:${region}:451483290750:layer:NewRelicNodeJS20XARM64:38`
)
}
throw new Error("Runtime must be NODEJS_18_X|NODEJS_20_X and Architecture must be X86_64|ARM_64")
}
const stage = scope.node.tryGetContext("stage");
const newRelicUKey = Secret.fromSecretNameV2(scope, `${id}-newrelic-usecret`, `${stage}/newrelic/ukey`)
const newRelicLKey = Secret.fromSecretNameV2(scope, `${id}-newrelic-lsecret`, `${stage}/newrelic/lkey`)
super(scope, id, {
...props,
bundling: {
sourceMap: true,
externalModules: ['newrelic']
},
layers: [...(props.layers ?? []), getLayerFromRuntimeAndArch(props.runtime, props.architecture)],
environment: {
...props.environment,
NEW_RELIC_ACCOUNT_ID: newRelicUKey.secretValueFromJson("account").unsafeUnwrap(),
NEW_RELIC_LICENSE_KEY: newRelicLKey.secretValue.unsafeUnwrap(),
NEW_RELIC_LAMBDA_HANDLER: `index.${props.handler || 'handler'}`,
// Enable logging
NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS: "true",
NEW_RELIC_EXTENSION_LOG_LEVEL: "WARN",
NEW_RELIC_DATA_COLLECTION_TIMEOUT: "2s",
// Performance related "suggested"
// https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/introduction-lambda/
NEW_RELIC_USE_ESM: "true",
NEW_RELIC_NATIVE_METRICS_ENABLED: "false",
NEW_RELIC_NO_CONFIG_FILE: "true"
},
})
// Override handler as per https://github.com/aws/aws-cdk/issues/16795#issuecomment-937544205
const handler = this.node.defaultChild as CfnFunction
handler.addOverride("Properties.Handler", "newrelic-lambda-wrapper.handler")
// Grant read to New Relic license key secret
newRelicLKey.grantRead(this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment