getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.98k stars 1.57k forks source link

Auto-instrumenting Mongoose@8 fails #13672

Closed SteffenLanger closed 1 month ago

SteffenLanger commented 1 month ago

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/node

SDK Version

8.30.0

Framework Version

Node.js v22.1.0 macOS 14.6.1

Link to Sentry event

No response

Reproduction Example/SDK Setup

Reproduction repo at https://github.com/SteffenLanger/reproduce-mongoose-integration-sentry-bug

package.json

{
  "name": "reproduce-mongoose-integration-sentry-bug",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node --import=./instrument.js index.js"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "typescript": "^5.6.2"
  },
  "dependencies": {
    "@sentry/node": "^8.30.0",
    "express": "^4.21.0",
    "mongoose": "^8.6.2"
  }
}

instrument.js

import * as Sentry from "@sentry/node";

// Ensure to call this before importing any other modules!
Sentry.init({
    dsn: "https://e6e1170322fc4adf5e394017eb219daa@o4507106464825344.ingest.de.sentry.io/4507106471641168",

    // Add Tracing by setting tracesSampleRate
    // We recommend adjusting this value in production
    tracesSampleRate: 1.0,
});
console.log("Sentry initialized");

index.js

import mongoose from 'mongoose';

console.log('Mongoose was loaded', !!mongoose);

Steps to Reproduce

Start the index.js script: node --import=./instrument.js index.js

Expected Result

The script should run without errors.

Actual Result

An error is thrown and the script exits.

Sentry initialized
TypeError: Cannot read properties of undefined (reading 'prototype')
    at MongooseInstrumentation.patch (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/@opentelemetry/instrumentation-mongoose/build/src/mongoose.js:94:44)
    at MongooseInstrumentation._onRequire (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/@opentelemetry/instrumentation/build/src/platform/node/instrumentation.js:164:39)
    at hookFn (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/@opentelemetry/instrumentation/build/src/platform/node/instrumentation.js:222:29)
    at callHookFn (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/import-in-the-middle/index.js:29:22)
    at Hook._iitmHook (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/import-in-the-middle/index.js:150:11)
    at /Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/import-in-the-middle/lib/register.js:28:31
    at Array.forEach (<anonymous>)
    at register (/Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/import-in-the-middle/lib/register.js:28:15)
    at file:///Users/steffen/projects/open-source/reproduce-mongoose-integration-sentry-bug/node_modules/mongoose/index.js?iitm=true:381:1
    at ModuleJob.run (node:internal/modules/esm/module_job:262:25)

The issue seems to lie in Sentry's dependency @opentelemetry/instrumentation-mongoose at node_modules/@opentelemetry/instrumentation-mongoose/build/src/mongoose.js:94:44). It tries to monkey patch mongoose.Aggregate but Aggregate does not exist on Mongoose (anymore?).

This is the opentelemetry code (see "<-- ISSUE LIES HERE"):

patch(moduleExports, moduleVersion) {
        this._wrap(moduleExports.Model.prototype, 'save', this.patchOnModelMethods('save', moduleVersion));
        // mongoose applies this code on module require:
        // Model.prototype.$save = Model.prototype.save;
        // which captures the save function before it is patched.
        // so we need to apply the same logic after instrumenting the save function.
        moduleExports.Model.prototype.$save = moduleExports.Model.prototype.save;
        if (instrumentRemove(moduleVersion)) {
            this._wrap(moduleExports.Model.prototype, 'remove', this.patchOnModelMethods('remove', moduleVersion));
        }
        this._wrap(moduleExports.Query.prototype, 'exec', this.patchQueryExec(moduleVersion));
        this._wrap(moduleExports.Aggregate.prototype, 'exec', this.patchAggregateExec(moduleVersion)); // <-- ISSUE LIES HERE
        const contextCaptureFunctions = getContextCaptureFunctions(moduleVersion);
        contextCaptureFunctions.forEach((funcName) => {
            this._wrap(moduleExports.Query.prototype, funcName, this.patchAndCaptureSpanContext(funcName));
        });
        this._wrap(moduleExports.Model, 'aggregate', this.patchModelAggregate());
        return moduleExports;
    }
chargome commented 1 month ago

@onurtemizkan could you have a look at this?

Systerr commented 1 month ago

Affected me as well. Node v22.8.0 in ubuntu 24.04. AWS ARM64 machine Interesting fact - inside docker with ubuntu 22.04 and node 22.8.0 it works well (mac m1 as a host)

andreiborza commented 1 month ago

Thanks for the extra info, we're still looking into this.

onurtemizkan commented 1 month ago

Hi all! It looks like the root of this issue is fixed on mongoose v8.6.3 (Fix PR). Please reopen if the issue persists after updating to 8.6.3. Thanks!