Skip to content

Commit 8916d1b

Browse files
chargomeclaude
andcommitted
ref(server-utils): Export the pg query span helpers
Expose the query-channel binding and the connection attribute builder so a driver that bundles its own copy of pg can emit the same span shape. The deprecated db.connection_string attribute moves behind an opt-in that only the pg integration sets, so new callers describe the connection with server.address and server.port alone. No behavior change for pg. Refs #25144 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent ca05d2d commit 8916d1b

1 file changed

Lines changed: 31 additions & 10 deletions

File tree

‎packages/server-utils/src/integrations/postgres.ts‎

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ interface PgChannelContext {
6969
_sentryCallerScope?: Scope;
7070
}
7171

72-
interface PgConnectionParams {
72+
export interface PgConnectionParams {
7373
database?: string;
7474
host?: string;
7575
port?: number;
@@ -96,9 +96,7 @@ const _postgresIntegration = ((options: { ignoreConnectSpans?: boolean } = {}) =
9696
}) satisfies IntegrationFn;
9797

9898
function instrumentPostgres(options: { ignoreConnectSpans?: boolean }): void {
99-
// Query spans: `pg`/native `Client.prototype.query`. Only this channel can return a streamable
100-
// `Submittable` result, so it's the only one that defers span-ending to the emitter (see below).
101-
subscribeQueryLikeChannel(CHANNELS.PG_QUERY, querySpanOptions, { deferStreamedResult: true });
99+
bindPgQueryChannel(CHANNELS.PG_QUERY, { origin: ORIGIN, connectionString: true });
102100

103101
// Connect spans, gated by `ignoreConnectSpans` (same as OTel pg).
104102
// `Client.prototype.connect` (pg + native)
@@ -109,6 +107,22 @@ function instrumentPostgres(options: { ignoreConnectSpans?: boolean }): void {
109107
}
110108
}
111109

110+
export interface PgQuerySpanOptions {
111+
origin: string;
112+
// `db.connection_string` is deprecated in favor of `server.address`/`server.port`. Only the pg
113+
// integration keeps emitting it, for parity with its OTel predecessor.
114+
connectionString?: boolean;
115+
}
116+
117+
/**
118+
* Query spans for a channel carrying `pg` `Client.prototype.query` calls, from `pg` itself or from
119+
* a copy bundled into another driver (`@neondatabase/serverless`). Only this call can return a
120+
* streamable `Submittable` result, so it's the only one that defers span-ending to the emitter.
121+
*/
122+
export function bindPgQueryChannel(channelName: string, options: PgQuerySpanOptions): void {
123+
subscribeQueryLikeChannel(channelName, ctx => querySpanOptions(ctx, options), { deferStreamedResult: true });
124+
}
125+
112126
/**
113127
* Subscribe to a pg tracing-channel and manage a span across its lifecycle.
114128
* Shared by the query/connect/pool-connect channels. They differ only in how
@@ -176,7 +190,10 @@ function subscribeQueryLikeChannel(
176190
);
177191
}
178192

179-
function querySpanOptions(ctx: PgChannelContext): { name: string; attributes: SpanAttributes } {
193+
function querySpanOptions(
194+
ctx: PgChannelContext,
195+
{ origin, connectionString }: PgQuerySpanOptions,
196+
): { name: string; attributes: SpanAttributes } {
180197
const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};
181198
const queryConfig = extractQueryConfig(ctx.arguments);
182199
const client = getClient();
@@ -190,8 +207,8 @@ function querySpanOptions(ctx: PgChannelContext): { name: string; attributes: Sp
190207
name,
191208
attributes: {
192209
[SENTRY_OP]: DB,
193-
...getConnectionAttributes(params),
194-
[SENTRY_ORIGIN]: ORIGIN,
210+
...(connectionString ? getPgConnectionAttributes(params) : getConnectionAttributes(params)),
211+
[SENTRY_ORIGIN]: origin,
195212
[DB_QUERY_TEXT]: queryText || undefined,
196213
[DB_QUERY_SUMMARY]: querySummary,
197214
[ATTR_PG_PLAN]: typeof queryConfig?.name === 'string' ? queryConfig.name : undefined,
@@ -202,7 +219,7 @@ function querySpanOptions(ctx: PgChannelContext): { name: string; attributes: Sp
202219
function connectSpanOptions(ctx: PgChannelContext): { name: string; attributes: SpanAttributes } {
203220
const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};
204221
// No origin set -> defaults to 'manual'
205-
return { name: SPAN_CONNECT, attributes: { [SENTRY_OP]: DB, ...getConnectionAttributes(params) } };
222+
return { name: SPAN_CONNECT, attributes: { [SENTRY_OP]: DB, ...getPgConnectionAttributes(params) } };
206223
}
207224

208225
function poolConnectSpanOptions(ctx: PgChannelContext): { name: string; attributes: SpanAttributes } {
@@ -229,17 +246,21 @@ function extractQueryConfig(args: unknown[]): { text: string; name?: unknown } |
229246
return undefined;
230247
}
231248

232-
function getConnectionAttributes(params: PgConnectionParams): SpanAttributes {
249+
/** The `db.*`/`server.*` attributes for a pg-style set of connection parameters. */
250+
export function getConnectionAttributes(params: PgConnectionParams): SpanAttributes {
233251
return {
234252
[DB_SYSTEM_NAME]: DB_SYSTEM_POSTGRESQL,
235-
[ATTR_DB_CONNECTION_STRING]: getConnectionString(params),
236253
[DB_NAMESPACE]: params.database,
237254
[DB_USER]: params.user,
238255
[SERVER_ADDRESS]: params.host,
239256
[SERVER_PORT]: Number.isInteger(params.port) ? params.port : undefined,
240257
};
241258
}
242259

260+
function getPgConnectionAttributes(params: PgConnectionParams): SpanAttributes {
261+
return { ...getConnectionAttributes(params), [ATTR_DB_CONNECTION_STRING]: getConnectionString(params) };
262+
}
263+
243264
function getPoolConnectionAttributes(opts: PgPoolOptions): SpanAttributes {
244265
let url: URL | undefined;
245266
try {

0 commit comments

Comments
 (0)