Skip to content

Conversation

@onurtemizkan
Copy link
Collaborator

@onurtemizkan onurtemizkan commented Oct 17, 2025

Resolves: #17889

This PR rewrites the postgresjs instrumentation with a new architecture:

  • Added ESM support via replaceExports

  • Moved to main export wrapping instead of internal module patching

    • Previously, we were patching connection.js and query.js internal modules
    • New approach: We are wrapping the main postgres module export to intercept sql instance creation
  • Connection context is now stored directly on sql instances using CONNECTION_CONTEXT_SYMBOL

  • Query.prototype fallback (CJS only)

    • Patches Query.prototype.handle as a fallback for pre-existing sql instances
    • Uses QUERY_FROM_INSTRUMENTED_SQL marker to prevent duplicate spans

Also,

  • Improved SQL sanitization
  • port attribute is now stored as a number per OTEL semantic conventions
  • Added fallback regex extraction for operation name when command isn't available

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.81 kB - -
@sentry/browser - with treeshaking flags 23.3 kB - -
@sentry/browser (incl. Tracing) 41.56 kB - -
@sentry/browser (incl. Tracing, Profiling) 46.15 kB - -
@sentry/browser (incl. Tracing, Replay) 79.98 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 69.7 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 84.65 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 96.9 kB - -
@sentry/browser (incl. Feedback) 41.52 kB - -
@sentry/browser (incl. sendFeedback) 29.49 kB - -
@sentry/browser (incl. FeedbackAsync) 34.48 kB - -
@sentry/react 26.52 kB - -
@sentry/react (incl. Tracing) 43.76 kB - -
@sentry/vue 29.27 kB - -
@sentry/vue (incl. Tracing) 43.37 kB - -
@sentry/svelte 24.82 kB - -
CDN Bundle 27.24 kB - -
CDN Bundle (incl. Tracing) 42.23 kB - -
CDN Bundle (incl. Tracing, Replay) 78.75 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 84.21 kB - -
CDN Bundle - uncompressed 80.04 kB - -
CDN Bundle (incl. Tracing) - uncompressed 125.39 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 241.42 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 254.18 kB - -
@sentry/nextjs (client) 45.98 kB - -
@sentry/sveltekit (client) 41.93 kB - -
@sentry/node-core 51.5 kB - -
@sentry/node 161.36 kB +0.66% +1.05 kB 🔺
@sentry/node - without tracing 92.91 kB - -
@sentry/aws-serverless 108.44 kB - -

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 8,745 - 11,561 -24%
GET With Sentry 1,611 18% 1,986 -19%
GET With Sentry (error only) 6,091 70% 7,859 -22%
POST Baseline 1,175 - 1,188 -1%
POST With Sentry 569 48% 583 -2%
POST With Sentry (error only) 1,047 89% 1,047 -
MYSQL Baseline 3,259 - 4,051 -20%
MYSQL With Sentry 553 17% 570 -3%
MYSQL With Sentry (error only) 2,650 81% 3,351 -21%

View base workflow run

@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch 2 times, most recently from f635159 to 96641f9 Compare October 17, 2025 10:06
@onurtemizkan onurtemizkan marked this pull request as ready for review November 21, 2025 14:28
@onurtemizkan onurtemizkan requested a review from Copilot November 21, 2025 14:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds ESM (ECMAScript Module) support for postgres.js instrumentation by refactoring the patching approach from file-based module instrumentation to module export wrapping. The instrumentation now wraps the main postgres export function to intercept SQL instance creation and instrument query methods dynamically.

Key changes:

  • Refactored instrumentation to wrap the main postgres export instead of patching internal files
  • Added comprehensive ESM test coverage alongside existing CJS tests
  • Enhanced SQL query sanitization to handle PostgreSQL placeholders ($1, $2, etc.)

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/node/src/integrations/tracing/postgresjs.ts Complete rewrite of instrumentation using module export wrapping; adds ESM support and improves query/connection handling
dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts Added ESM tests, requestHook tests, URL initialization tests, and unsafe query tests
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs New ESM scenario file for testing ESM imports
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.cjs New CJS scenario file with consolidated initialization
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js Enhanced with additional query test cases
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs New ESM test scenario for URL-based postgres initialization
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.cjs New CJS test scenario for URL-based postgres initialization
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.cjs New test scenario for sql.unsafe() method
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs New ESM test scenario for requestHook functionality
dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.js New CJS test scenario for requestHook functionality
dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument.mjs New ESM instrumentation file for tests
dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument.cjs New CJS instrumentation file for tests
dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.mjs New ESM instrumentation with requestHook configuration
dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.cjs New CJS instrumentation with requestHook configuration
Comments suppressed due to low confidence (1)

dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js:83

  • The floating promise should be handled with proper error handling. Consider using run().catch(console.error) or wrapping in an async IIFE to ensure errors are not silently swallowed.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 363 to 367
let spanName = sanitizedSqlQuery?.trim() || '';
if (!spanName) {
// Fallback: try to extract operation from the sanitized query
const operationMatch = sanitizedSqlQuery?.match(SQL_OPERATION_REGEX);
spanName = operationMatch?.[1] ? `db.${operationMatch[1].toLowerCase()}` : 'db.query';
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic error: spanName is set to the trimmed sanitizedSqlQuery on line 363, which means the condition !spanName on line 364 will only be true if sanitizedSqlQuery is empty or undefined. However, line 366 attempts to match the same sanitizedSqlQuery against SQL_OPERATION_REGEX. This code path is unreachable when sanitizedSqlQuery has content. The fallback logic appears to be intended for cases where sanitizedSqlQuery exists but is not suitable as a span name, but the current implementation doesn't achieve this.

Suggested change
let spanName = sanitizedSqlQuery?.trim() || '';
if (!spanName) {
// Fallback: try to extract operation from the sanitized query
const operationMatch = sanitizedSqlQuery?.match(SQL_OPERATION_REGEX);
spanName = operationMatch?.[1] ? `db.${operationMatch[1].toLowerCase()}` : 'db.query';
let spanName: string;
const operationMatch = sanitizedSqlQuery?.match(SQL_OPERATION_REGEX);
if (operationMatch?.[1]) {
spanName = `db.${operationMatch[1].toLowerCase()}`;
} else if (sanitizedSqlQuery?.trim()) {
spanName = sanitizedSqlQuery.trim();
} else {
spanName = 'db.query';

Copilot uses AI. Check for mistakes.
InstrumentationBase,
InstrumentationNodeModuleDefinition,
InstrumentationNodeModuleFile,
safeExecuteInTheMiddle,
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import of safeExecuteInTheMiddle should be removed from '@opentelemetry/instrumentation' and imported from '@sentry/core' instead, as indicated by the usage pattern at line 394. However, checking the actual usage shows it is used correctly. If this import is not used elsewhere in the file, it should be removed.

Copilot uses AI. Check for mistakes.
@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from d9a0dfa to 35bf27d Compare November 26, 2025 14:56
@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from 35bf27d to 5143c10 Compare November 27, 2025 10:54
spanName = sanitizedSqlQuery.trim();
} else {
spanName = 'db.query';
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Span description uses operation prefix instead of full query

The span name logic sets spanName to db.${operation} (e.g., db.create, db.select) for recognized SQL operations, but this value becomes the span's description when serialized (as confirmed in sentrySpan.ts line 226: description: this._name). The tests in this same PR explicitly expect the span description to be the full sanitized SQL query (e.g., 'CREATE TABLE "User" (...)'), not the abbreviated db.create format. This mismatch means the detailed test expectations will fail.

Fix in Cursor Fix in Web

@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from 5143c10 to 898802b Compare November 27, 2025 17:16
Comment on lines 482 to 532
sqlQuery
.replace(/\s+/g, ' ')
.trim() // Remove extra spaces including newlines and trim
.substring(0, 1024) // Truncate to 1024 characters
.replace(/--.*?(\r?\n|$)/g, '') // Single line comments
// Remove comments first (they may contain newlines and extra spaces)
.replace(/--.*$/gm, '') // Single line comments (multiline mode)
.replace(/\/\*[\s\S]*?\*\//g, '') // Multi-line comments

This comment was marked as outdated.

@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from b0cf889 to 29ff73f Compare November 28, 2025 14:58
@onurtemizkan onurtemizkan requested a review from Lms24 November 28, 2025 15:29
@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from 299da8a to 11a366d Compare December 2, 2025 11:42
@aldy505
Copy link

aldy505 commented Dec 11, 2025

...any updates?

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the changes. This looks good to me for now, though I'd like us to improve parameterization in a follow-up PR (see slack convo).

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for making the changes!

@onurtemizkan
Copy link
Collaborator Author

@Lms24 - Implemented complete sanitization. 4ae3e66

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Let's fix the last lint warning and then we can merge it.

@onurtemizkan onurtemizkan force-pushed the onur/postgres-js-esm-support branch from 4767e70 to 9cf452d Compare December 15, 2025 17:39
@Lms24 Lms24 merged commit 0cd1d4a into develop Dec 16, 2025
143 checks passed
@Lms24 Lms24 deleted the onur/postgres-js-esm-support branch December 16, 2025 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry.postgresJsIntegration() not creating any DB spans

4 participants