Skip to content

Commit 8963d48

Browse files
cursoragentclaude
andcommitted
fix: Restore runName parameter in LangChain handleChainStart and deduplicate SQL utilities
Bug 1: Added missing parameters to handleChainStart method in LangChain integration including runName, and updated chain naming logic to prioritize runName over chain.name, preventing chains with custom runName but without chain.name from being incorrectly named 'unknown_chain'. Bug 2: Removed duplicate SQL utility functions (_reconstructQuery and _sanitizeSqlQuery) from node postgresjs integration and updated code to use the exported functions from @sentry/core instead. Also updated node tests to import these functions directly from core. Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
1 parent f399513 commit 8963d48

File tree

4 files changed

+20
-74
lines changed

4 files changed

+20
-74
lines changed

packages/core/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export { dedupeIntegration } from './integrations/dedupe';
120120
export { extraErrorDataIntegration } from './integrations/extraerrordata';
121121
export { rewriteFramesIntegration } from './integrations/rewriteframes';
122122
export { supabaseIntegration, instrumentSupabaseClient } from './integrations/supabase';
123-
export { instrumentPostgresJsSql } from './integrations/postgresjs';
123+
export { instrumentPostgresJsSql, _reconstructQuery, _sanitizeSqlQuery } from './integrations/postgresjs';
124124
export { zodErrorsIntegration } from './integrations/zoderrors';
125125
export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter';
126126
export { consoleIntegration } from './integrations/console';

packages/core/src/tracing/langchain/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,17 @@ export function createLangChainCallbackHandler(options: LangChainOptions = {}):
184184
},
185185

186186
// Chain Start Handler
187-
handleChainStart(chain: { name?: string }, inputs: Record<string, unknown>, runId: string, _parentRunId?: string) {
188-
const chainName = chain.name || 'unknown_chain';
187+
handleChainStart(
188+
chain: { name?: string },
189+
inputs: Record<string, unknown>,
190+
runId: string,
191+
_parentRunId?: string,
192+
_tags?: string[],
193+
_metadata?: Record<string, unknown>,
194+
_runType?: string,
195+
runName?: string,
196+
) {
197+
const chainName = runName || chain.name || 'unknown_chain';
189198
const attributes: Record<string, SpanAttributeValue> = {
190199
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.langchain',
191200
'langchain.chain.name': chainName,

packages/node/src/integrations/tracing/postgresjs.ts

Lines changed: 4 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
} from '@opentelemetry/semantic-conventions';
1818
import type { IntegrationFn, Span } from '@sentry/core';
1919
import {
20+
_reconstructQuery,
21+
_sanitizeSqlQuery,
2022
debug,
2123
defineIntegration,
2224
instrumentPostgresJsSql,
@@ -197,65 +199,6 @@ export class PostgresJsInstrumentation extends InstrumentationBase<PostgresJsIns
197199
}
198200
}
199201

200-
/**
201-
* Reconstructs the full SQL query from template strings with PostgreSQL placeholders.
202-
*
203-
* For sql`SELECT * FROM users WHERE id = ${123} AND name = ${'foo'}`:
204-
* strings = ["SELECT * FROM users WHERE id = ", " AND name = ", ""]
205-
* returns: "SELECT * FROM users WHERE id = $1 AND name = $2"
206-
*/
207-
private _reconstructQuery(strings: string[] | undefined): string | undefined {
208-
if (!strings?.length) {
209-
return undefined;
210-
}
211-
if (strings.length === 1) {
212-
return strings[0] || undefined;
213-
}
214-
// Join template parts with PostgreSQL placeholders ($1, $2, etc.)
215-
return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');
216-
}
217-
218-
/**
219-
* Sanitize SQL query as per the OTEL semantic conventions
220-
* https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext
221-
*
222-
* PostgreSQL $n placeholders are preserved per OTEL spec - they're parameterized queries,
223-
* not sensitive literals. Only actual values (strings, numbers, booleans) are sanitized.
224-
*/
225-
private _sanitizeSqlQuery(sqlQuery: string | undefined): string {
226-
if (!sqlQuery) {
227-
return 'Unknown SQL Query';
228-
}
229-
230-
return (
231-
sqlQuery
232-
// Remove comments first (they may contain newlines and extra spaces)
233-
.replace(/--.*$/gm, '') // Single line comments (multiline mode)
234-
.replace(/\/\*[\s\S]*?\*\//g, '') // Multi-line comments
235-
.replace(/;\s*$/, '') // Remove trailing semicolons
236-
// Collapse whitespace to a single space (after removing comments)
237-
.replace(/\s+/g, ' ')
238-
.trim() // Remove extra spaces and trim
239-
// Sanitize hex/binary literals before string literals
240-
.replace(/\bX'[0-9A-Fa-f]*'/gi, '?') // Hex string literals
241-
.replace(/\bB'[01]*'/gi, '?') // Binary string literals
242-
// Sanitize string literals (handles escaped quotes)
243-
.replace(/'(?:[^']|'')*'/g, '?')
244-
// Sanitize hex numbers
245-
.replace(/\b0x[0-9A-Fa-f]+/gi, '?')
246-
// Sanitize boolean literals
247-
.replace(/\b(?:TRUE|FALSE)\b/gi, '?')
248-
// Sanitize numeric literals (preserve $n placeholders via negative lookbehind)
249-
.replace(/-?\b\d+\.?\d*[eE][+-]?\d+\b/g, '?') // Scientific notation
250-
.replace(/-?\b\d+\.\d+\b/g, '?') // Decimals
251-
.replace(/-?\.\d+\b/g, '?') // Decimals starting with dot
252-
.replace(/(?<!\$)-?\b\d+\b/g, '?') // Integers (NOT $n placeholders)
253-
// Collapse IN clauses for cardinality (both ? and $n variants)
254-
.replace(/\bIN\b\s*\(\s*\?(?:\s*,\s*\?)*\s*\)/gi, 'IN (?)')
255-
.replace(/\bIN\b\s*\(\s*\$\d+(?:\s*,\s*\$\d+)*\s*\)/gi, 'IN ($?)')
256-
);
257-
}
258-
259202
/**
260203
* Fallback patch for Query.prototype.handle to instrument queries from pre-existing sql instances.
261204
* This catches queries from sql instances created BEFORE Sentry was initialized (CJS only).
@@ -294,8 +237,8 @@ export class PostgresJsInstrumentation extends InstrumentationBase<PostgresJsIns
294237
return originalHandle.apply(this, args);
295238
}
296239

297-
const fullQuery = self._reconstructQuery(this.strings);
298-
const sanitizedSqlQuery = self._sanitizeSqlQuery(fullQuery);
240+
const fullQuery = _reconstructQuery(this.strings);
241+
const sanitizedSqlQuery = _sanitizeSqlQuery(fullQuery);
299242

300243
return startSpanManual(
301244
{

packages/node/test/integrations/tracing/postgresjs.test.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1+
import { _reconstructQuery, _sanitizeSqlQuery } from '@sentry/core';
12
import { describe, expect, it } from 'vitest';
23
import { PostgresJsInstrumentation } from '../../../src/integrations/tracing/postgresjs';
34

45
describe('PostgresJs', () => {
56
const instrumentation = new PostgresJsInstrumentation({ requireParentSpan: true });
67

78
describe('_reconstructQuery', () => {
8-
const reconstruct = (strings: string[] | undefined) =>
9-
(
10-
instrumentation as unknown as { _reconstructQuery: (s: string[] | undefined) => string | undefined }
11-
)._reconstructQuery(strings);
9+
const reconstruct = (strings: string[] | undefined) => _reconstructQuery(strings);
1210

1311
describe('empty input handling', () => {
1412
it.each([
@@ -69,10 +67,7 @@ describe('PostgresJs', () => {
6967
});
7068

7169
describe('integration with _sanitizeSqlQuery', () => {
72-
const sanitize = (query: string | undefined) =>
73-
(instrumentation as unknown as { _sanitizeSqlQuery: (q: string | undefined) => string })._sanitizeSqlQuery(
74-
query,
75-
);
70+
const sanitize = (query: string | undefined) => _sanitizeSqlQuery(query);
7671

7772
it('preserves $n placeholders per OTEL spec', () => {
7873
const strings = ['SELECT * FROM users WHERE id = ', ' AND name = ', ''];
@@ -96,8 +91,7 @@ describe('PostgresJs', () => {
9691
});
9792

9893
describe('_sanitizeSqlQuery', () => {
99-
const sanitize = (query: string | undefined) =>
100-
(instrumentation as unknown as { _sanitizeSqlQuery: (q: string | undefined) => string })._sanitizeSqlQuery(query);
94+
const sanitize = (query: string | undefined) => _sanitizeSqlQuery(query);
10195

10296
describe('passthrough (no literals)', () => {
10397
it.each([

0 commit comments

Comments
 (0)