diff --git a/.github/component_owners.yml b/.github/component_owners.yml
index 85120136a8..d6ea67a435 100644
--- a/.github/component_owners.yml
+++ b/.github/component_owners.yml
@@ -72,6 +72,10 @@ components:
- blumamir
packages/instrumentation-socket.io:
- mottibec
+ packages/instrumentation-sequelize:
+ - seemk
+ - t2t2
+ - mhennoch
packages/instrumentation-tedious: []
# Unmaintained
packages/instrumentation-typeorm:
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 0a774e6f9d..2e5f624394 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -27,6 +27,7 @@
"packages/instrumentation-lru-memoizer": "0.52.0",
"packages/instrumentation-mongoose": "0.54.0",
"packages/instrumentation-runtime-node": "0.21.0",
+ "packages/instrumentation-sequelize": "0.1.0",
"packages/instrumentation-socket.io": "0.54.0",
"packages/instrumentation-tedious": "0.26.0",
"packages/instrumentation-typeorm": "0.8.0",
diff --git a/package-lock.json b/package-lock.json
index 02236413db..357af68cce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2282,7 +2282,6 @@
"integrity": "sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.6",
@@ -4172,7 +4171,6 @@
"integrity": "sha512-b7W4snvXYi1T2puUjxamASCCNhNzVSzb/fQUuGSkdjm/AFfJ24jo8kOHQyOcaoArCG71sVQci4vkZaITzl/V1w==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@cucumber/ci-environment": "10.0.1",
"@cucumber/cucumber-expressions": "18.0.1",
@@ -4254,7 +4252,6 @@
"integrity": "sha512-659CCFsrsyvuBi/Eix1fnhSheMnojSfnBcqJ3IMPNawx7JlrNJDcXYSSdxcUw3n/nG05P+ptCjmiZY3i14p+tA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@cucumber/messages": ">=19.1.4 <29"
}
@@ -4411,7 +4408,6 @@
"integrity": "sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==",
"dev": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@cucumber/messages": ">=17.1.1"
}
@@ -4422,7 +4418,6 @@
"integrity": "sha512-2LzZtOwYKNlCuNf31ajkrekoy2M4z0Z1QGiPH40n4gf5t8VOUFb7m1ojtR4LmGvZxBGvJZP8voOmRqDWzBzYKA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/uuid": "10.0.0",
"class-transformer": "0.5.1",
@@ -7344,7 +7339,6 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@napi-rs/wasm-runtime": "0.2.4",
"@yarnpkg/lockfile": "^1.1.0",
@@ -7646,7 +7640,6 @@
"integrity": "sha512-pzGXp14KF2Q4CDZGQgPK4l8zEg7i6cNkb+10yc8ZA5K41cLe3ZbWW1YxtY2e/glHauOJwTLSVjH4tiRVtOTizg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"iterare": "1.2.1",
"tslib": "2.8.1",
@@ -7729,7 +7722,6 @@
"integrity": "sha512-UVSf0yaWFBC2Zn2FOWABXxCnyG8XNIXrNnvTFpbUFqaJu1YDdwJ7wQBBqxq9CtJT7ILqSmfhOU7HS0d/0EAxpw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"cors": "2.8.5",
"express": "5.0.1",
@@ -9197,7 +9189,6 @@
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
@@ -9386,7 +9377,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
- "peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -9926,6 +9916,10 @@
"resolved": "packages/instrumentation-runtime-node",
"link": true
},
+ "node_modules/@opentelemetry/instrumentation-sequelize": {
+ "resolved": "packages/instrumentation-sequelize",
+ "link": true
+ },
"node_modules/@opentelemetry/instrumentation-socket.io": {
"resolved": "packages/instrumentation-socket.io",
"link": true
@@ -10424,7 +10418,6 @@
"integrity": "sha512-MZVUE+l7LmMIYlIjubPosruJ9ltSLGFmJqsXApTqPLyHLjsJUSAbAJb/A3N34fEqean4ddiDkdWzNu4ZKPvRUg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"cluster-key-slot": "1.1.2"
},
@@ -12216,6 +12209,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/debug": {
+ "version": "4.1.12",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
+ "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
@@ -12447,6 +12450,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/ms": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/mysql": {
"version": "2.15.27",
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz",
@@ -12461,7 +12471,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.9.tgz",
"integrity": "sha512-5yBtK0k/q8PjkMXbTfeIEP/XVYnz1R9qZJ3yUicdEW7ppdDJfe+MqXEhpqDL3mtn4Wvs1u0KLEG0RXzCgNpsSg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -12543,7 +12552,6 @@
"integrity": "sha512-I98SaDCar5lvEYl80ClRIUztH/hyWHR+I2f+5yTVp/MQ205HgYkA2b5mVdry/+nsEIrf8I65KA5V/PASx68MsQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "^0.16",
@@ -12705,6 +12713,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/validator": {
+ "version": "13.15.3",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz",
+ "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/webidl-conversions": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -12813,7 +12828,6 @@
"integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.41.0",
"@typescript-eslint/types": "8.41.0",
@@ -13861,7 +13875,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -13978,7 +13991,6 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -14814,7 +14826,6 @@
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
@@ -15388,7 +15399,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.9",
"caniuse-lite": "^1.0.30001746",
@@ -17455,8 +17465,7 @@
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz",
"integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==",
"dev": true,
- "license": "BSD-3-Clause",
- "peer": true
+ "license": "BSD-3-Clause"
},
"node_modules/di": {
"version": "0.0.1",
@@ -17566,6 +17575,13 @@
"url": "https://dotenvx.com"
}
},
+ "node_modules/dottie": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz",
+ "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
@@ -18287,7 +18303,6 @@
"integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -21195,6 +21210,16 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/inflection": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
+ "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==",
+ "dev": true,
+ "engines": [
+ "node >= 0.4.0"
+ ],
+ "license": "MIT"
+ },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -22951,7 +22976,6 @@
"integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@colors/colors": "1.5.0",
"body-parser": "^1.19.0",
@@ -24533,7 +24557,6 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@napi-rs/wasm-runtime": "0.2.4",
"@yarnpkg/lockfile": "^1.1.0",
@@ -26669,7 +26692,19 @@
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"dev": true,
"license": "MIT",
- "optional": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/moment-timezone": {
+ "version": "0.5.48",
+ "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz",
+ "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "moment": "^2.29.4"
+ },
"engines": {
"node": "*"
}
@@ -27964,7 +27999,6 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@napi-rs/wasm-runtime": "0.2.4",
"@yarnpkg/lockfile": "^1.1.0",
@@ -29390,7 +29424,6 @@
"integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
@@ -30236,7 +30269,6 @@
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
@@ -30699,8 +30731,7 @@
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"dev": true,
- "license": "Apache-2.0",
- "peer": true
+ "license": "Apache-2.0"
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
@@ -31234,6 +31265,13 @@
"node": "*"
}
},
+ "node_modules/retry-as-promised": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz",
+ "integrity": "sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -31335,7 +31373,6 @@
"integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -31455,7 +31492,6 @@
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -31696,6 +31732,89 @@
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==",
"dev": true
},
+ "node_modules/sequelize": {
+ "version": "6.37.7",
+ "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.7.tgz",
+ "integrity": "sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sequelize"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/debug": "^4.1.8",
+ "@types/validator": "^13.7.17",
+ "debug": "^4.3.4",
+ "dottie": "^2.0.6",
+ "inflection": "^1.13.4",
+ "lodash": "^4.17.21",
+ "moment": "^2.29.4",
+ "moment-timezone": "^0.5.43",
+ "pg-connection-string": "^2.6.1",
+ "retry-as-promised": "^7.0.4",
+ "semver": "^7.5.4",
+ "sequelize-pool": "^7.1.0",
+ "toposort-class": "^1.0.1",
+ "uuid": "^8.3.2",
+ "validator": "^13.9.0",
+ "wkx": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ibm_db": {
+ "optional": true
+ },
+ "mariadb": {
+ "optional": true
+ },
+ "mysql2": {
+ "optional": true
+ },
+ "oracledb": {
+ "optional": true
+ },
+ "pg": {
+ "optional": true
+ },
+ "pg-hstore": {
+ "optional": true
+ },
+ "snowflake-sdk": {
+ "optional": true
+ },
+ "sqlite3": {
+ "optional": true
+ },
+ "tedious": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sequelize-pool": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz",
+ "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/sequelize/node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
@@ -33982,7 +34101,6 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -34453,6 +34571,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/toposort-class": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
+ "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/tr46": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
@@ -34588,7 +34713,6 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -35127,7 +35251,6 @@
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -35571,6 +35694,16 @@
"node": "^18.17.0 || >=20.5.0"
}
},
+ "node_modules/validator": {
+ "version": "13.15.15",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz",
+ "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -35686,7 +35819,6 @@
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "^1.0.5",
"@webassemblyjs/ast": "^1.12.1",
@@ -35734,7 +35866,6 @@
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^2.1.1",
@@ -36142,6 +36273,16 @@
"node": ">=0.1.90"
}
},
+ "node_modules/wkx": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz",
+ "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -36681,8 +36822,7 @@
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
"integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"packages/auto-configuration-propagators": {
"name": "@opentelemetry/auto-configuration-propagators",
@@ -39146,6 +39286,312 @@
"dev": true,
"license": "MIT"
},
+ "packages/instrumentation-sequelize": {
+ "name": "@opentelemetry/instrumentation-sequelize",
+ "version": "0.1.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "^2.0.0",
+ "@opentelemetry/instrumentation": "^0.207.0",
+ "@opentelemetry/semantic-conventions": "^1.27.0"
+ },
+ "devDependencies": {
+ "@opentelemetry/api": "^1.3.0",
+ "@opentelemetry/contrib-test-utils": "^0.54.0",
+ "@opentelemetry/sdk-trace-base": "^2.0.0",
+ "@types/node": "18.18.14",
+ "nyc": "15.1.0",
+ "rimraf": "5.0.10",
+ "sequelize": "^6.37.3",
+ "typescript": "5.0.4"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/@types/node": {
+ "version": "18.18.14",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.14.tgz",
+ "integrity": "sha512-iSOeNeXYNYNLLOMDSVPvIFojclvMZ/HDY2dU17kUlcsOsSQETbWIslJbYLZgA+ox8g2XQwSHKTkght1a5X26lQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/instrumentation-sequelize/node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/instrumentation-sequelize/node_modules/foreground-child": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/nyc": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+ "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "caching-transform": "^4.0.0",
+ "convert-source-map": "^1.7.0",
+ "decamelize": "^1.2.0",
+ "find-cache-dir": "^3.2.0",
+ "find-up": "^4.1.0",
+ "foreground-child": "^2.0.0",
+ "get-package-type": "^0.1.0",
+ "glob": "^7.1.6",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-hook": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "istanbul-lib-processinfo": "^2.0.2",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.2",
+ "make-dir": "^3.0.0",
+ "node-preload": "^0.2.1",
+ "p-map": "^3.0.0",
+ "process-on-spawn": "^1.0.0",
+ "resolve-from": "^5.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "spawn-wrap": "^2.0.0",
+ "test-exclude": "^6.0.0",
+ "yargs": "^15.0.2"
+ },
+ "bin": {
+ "nyc": "bin/nyc.js"
+ },
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/nyc/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "packages/instrumentation-sequelize/node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/instrumentation-sequelize/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "packages/instrumentation-sequelize/node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "packages/instrumentation-sequelize/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"packages/instrumentation-socket.io": {
"name": "@opentelemetry/instrumentation-socket.io",
"version": "0.54.0",
diff --git a/packages/instrumentation-sequelize/.tav.yml b/packages/instrumentation-sequelize/.tav.yml
new file mode 100644
index 0000000000..49020bf64e
--- /dev/null
+++ b/packages/instrumentation-sequelize/.tav.yml
@@ -0,0 +1,5 @@
+sequelize:
+ versions:
+ include: '>=6 <7'
+ mode: max-7
+ commands: npm run test
diff --git a/packages/instrumentation-sequelize/LICENSE b/packages/instrumentation-sequelize/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/packages/instrumentation-sequelize/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/packages/instrumentation-sequelize/NOTICE b/packages/instrumentation-sequelize/NOTICE
new file mode 100644
index 0000000000..4fee72c6a6
--- /dev/null
+++ b/packages/instrumentation-sequelize/NOTICE
@@ -0,0 +1,6 @@
+[Based on the instrumentation written by Aspecto](https://github.com/aspecto-io/opentelemetry-ext-js/tree/master/packages/instrumentation-sequelize).
+
+The library contains the following changes compared to the original:
+* Removed `moduleVersionAttributeName` configuration option.
+* Various type declaration fixes.
+* Upgraded to latest instrumentation and semantic conventions.
\ No newline at end of file
diff --git a/packages/instrumentation-sequelize/README.md b/packages/instrumentation-sequelize/README.md
new file mode 100644
index 0000000000..898611cce8
--- /dev/null
+++ b/packages/instrumentation-sequelize/README.md
@@ -0,0 +1,96 @@
+# OpenTelemetry `sequelize` Instrumentation for Node.js
+
+[![NPM Published Version][npm-img]][npm-url]
+[![Apache License][license-image]][license-image]
+
+This module provides automatic instrumentation for the [`sequelize`](https://www.npmjs.com/package/sequelize) package, which may be loaded using the [`@opentelemetry/sdk-trace-node`](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package and is included in the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle.
+
+If total installation size is not constrained, it is recommended to use the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle with [@opentelemetry/sdk-node](`https://www.npmjs.com/package/@opentelemetry/sdk-node`) for the most seamless instrumentation experience.
+
+## Installation
+
+```bash
+npm install --save @opentelemetry/instrumentation-sequelize
+```
+
+### Supported versions
+
+- [`sequelize`](https://www.npmjs.com/package/sequelize) versions `>=6 <7`
+
+## Usage
+
+```js
+const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
+const { SequelizeInstrumentation } = require('@opentelemetry/instrumentation-sequelize');
+const { registerInstrumentations } = require('@opentelemetry/instrumentation');
+
+const provider = new NodeTracerProvider();
+provider.register();
+
+registerInstrumentations({
+ instrumentations: [
+ new SequelizeInstrumentation({
+ // see below for available configuration
+ }),
+ ],
+});
+export interface SequelizeInstrumentationConfig extends InstrumentationConfig {
+ /** Hook for adding custom attributes using the query */
+ queryHook?: SequelizeQueryHook;
+ /** Hook for adding custom attributes using the response payload */
+ responseHook?: SequelizeResponseCustomAttributesFunction;
+ /** Set to true if you only want to trace operation which has parent spans */
+ ignoreOrphanedSpans?: boolean;
+ /**
+ * Sequelize operation use postgres/mysql/mariadb/etc. under the hood.
+ * If, for example, postgres instrumentation is enabled, a postgres operation will also create
+ * a postgres span describing the communication.
+ * Setting the `suppressInternalInstrumentation` config value to `true` will
+ * cause the instrumentation to suppress instrumentation of underlying operations.
+ */
+ suppressInternalInstrumentation?: boolean;
+ * An identifier for the database management system (DBMS) product being used. See below for a list of well-known identifiers.
+```
+
+### Instrumentation Options
+
+You can set the following:
+
+| Options | Type | Description |
+| --------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------- |
+| `queryHook` | `SequelizeQueryHook` | Function called before running the query. Allows for adding custom attributes to the span. |
+| `responseHook` | `SequelizeResponseCustomAttributesFunction` | Function called after a response is received. Allows for adding custom attributes to the span. |
+| `ignoreOrphanedSpans` | `boolean` | Can be set to only produce spans which have parent spans. Default: `false` |
+| `suppressInternalInstrumentation` | `boolean` | Set to ignore the underlying database library instrumentation. Default: `false` |
+
+## Semantic Conventions
+
+| Attribute | Short Description |
+| ---------------------| --------------------------------------------------------------------------- |
+| `db.namespace` | The name of the database being accessed. |
+| `db.operation.name` | The name of the operation being executed (e.g. the SQL keyword). |
+| `db.collection.name` | The name of the table being accessed. |
+| `db.query.text` | The database statement being executed. |
+| `db.system.name` | An identifier for the database management system (DBMS) product being used. |
+| `server.address` | Remote address of the database. |
+| `server.port` | Peer port number of the network connection. |
+| `network transport` | OSI transport layer or inter-process communication method. |
+
+Attributes collected:
+
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions
+[license-url]: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-sequelize
+[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-sequelize.svg
diff --git a/packages/instrumentation-sequelize/package.json b/packages/instrumentation-sequelize/package.json
new file mode 100644
index 0000000000..486a89ac7b
--- /dev/null
+++ b/packages/instrumentation-sequelize/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "@opentelemetry/instrumentation-sequelize",
+ "version": "0.1.0",
+ "description": "OpenTelemetry instrumentation for `sequelize` ORM",
+ "main": "build/src/index.js",
+ "types": "build/src/index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/open-telemetry/opentelemetry-js-contrib.git",
+ "directory": "packages/instrumentation-sequelize"
+ },
+ "scripts": {
+ "clean": "rimraf build/*",
+ "compile": "tsc -p .",
+ "compile:with-dependencies": "nx run-many -t compile -p @opentelemetry/instrumentation-sequelize",
+ "lint:readme": "node ../../scripts/lint-readme.js",
+ "prepublishOnly": "npm run compile",
+ "tdd": "yarn test -- --watch-extensions ts --watch",
+ "test": "nyc --no-clean mocha --require '@opentelemetry/contrib-test-utils' 'test/**/*.test.ts'",
+ "test-all-versions": "tav",
+ "version:update": "node ../../scripts/version-update.js",
+ "watch": "tsc -w"
+ },
+ "keywords": [
+ "sequelize",
+ "instrumentation",
+ "nodejs",
+ "opentelemetry",
+ "tracing"
+ ],
+ "author": "OpenTelemetry Authors",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "files": [
+ "build/src/**/*.js",
+ "build/src/**/*.js.map",
+ "build/src/**/*.d.ts"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ },
+ "devDependencies": {
+ "@opentelemetry/api": "^1.3.0",
+ "@opentelemetry/contrib-test-utils": "^0.54.0",
+ "@opentelemetry/sdk-trace-base": "^2.0.0",
+ "@types/node": "18.18.14",
+ "nyc": "15.1.0",
+ "rimraf": "5.0.10",
+ "sequelize": "^6.37.3",
+ "typescript": "5.0.4"
+ },
+ "dependencies": {
+ "@opentelemetry/instrumentation": "^0.207.0",
+ "@opentelemetry/core": "^2.0.0",
+ "@opentelemetry/semantic-conventions": "^1.27.0"
+ },
+ "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-sequelize#readme"
+}
diff --git a/packages/instrumentation-sequelize/src/index.ts b/packages/instrumentation-sequelize/src/index.ts
new file mode 100644
index 0000000000..0cf727963d
--- /dev/null
+++ b/packages/instrumentation-sequelize/src/index.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright The OpenTelemetry Authors, Aspecto
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { SequelizeInstrumentation } from './instrumentation';
+export type {
+ SequelizeResponseCustomAttributesFunction,
+ SequelizeQueryHook,
+ SequelizeQueryHookParams,
+ SequelizeInstrumentationConfig,
+} from './types';
diff --git a/packages/instrumentation-sequelize/src/instrumentation.ts b/packages/instrumentation-sequelize/src/instrumentation.ts
new file mode 100644
index 0000000000..ce920bb11c
--- /dev/null
+++ b/packages/instrumentation-sequelize/src/instrumentation.ts
@@ -0,0 +1,245 @@
+/*
+ * Copyright The OpenTelemetry Authors, Aspecto
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+ context,
+ Span,
+ SpanKind,
+ SpanStatusCode,
+ trace,
+ diag,
+ Attributes,
+} from '@opentelemetry/api';
+import { suppressTracing } from '@opentelemetry/core';
+import {
+ ATTR_DB_COLLECTION_NAME,
+ ATTR_DB_OPERATION_NAME,
+ ATTR_DB_NAMESPACE,
+ ATTR_DB_QUERY_TEXT,
+ ATTR_DB_SYSTEM_NAME,
+ ATTR_SERVER_ADDRESS,
+ ATTR_SERVER_PORT,
+ ATTR_NETWORK_TRANSPORT,
+ NETWORK_TRANSPORT_VALUE_TCP,
+} from '@opentelemetry/semantic-conventions';
+import type * as sequelize from 'sequelize';
+import { SequelizeInstrumentationConfig } from './types';
+/** @knipignore */
+import { PACKAGE_NAME, PACKAGE_VERSION } from './version';
+import { extractTableFromQuery } from './utils';
+import {
+ InstrumentationBase,
+ InstrumentationNodeModuleDefinition,
+ InstrumentationNodeModuleFile,
+ isWrapped,
+ safeExecuteInTheMiddle,
+} from '@opentelemetry/instrumentation';
+
+export class SequelizeInstrumentation extends InstrumentationBase {
+ static readonly component = 'sequelize';
+ static readonly supportedVersions = '>=6 <7';
+
+ constructor(config: SequelizeInstrumentationConfig = {}) {
+ super(PACKAGE_NAME, PACKAGE_VERSION, config);
+ }
+
+ protected init() {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const unpatchConnectionManager = (moduleExports: any) => {
+ if (
+ isWrapped(moduleExports?.ConnectionManager?.prototype?.getConnection)
+ ) {
+ this._unwrap(
+ moduleExports.ConnectionManager.prototype,
+ 'getConnection'
+ );
+ }
+ return moduleExports;
+ };
+ const connectionManagerInstrumentation = new InstrumentationNodeModuleFile(
+ 'sequelize/lib/dialects/abstract/connection-manager.js',
+ [SequelizeInstrumentation.supportedVersions],
+ moduleExports => {
+ if (moduleExports === undefined || moduleExports === null) {
+ return moduleExports;
+ }
+ unpatchConnectionManager(moduleExports);
+ this._wrap(
+ moduleExports.ConnectionManager.prototype,
+ 'getConnection',
+ this._getConnectionPatch()
+ );
+ return moduleExports;
+ },
+ unpatchConnectionManager
+ );
+
+ const unpatch = (moduleExports: typeof sequelize) => {
+ if (isWrapped(moduleExports.Sequelize.prototype.query)) {
+ this._unwrap(moduleExports.Sequelize.prototype, 'query');
+ }
+ };
+ const module = new InstrumentationNodeModuleDefinition(
+ SequelizeInstrumentation.component,
+ [SequelizeInstrumentation.supportedVersions],
+ moduleExports => {
+ if (moduleExports === undefined || moduleExports === null) {
+ return moduleExports;
+ }
+
+ unpatch(moduleExports);
+ this._wrap(
+ moduleExports.Sequelize.prototype,
+ 'query',
+ this._createQueryPatch()
+ );
+
+ return moduleExports;
+ },
+ unpatch,
+ [connectionManagerInstrumentation]
+ );
+ return module;
+ }
+
+ // run getConnection with suppressTracing, as it might call internally to `databaseVersion` function
+ // which calls `query` and create internal span which we don't need to instrument
+ private _getConnectionPatch() {
+ return (original: Function) => {
+ return function (this: unknown, ...args: unknown[]) {
+ return context.with(suppressTracing(context.active()), () =>
+ original.apply(this, args)
+ );
+ };
+ };
+ }
+
+ private _createQueryPatch() {
+ const self = this;
+ return (original: sequelize.Sequelize['query']) => {
+ return function query(
+ this: sequelize.Sequelize,
+ ...args: Parameters
+ ) {
+ if (
+ self.getConfig().ignoreOrphanedSpans &&
+ !trace.getSpan(context.active())
+ ) {
+ return original.apply(this, args);
+ }
+
+ const sqlOrQuery = args[0];
+ const extractStatement = (sql: typeof sqlOrQuery) => {
+ if (typeof sql === 'string') return sql;
+ return sql?.query || '';
+ };
+ const statement = extractStatement(args[0]).trim();
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const option = args[1] as any;
+ let operation = option?.type;
+
+ if (!operation) operation = statement.split(' ')[0];
+
+ const sequelizeInstance: sequelize.Sequelize = this;
+ const config = sequelizeInstance?.config;
+
+ let tableName = option?.instance?.constructor?.tableName;
+ if (!tableName) {
+ if (Array.isArray(option?.tableNames) && option.tableNames.length > 0)
+ tableName = option?.tableNames.sort().join(',');
+ else tableName = extractTableFromQuery(statement);
+ }
+
+ const attributes: Attributes = {
+ [ATTR_DB_SYSTEM_NAME]: sequelizeInstance.getDialect(),
+ [ATTR_DB_NAMESPACE]: config?.database,
+ [ATTR_DB_OPERATION_NAME]: operation,
+ [ATTR_DB_QUERY_TEXT]: statement,
+ [ATTR_DB_COLLECTION_NAME]: tableName,
+ [ATTR_SERVER_ADDRESS]: config?.host,
+ [ATTR_SERVER_PORT]: config?.port ? Number(config?.port) : undefined,
+ [ATTR_NETWORK_TRANSPORT]: self._getNetTransport(config?.protocol),
+ };
+
+ const newSpan: Span = self.tracer.startSpan(`Sequelize ${operation}`, {
+ kind: SpanKind.CLIENT,
+ attributes,
+ });
+
+ const activeContextWithSpan = trace.setSpan(context.active(), newSpan);
+
+ const hook = self.getConfig().queryHook;
+ if (hook !== undefined && sqlOrQuery !== undefined) {
+ safeExecuteInTheMiddle(
+ () => hook(newSpan, { sql: sqlOrQuery, option }),
+ e => {
+ if (e)
+ diag.error('sequelize instrumentation: queryHook error', e);
+ },
+ true
+ );
+ }
+
+ return (
+ context
+ .with(
+ self.getConfig().suppressInternalInstrumentation
+ ? suppressTracing(activeContextWithSpan)
+ : activeContextWithSpan,
+ () => original.apply(this, args)
+ )
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ .then((response: any) => {
+ const responseHook = self.getConfig().responseHook;
+ if (responseHook !== undefined) {
+ safeExecuteInTheMiddle(
+ () => responseHook(newSpan, response),
+ e => {
+ if (e)
+ diag.error(
+ 'sequelize instrumentation: responseHook error',
+ e
+ );
+ },
+ true
+ );
+ }
+ return response;
+ })
+ .catch((err: Error) => {
+ newSpan.setStatus({
+ code: SpanStatusCode.ERROR,
+ message: err.message,
+ });
+ throw err;
+ })
+ .finally(() => {
+ newSpan.end();
+ })
+ );
+ };
+ };
+ }
+
+ private _getNetTransport(protocol: string) {
+ switch (protocol) {
+ case 'tcp':
+ return NETWORK_TRANSPORT_VALUE_TCP;
+ default:
+ return undefined;
+ }
+ }
+}
diff --git a/packages/instrumentation-sequelize/src/types.ts b/packages/instrumentation-sequelize/src/types.ts
new file mode 100644
index 0000000000..287f0becd6
--- /dev/null
+++ b/packages/instrumentation-sequelize/src/types.ts
@@ -0,0 +1,52 @@
+/*
+ * Copyright The OpenTelemetry Authors, Aspecto
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Span } from '@opentelemetry/api';
+import { InstrumentationConfig } from '@opentelemetry/instrumentation';
+
+export interface SequelizeQueryHookParams {
+ /** The type of sql parameter depends on the database dialect. */
+ sql: string | { query: string; values: unknown[] };
+ /** The type of option parameter depends on the database dialect. */
+ option: any;
+}
+
+export type SequelizeQueryHook = (
+ span: Span,
+ params: T
+) => void;
+
+export type SequelizeResponseCustomAttributesFunction = (
+ span: Span,
+ response: any
+) => void;
+
+export interface SequelizeInstrumentationConfig extends InstrumentationConfig {
+ /** Hook for adding custom attributes using the query */
+ queryHook?: SequelizeQueryHook;
+ /** Hook for adding custom attributes using the response payload */
+ responseHook?: SequelizeResponseCustomAttributesFunction;
+ /** Set to true if you only want to trace operation which has parent spans */
+ ignoreOrphanedSpans?: boolean;
+ /**
+ * Sequelize operation use postgres/mysql/mariadb/etc. under the hood.
+ * If, for example, postgres instrumentation is enabled, a postgres operation will also create
+ * a postgres span describing the communication.
+ * Setting the `suppressInternalInstrumentation` config value to `true` will
+ * cause the instrumentation to suppress instrumentation of underlying operations.
+ */
+ suppressInternalInstrumentation?: boolean;
+}
diff --git a/packages/instrumentation-sequelize/src/utils.ts b/packages/instrumentation-sequelize/src/utils.ts
new file mode 100644
index 0000000000..d31f7541d0
--- /dev/null
+++ b/packages/instrumentation-sequelize/src/utils.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright The OpenTelemetry Authors, Aspecto
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const extractTableFromQuery = (query: string | null | undefined) => {
+ try {
+ const result = query?.match(/(?<=from|join|truncate)\s+"?`?(\w+)"?`?/gi);
+ if (!Array.isArray(result)) return;
+
+ return result
+ .map(table =>
+ table
+ .trim()
+ .replace(/^"(.*)"$/, '$1')
+ .replace(/^`(.*)`$/, '$1')
+ )
+ .sort()
+ .join(',');
+ } catch {
+ return;
+ }
+};
diff --git a/packages/instrumentation-sequelize/test/sequelize.test.ts b/packages/instrumentation-sequelize/test/sequelize.test.ts
new file mode 100644
index 0000000000..1f38005313
--- /dev/null
+++ b/packages/instrumentation-sequelize/test/sequelize.test.ts
@@ -0,0 +1,559 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import * as assert from 'assert';
+import { SequelizeInstrumentation } from '../src';
+import { extractTableFromQuery } from '../src/utils';
+import { ReadableSpan } from '@opentelemetry/sdk-trace-base';
+import {
+ context,
+ diag,
+ SpanStatusCode,
+ DiagConsoleLogger,
+ ROOT_CONTEXT,
+} from '@opentelemetry/api';
+import {
+ ATTR_DB_COLLECTION_NAME,
+ ATTR_DB_OPERATION_NAME,
+ ATTR_DB_NAMESPACE,
+ ATTR_DB_QUERY_TEXT,
+ ATTR_DB_SYSTEM_NAME,
+ ATTR_SERVER_ADDRESS,
+ ATTR_SERVER_PORT,
+} from '@opentelemetry/semantic-conventions';
+import {
+ getTestSpans,
+ registerInstrumentationTesting,
+} from '@opentelemetry/contrib-test-utils';
+
+const instrumentation = registerInstrumentationTesting(
+ new SequelizeInstrumentation()
+);
+
+import * as sequelize from 'sequelize';
+
+type QueryFunction = typeof sequelize.Sequelize.prototype.query;
+
+describe('instrumentation-sequelize', () => {
+ const getSequelizeSpans = (): ReadableSpan[] => {
+ return getTestSpans().filter(s =>
+ s.instrumentationScope.name.includes('sequelize')
+ ) as ReadableSpan[];
+ };
+
+ beforeEach(() => {
+ instrumentation.enable();
+ });
+
+ afterEach(() => {
+ instrumentation.disable();
+ });
+
+ describe('postgres', () => {
+ const DB_SYSTEM = 'postgres';
+ const DB_USER = 'some-user';
+ const SERVER_ADDRESS = 'localhost';
+ const SERVER_PORT = 12345;
+ const DB_NAME = 'my-db';
+
+ const instance = new sequelize.Sequelize(
+ `${DB_SYSTEM}://${DB_USER}@${SERVER_ADDRESS}:${SERVER_PORT}/${DB_NAME}`,
+ { logging: false }
+ );
+ class User extends sequelize.Model {
+ firstName: string = '';
+ }
+
+ User.init(
+ { firstName: { type: sequelize.DataTypes.STRING } },
+ { sequelize: instance }
+ );
+
+ it('create is instrumented', async () => {
+ try {
+ await User.create({ firstName: 'OpenTelemetry' });
+ } catch {
+ // Error is thrown but we don't care
+ }
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ assert.strictEqual(spans[0].status.code, SpanStatusCode.ERROR);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], DB_SYSTEM);
+ assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], SERVER_ADDRESS);
+ assert.strictEqual(attributes[ATTR_SERVER_PORT], SERVER_PORT);
+ assert.strictEqual(attributes[ATTR_DB_NAMESPACE], DB_NAME);
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.match(
+ attributes[ATTR_DB_QUERY_TEXT] as string,
+ /INSERT INTO "Users" \("id","firstName","createdAt","updatedAt"\) VALUES \(DEFAULT,\$1,\$2,\$3\) RETURNING (\*|"id","firstName","createdAt","updatedAt");/
+ );
+ });
+
+ it('findAll is instrumented', async () => {
+ await User.findAll().catch(() => {});
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'SELECT "id", "firstName", "createdAt", "updatedAt" FROM "Users" AS "User";'
+ );
+ });
+
+ it('destroy is instrumented', async () => {
+ await User.destroy({ where: {}, truncate: true }).catch(() => {});
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'BULKDELETE');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'TRUNCATE "Users"');
+ });
+
+ it('count is instrumented', async () => {
+ await User.count().catch(() => {});
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'SELECT count(*) AS "count" FROM "Users" AS "User";'
+ );
+ });
+
+ it('handled complex query', async () => {
+ const Op = sequelize.Op;
+ await User.findOne({
+ where: {
+ username: 'Shlomi',
+ rank: {
+ [Op.or]: {
+ [Op.lt]: 1000,
+ [Op.eq]: null,
+ },
+ },
+ },
+ attributes: ['id', 'username'],
+ order: [['username', 'DESC']],
+ limit: 10,
+ offset: 5,
+ }).catch(() => {});
+
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'SELECT "id", "username" FROM "Users" AS "User" WHERE "User"."username" = \'Shlomi\' AND ("User"."rank" < 1000 OR "User"."rank" IS NULL) ORDER BY "User"."username" DESC LIMIT 10 OFFSET 5;'
+ );
+ });
+
+ it('tableName is taken from init override', async () => {
+ class Planet extends sequelize.Model {}
+ const expectedTableName = 'solar-system';
+ Planet.init({}, { sequelize: instance, tableName: expectedTableName });
+
+ await Planet.findAll().catch(() => {});
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+ assert.strictEqual(
+ attributes[ATTR_DB_COLLECTION_NAME],
+ expectedTableName
+ );
+ });
+
+ it('handles JOIN queries', async () => {
+ class Dog extends sequelize.Model {
+ firstName: string = '';
+ }
+
+ Dog.init(
+ {
+ firstName: { type: sequelize.DataTypes.STRING },
+ owner: { type: sequelize.DataTypes.STRING },
+ },
+ { sequelize: instance }
+ );
+ Dog.belongsTo(User, { foreignKey: 'firstName' });
+ User.hasMany(Dog, { foreignKey: 'firstName' });
+
+ await Dog.findOne({
+ attributes: ['firstName', 'owner'],
+ include: [
+ {
+ model: User,
+ attributes: ['firstName'],
+ required: true,
+ },
+ ],
+ }).catch(() => {});
+
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Dogs,Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'SELECT "Dog"."id", "Dog"."firstName", "Dog"."owner", "User"."id" AS "User.id", "User"."firstName" AS "User.firstName" FROM "Dogs" AS "Dog" INNER JOIN "Users" AS "User" ON "Dog"."firstName" = "User"."id" LIMIT 1;'
+ );
+ });
+ });
+
+ describe('mysql', () => {
+ const DB_SYSTEM = 'mysql';
+ const DB_USER = 'RickSanchez';
+ const SERVER_NAME = 'localhost';
+ const SERVER_PORT = 34567;
+ const DB_NAME = 'mysql-db';
+
+ const instance = new sequelize.Sequelize(DB_NAME, DB_USER, 'password', {
+ host: SERVER_NAME,
+ port: SERVER_PORT,
+ dialect: DB_SYSTEM,
+ });
+
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ it('create is instrumented', async () => {
+ await instance.models.User.create({ firstName: 'OpenTelemetry' }).catch(
+ () => {}
+ );
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ assert.strictEqual(spans[0].status.code, SpanStatusCode.ERROR);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], DB_SYSTEM);
+ assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], SERVER_NAME);
+ assert.strictEqual(attributes[ATTR_SERVER_PORT], SERVER_PORT);
+ assert.strictEqual(attributes[ATTR_DB_NAMESPACE], DB_NAME);
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'INSERT INTO `Users` (`id`,`firstName`,`createdAt`,`updatedAt`) VALUES (DEFAULT,$1,$2,$3);'
+ );
+ });
+
+ it('findAll is instrumented', async () => {
+ await instance.models.User.findAll().catch(() => {});
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'SELECT `id`, `firstName`, `createdAt`, `updatedAt` FROM `Users` AS `User`;'
+ );
+ });
+
+ describe('query is instrumented', () => {
+ it('with options not specified', async () => {
+ try {
+ await instance.query('SELECT 1 + 1');
+ } catch {
+ // Do not care about the error
+ }
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
+ });
+ it('with type not specified in options', async () => {
+ try {
+ await instance.query('SELECT 1 + 1', {});
+ } catch {
+ // Do not care about the error
+ }
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
+ assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
+ });
+
+ it('with type specified in options', async () => {
+ try {
+ await instance.query('SELECT 1 + 1', {
+ type: sequelize.QueryTypes.RAW,
+ });
+ } catch {
+ // Do not care about the error
+ }
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'RAW');
+ assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
+ });
+ });
+ });
+
+ describe('sqlite', () => {
+ const instance = new sequelize.Sequelize('sqlite:memory', {
+ logging: false,
+ });
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ it('create is instrumented', async () => {
+ await instance.models.User.create({ firstName: 'OpenTelemetry' }).catch(
+ () => {}
+ );
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ const attributes = spans[0].attributes;
+ assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], 'sqlite');
+ assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], 'memory');
+ assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
+ assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
+ assert.strictEqual(
+ attributes[ATTR_DB_QUERY_TEXT],
+ 'INSERT INTO `Users` (`id`,`firstName`,`createdAt`,`updatedAt`) VALUES (NULL,$1,$2,$3);'
+ );
+ });
+ });
+
+ describe('config', () => {
+ describe('queryHook', () => {
+ it('able to collect query', async () => {
+ instrumentation.disable();
+ const instance = new sequelize.Sequelize(
+ 'postgres://john@$localhost:1111/my-name',
+ { logging: false }
+ );
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ const response = { john: 'doe' };
+ sequelize.Sequelize.prototype.query = (() => {
+ return new Promise(resolve => resolve(response));
+ }) as QueryFunction;
+ instrumentation.setConfig({
+ queryHook: (span, { sql, option }: { sql: any; option: any }) => {
+ span.setAttribute('test-sql', 'any');
+ span.setAttribute('test-option', 'any');
+ },
+ });
+ instrumentation.enable();
+
+ await instance.models.User.findAll();
+ const spans = getSequelizeSpans();
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes['test-sql'], 'any');
+ assert.strictEqual(attributes['test-option'], 'any');
+ });
+
+ it('query hook which throws does not affect span', async () => {
+ instrumentation.disable();
+ const instance = new sequelize.Sequelize(
+ 'postgres://john@$localhost:1111/my-name',
+ { logging: false }
+ );
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ const response = { john: 'doe' };
+ sequelize.Sequelize.prototype.query = (() => {
+ return new Promise(resolve => resolve(response));
+ }) as QueryFunction;
+ const mockedLogger = (() => {
+ let message: string;
+ let error: Error;
+ return {
+ error: (_message: string, _err: Error) => {
+ message = _message;
+ error = _err;
+ },
+ debug: () => {},
+ getMessage: () => message,
+ getError: () => error,
+ };
+ })();
+
+ instrumentation.setConfig({
+ queryHook: () => {
+ throw new Error('Throwing');
+ },
+ });
+ instrumentation.enable();
+ diag.setLogger(mockedLogger as any);
+ await instance.models.User.findAll();
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ assert.strictEqual(
+ mockedLogger.getMessage(),
+ 'sequelize instrumentation: queryHook error'
+ );
+ assert.strictEqual(mockedLogger.getError().message, 'Throwing');
+ diag.setLogger(new DiagConsoleLogger());
+ });
+ });
+
+ describe('responseHook', () => {
+ it('able to collect response', async () => {
+ instrumentation.disable();
+ const instance = new sequelize.Sequelize(
+ 'postgres://john@$localhost:1111/my-name',
+ { logging: false }
+ );
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ const response = { john: 'doe' };
+ sequelize.Sequelize.prototype.query = (() => {
+ return new Promise(resolve => resolve(response));
+ }) as QueryFunction;
+ instrumentation.setConfig({
+ responseHook: (span, response) => {
+ span.setAttribute('test', JSON.stringify(response));
+ },
+ });
+ instrumentation.enable();
+
+ await instance.models.User.findAll();
+ const spans = getSequelizeSpans();
+ const attributes = spans[0].attributes;
+
+ assert.strictEqual(attributes['test'], JSON.stringify(response));
+ });
+
+ it('response hook which throws does not affect span', async () => {
+ instrumentation.disable();
+ const instance = new sequelize.Sequelize(
+ 'postgres://john@$localhost:1111/my-name',
+ { logging: false }
+ );
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+
+ const response = { john: 'doe' };
+ sequelize.Sequelize.prototype.query = (() => {
+ return new Promise(resolve => resolve(response));
+ }) as QueryFunction;
+ const mockedLogger = (() => {
+ let message: string;
+ let error: Error;
+ return {
+ error: (_message: string, _err: Error) => {
+ message = _message;
+ error = _err;
+ },
+ debug: () => {},
+ getMessage: () => message,
+ getError: () => error,
+ };
+ })();
+
+ instrumentation.setConfig({
+ responseHook: () => {
+ throw new Error('Throwing');
+ },
+ });
+ instrumentation.enable();
+ diag.setLogger(mockedLogger as any);
+ await instance.models.User.findAll();
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 1);
+ assert.strictEqual(
+ mockedLogger.getMessage(),
+ 'sequelize instrumentation: responseHook error'
+ );
+ assert.strictEqual(mockedLogger.getError().message, 'Throwing');
+ diag.setLogger(new DiagConsoleLogger());
+ });
+ });
+
+ describe('ignoreOrphanedSpans', () => {
+ it('skips when ignoreOrphanedSpans option is true', async () => {
+ instrumentation.disable();
+ const instance = new sequelize.Sequelize(
+ 'postgres://john@$localhost:1111/my-name',
+ { logging: false }
+ );
+ instance.define('User', {
+ firstName: { type: sequelize.DataTypes.STRING },
+ });
+ instrumentation.setConfig({
+ ignoreOrphanedSpans: true,
+ });
+ instrumentation.enable();
+
+ try {
+ await context.with(ROOT_CONTEXT, async () => {
+ await instance.models.User.create({ firstName: 'OpenTelemetry' });
+ });
+ } catch {}
+
+ const spans = getSequelizeSpans();
+ assert.strictEqual(spans.length, 0);
+ });
+ });
+ });
+
+ describe('misc', () => {
+ it('extractTableFromQuery', async () => {
+ assert.strictEqual(
+ extractTableFromQuery('FROM Users JOIN Dogs Where 1243'),
+ 'Dogs,Users'
+ );
+ assert.strictEqual(extractTableFromQuery('FROM "Users"'), 'Users');
+ assert.strictEqual(
+ extractTableFromQuery(
+ 'SELECT count(*) AS "count" FROM "Users" AS "User";'
+ ),
+ 'Users'
+ );
+ assert.strictEqual(
+ extractTableFromQuery(
+ 'SELECT `id`, `firstName`, `createdAt`, `updatedAt` FROM `Users` AS `User`;'
+ ),
+ 'Users'
+ );
+ assert.strictEqual(extractTableFromQuery(null), undefined);
+ assert.strictEqual(extractTableFromQuery(undefined), undefined);
+ });
+ });
+});
diff --git a/packages/instrumentation-sequelize/tsconfig.json b/packages/instrumentation-sequelize/tsconfig.json
new file mode 100644
index 0000000000..4078877ce6
--- /dev/null
+++ b/packages/instrumentation-sequelize/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.base",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "build"
+ },
+ "include": [
+ "src/**/*.ts",
+ "test/**/*.ts"
+ ]
+}
diff --git a/release-please-config.json b/release-please-config.json
index 3b1e3943d4..75a9dec7bc 100644
--- a/release-please-config.json
+++ b/release-please-config.json
@@ -34,6 +34,7 @@
"packages/instrumentation-lru-memoizer": {},
"packages/instrumentation-mongoose": {},
"packages/instrumentation-runtime-node": {},
+ "packages/instrumentation-sequelize": {},
"packages/instrumentation-socket.io": {},
"packages/instrumentation-tedious": {},
"packages/instrumentation-typeorm": {},