getsentry / sentry-javascript-bundler-plugins

JavaScript Bundler Plugins for Sentry
https://sentry.io
BSD 3-Clause "New" or "Revised" License
142 stars 37 forks source link

Sourcemaps repeatedly uploading with esbuild plugin #615

Closed ancheetah closed 1 month ago

ancheetah commented 1 month ago

Environment

"@sentry/aws-serverless": "^8.26.0" "@sentry/esbuild-plugin": "^2.22.2" "serverless": "^3.26.0" "serverless-esbuild": "^1.52.1"

Description

Sourcemaps should be uploaded for aws lambda functions when packaging (sls package). I've tried two different configurations:

  1. Loading the sentry esbuild-plugin as a serverless-esbuild plugin as suggested here. This results in good stack traces but the sourcemaps are uploaded repeatedly when run in a Github Action. It finds something like 4 files then uploads then 8 files then uploads and repeats until it finds all the files. How often it's uploaded and the number of files found is different every time.

serverless.yml

package:
  individually: true

custom:
  esbuild:
    bundle: true
    minify: false
    sourcemap: true
    platform: 'node'
    outputBuildFolder: '.build'
    keepOutputDirectory: true
    skipRebuild: true
    logLevel: debug
    plugins: './esbuild.plugins.js'

esbuild.plugin.js

const { sentryEsbuildPlugin } = require('@sentry/esbuild-plugin');

module.exports = (serverless) => {
  return [
      sentryEsbuildPlugin({
        org: my_org,
        project: my_project,
        authToken:
          process.env.SOURCEMAPS === 'true'
            ? serverless.configurationInput.provider.environment.SENTRY_AUTH_TOKEN
            : undefined,
        sourcemaps: {
          assets: ['./.esbuild/.build/**/*'],
          filesToDeleteAfterUpload: ['./.esbuild/.build/**/*.js.map'],
        },
        telemetry: false,
        debug: true,
      }),
    ]
  }
  1. Loading the sentry plugin within the esbuild.config.js as per the documentation. This uploads the sourcemaps only once however the sourcemap debug IDs are injected into the output esbuild folder but not the .serverless folder which gets deployed so we get no stack trace in Sentry.

serverless.yml

package:
  individually: true

custom:
  esbuild:
    config: './esbuild.config.js'

esbuild.config.js

const { sentryEsbuildPlugin } = require("@sentry/esbuild-plugin");
const esbuild = require("esbuild");
const glob = require("glob");

module.exports = async (serverless) => {
  const sources = glob.sync('./src/**/index.ts');

  await esbuild.build({
    entryPoints: sources,
    bundle: true,
    minify: false,
    sourcemap: true,
    platform: 'node',
    outdir: '.dist-esbuild',
    logLevel: 'debug',
    plugins: [
    sentryEsbuildPlugin({
      org: my_org,
      project: my_project,
      authToken: process.env.SOURCEMAPS === 'true'
        ? serverless.configurationInput.provider.environment.SENTRY_AUTH_TOKEN 
        : undefined,
      sourcemaps: {
        assets: './.dist-esbuild/**/*',
        filesToDeleteAfterUpload: ['./.dist-esbuild/**/*.js.map'],
      },
      telemetry: false,
      debug: true,
    }),
    ]
  })
}
lforst commented 1 month ago

Hi, can you verify how often other plugins are called with sls? I fear this is up to sls and nothing we can control.

ancheetah commented 1 month ago

Hi @lforst, with the first method, according to the logs the esbuild is run only once before the sentry plugin. It is when the sentry plugin starts that it repeatedly uploads. Here is a sample of logs that keep repeating (some info redacted). Happy to share more with you privately.

> Found 10 files
> Analyzing 10 sources
> Adding source map references
> Bundled 6 files for upload
> Bundle ID: 12345
> Uploaded files to Sentry
> Found 12 files
> File upload complete (processing pending on server)
> Organization: my-org
> Project: my-project
> Release: 12345
> Dist: None
> Upload type: artifact bundle
lforst commented 1 month ago

Nothing sticks out to me as what may cause this. Would you mind providing a reproduction example so we can investigate further? Thanks!

ancheetah commented 1 month ago

@lforst here is a reproduction with a Github action that you can use to test

https://github.com/ancheetah/serverless-sentry-esbuild

lforst commented 1 month ago

This rang a bell and I dug out this issue: https://github.com/getsentry/sentry-javascript-bundler-plugins/issues/245

It seems like sls is repeatedly calling esbuild. Unfortunately, from the plugin's perspective, there is nothing (reasonable) we can do to prevent the plugin being invoked multiple times. You can potentially narrow down the upload scope of the plugin with sourcemaps.assets.

As an alternative, you can also use Sentry CLI to upload sourcemaps which you can invoke once for all of your bundles: https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/cli/

ancheetah commented 1 month ago

Thanks for tracking that down. I think using the Sentry CLI after building and packaging will be a good workaround. However, the sentry-esbuild plugin is still needed to inject the debug IDs at the time of packaging with sls since it is those packaged files that will get deployed. Could you add an option to the sentry-esbuild plugin that injects the debug IDs but skips uploads?

mydea commented 1 month ago

You should not need the esbuild plugin when you use sentry-cli - see https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/cli/#3-inject-debug-ids-into-artifacts for how to inject the debug IDs directly in this scenario! Let us know if that does not work for you.

ancheetah commented 1 month ago

This works for us. Thanks @mydea!