Hi, I tried to add a lambda layer to all of my fun...
# sst
k
Hi, I tried to add a lambda layer to all of my functions using
app.setDefaultFunctionProps
but it looks like you can only do that within the context of a stack, I think there should be an easier way to add lambda layers for all functions in all my stacks (I ended up just adding it to one of the stacks that the others are dependent on)
f
Hey @Kujtim Hoxha, were you using an existing layer?
Copy code
LayerVersion.fromLayerVersionArn(this, "Layer", layerArn);
Or were you creating a new layer?
Copy code
new lambda.LayerVersion(this, 'Layer', {
  code: lambda.Code.fromAsset(...),
});
k
An existing layer
Specifically the sentry one
f
Oh, what was the error you were getting?
And can I see what your
app.setDefaultFunctionProps
looked like?
k
Copy code
const sentryLayer = lambda.LayerVersion.fromLayerVersionArn(
      this,
      'SentryLayer',
      'arn:aws:lambda:us-east-1:943013980633:layer:SentryNodeServerlessSDK:26'
    );

    app.setDefaultFunctionProps({
      layers: process.env.IS_LOCAL ? [] : [sentryLayer],
    });
f
hmm, it won’t work b/c
this
isn’t a Stack right. Was that the error you were getting?
k
Wait sorry no instead of this I had
app
let me try again and give you the error
Copy code
Import at 'SentryLayer' should be created in the scope of a Stack, but no Stack found
f
Yeah, try this:
Copy code
const sentryLayer = (stack) => lambda.LayerVersion.fromLayerVersionArn(
      stack,
      'SentryLayer',
      'arn:aws:lambda:us-east-1:943013980633:layer:SentryNodeServerlessSDK:26'
    );

  app.setDefaultFunctionProps((stack) => ({
    layers: process.env.IS_LOCAL ? [] : [sentryLayer(stack)],
  }));
k
That did it 😮
Thanks man
j
Hey @Kujtim Hoxha, curious how you got this working. Are you calling
Sentry.init({})
in each lambda handler?
k
Accidentally deleted my previous message 🤦‍♂️ So basically anything that has to do with sentry I only setup if I am not doing local development
Copy code
app.setDefaultFunctionProps((stack) => {
    stackLayer[stack.artifactId] =
      stackLayer[stack.artifactId] || sentryLayer(stack);
    return {
      layers: process.env.IS_LOCAL ? [] : [stackLayer[stack.artifactId]],
    };
  });
And for the handlers
Copy code
if (process.env.NODE_ENV !== 'development') {
  // x-ray tracing for all aws services
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  captureAWS(require('aws-sdk'));
  const Sentry = require('@sentry/serverless');

  Sentry.AWSLambda.init({
    dsn: process.env.SENTRY_DNS,

    // We recommend adjusting this value in production, or using tracesSampler
    // for finer control
    tracesSampleRate: process.env.SENTRY_TRACES_SAMPLE_RATE,
  });
}
To get
NODE_ENV
inside your functions just add this
j
Thank you, I’ll try it out 😄
k
@Janessa just one change from the example @Frank shared, it looks like the method is called multiple times for the same stack (at least for me it was) so I had to check if I already added the layer
Copy code
const sentryLayer = (stack: Stack) => {
  return lambda.LayerVersion.fromLayerVersionArn(
    stack,
    'SentryLayer',
    'arn:aws:lambda:us-east-1:943013980633:layer:SentryNodeServerlessSDK:26'
  );
};

const stackLayer: { [key: string]: ILayerVersion } = {};
app.setDefaultFunctionProps((stack) => {
  stackLayer[stack.artifactId] =
    stackLayer[stack.artifactId] || sentryLayer(stack);
  return {
    layers: process.env.IS_LOCAL ? [] : [stackLayer[stack.artifactId]],
  };
});
^ here is the full code
j
I see the layer on my lambda, but I’m not getting anything in Sentry 🤔 Do you see anything wrong about this?
Copy code
export const lambdaHandler: Handler = (async (event: Event, context: Context) => {
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const Sentry = require('@sentry/serverless');

  Sentry.AWSLambda.init({
    dsn: process.env.SENTRY_DNS,

    // We recommend adjusting this value in production, or using tracesSampler
    // for finer control
    tracesSampleRate: 1.0 //process.env.SENTRY_TRACES_SAMPLE_RATE,
  });
  try {
    randomFunction()
  } catch (error) {
    console.log("Error!")
    Sentry.captureException(error)
  }
})

const randomFunction = () => {
  throw new Error("Function not implemented.");
}
k
do you have the
SENTRY_DNS
setup ?
j
yeah, I also printed out the sentry client in my lambda and it has the expected value for the dsn
k
Instead of using
Sentry.captureException(error)
try doing
Sentry.AWSLambda.init
outside of your handler function and wrap the handler using
Copy code
if (process.env.NODE_ENV !== 'development') {
  handler = Sentry.AWSLambda.wrapHandler(handler);
}
j
I’ve gotten it to work using the Sentry wrapHandler method, but I was hoping I could avoid it by using the Sentry Layer 😅 Maybe not though?
k
I think you will have to use both 🤔 but maybe I am wrong
Why are you trying to avoid the wrapper ?
j
Ooh maybe that is the case, is the layer just another way of injecting the sentry module then? I was trying to avoid the wrapper because I didn’t want to have to go back and wrap all existing lambda handlers with it
k
Ah yeah the layer just ads the module (i think)
j
I see. Thank you for your help!! 🙏
k
If you already need to go back and wrap all the functions maybe create a middleware that adds the sentry wrapper and use that middleware, and from now on if you have to wrap all the functions again you could just add it to the middleware
I personally use
middy
Copy code
export const wrapper = (handler: LambdaHandler, logger?: Logger): any => {
  if (process.env.NODE_ENV !== 'development') {
    handler = Sentry.AWSLambda.wrapHandler(handler);
  }
  return middy(handler)
    .use(warmerMiddleware())
    .use(httpEventNormalizer())
    .use(httpHeaderNormalizer())
    .use(httpJsonBodyParser())
    .use(httpUrlEncodeBodyParser())
    .use(authMiddleware())
    .use(httpCors())
    .use(errorMiddleware(logger))
    .use(httpResponseSerializer());
};
And now all my functions look like
Copy code
export const handler = wrapper(async (event: APIGatewayProxyEvent) => {
....
})