@justanalyticsapp/node 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +286 -0
- package/dist/client.js +681 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +126 -0
- package/dist/context.js +170 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +135 -0
- package/dist/errors.js +180 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +314 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/express.d.ts +77 -0
- package/dist/integrations/express.js +87 -0
- package/dist/integrations/express.js.map +1 -0
- package/dist/integrations/http.d.ts +129 -0
- package/dist/integrations/http.js +465 -0
- package/dist/integrations/http.js.map +1 -0
- package/dist/integrations/metrics.d.ts +110 -0
- package/dist/integrations/metrics.js +313 -0
- package/dist/integrations/metrics.js.map +1 -0
- package/dist/integrations/next.d.ts +252 -0
- package/dist/integrations/next.js +480 -0
- package/dist/integrations/next.js.map +1 -0
- package/dist/integrations/pg.d.ts +169 -0
- package/dist/integrations/pg.js +616 -0
- package/dist/integrations/pg.js.map +1 -0
- package/dist/integrations/pino.d.ts +52 -0
- package/dist/integrations/pino.js +153 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/integrations/redis.d.ts +190 -0
- package/dist/integrations/redis.js +597 -0
- package/dist/integrations/redis.js.map +1 -0
- package/dist/integrations/winston.d.ts +48 -0
- package/dist/integrations/winston.js +99 -0
- package/dist/integrations/winston.js.map +1 -0
- package/dist/logger.d.ts +148 -0
- package/dist/logger.js +162 -0
- package/dist/logger.js.map +1 -0
- package/dist/span.d.ts +192 -0
- package/dist/span.js +197 -0
- package/dist/span.js.map +1 -0
- package/dist/transport.d.ts +246 -0
- package/dist/transport.js +654 -0
- package/dist/transport.js.map +1 -0
- package/dist/utils/headers.d.ts +60 -0
- package/dist/utils/headers.js +93 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/id.d.ts +23 -0
- package/dist/utils/id.js +36 -0
- package/dist/utils/id.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file packages/node-sdk/src/integrations/pg.ts
|
|
4
|
+
* @description PostgreSQL auto-instrumentation integration for the JustAnalytics Node.js SDK.
|
|
5
|
+
*
|
|
6
|
+
* Implements Story 039 - PostgreSQL Auto-Instrumentation
|
|
7
|
+
*
|
|
8
|
+
* Monkey-patches `pg.Client.prototype.query`, `pg.Pool.prototype.query`, and
|
|
9
|
+
* `pg.Pool.prototype.connect` to automatically create `db.query` and `db.connect`
|
|
10
|
+
* spans for all PostgreSQL operations. This captures all PostgreSQL traffic regardless
|
|
11
|
+
* of which ORM or query builder sits on top (Prisma, Knex, TypeORM, Sequelize, Drizzle).
|
|
12
|
+
*
|
|
13
|
+
* Follows the same monkey-patching pattern established in Story 036 (HTTP Auto-Instrumentation):
|
|
14
|
+
* - Integration class with `enable()`/`disable()` lifecycle methods
|
|
15
|
+
* - Original function preservation for clean teardown
|
|
16
|
+
* - Integration with AsyncLocalStorage context for automatic parent-child span relationships
|
|
17
|
+
* - Fail-open design: if instrumentation code fails, the original query executes normally
|
|
18
|
+
*
|
|
19
|
+
* SQL sanitization is a critical security requirement: all literal values (strings,
|
|
20
|
+
* numbers, booleans) are replaced with `$?` placeholders. Actual query parameter
|
|
21
|
+
* values are NEVER included in span attributes.
|
|
22
|
+
*
|
|
23
|
+
* References:
|
|
24
|
+
* - OpenTelemetry Database Semantic Conventions (db.system, db.statement, etc.)
|
|
25
|
+
* - Story 035 - Node.js SDK Core (Span, context, transport)
|
|
26
|
+
* - Story 036 - HTTP Auto-Instrumentation (integration pattern)
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.PgIntegration = void 0;
|
|
30
|
+
exports.sanitizeSql = sanitizeSql;
|
|
31
|
+
exports.extractSqlOperation = extractSqlOperation;
|
|
32
|
+
exports.extractTableName = extractTableName;
|
|
33
|
+
exports.sanitizeConnectionString = sanitizeConnectionString;
|
|
34
|
+
const span_1 = require("../span");
|
|
35
|
+
const context_1 = require("../context");
|
|
36
|
+
const id_1 = require("../utils/id");
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// SQL Sanitization Utilities (exported for testing)
|
|
39
|
+
// ============================================================================
|
|
40
|
+
/**
|
|
41
|
+
* Sanitize a SQL query by replacing literal values with placeholders.
|
|
42
|
+
*
|
|
43
|
+
* Rules (applied in order):
|
|
44
|
+
* 1. Strip block comments (/* ... */)
|
|
45
|
+
* 2. Strip line comments (-- ...)
|
|
46
|
+
* 3. Replace string literals ('...') with $?
|
|
47
|
+
* 4. Replace numeric literals with $? (preserving $N parameter placeholders)
|
|
48
|
+
* 5. Replace boolean literals (TRUE/FALSE) with $?
|
|
49
|
+
* 6. Normalize whitespace (collapse multiple spaces, trim)
|
|
50
|
+
* 7. Truncate to maxLength
|
|
51
|
+
*
|
|
52
|
+
* @param sql - Raw SQL query string
|
|
53
|
+
* @param maxLength - Maximum length for the sanitized output (default: 2048)
|
|
54
|
+
* @returns Sanitized SQL with literals replaced
|
|
55
|
+
*/
|
|
56
|
+
function sanitizeSql(sql, maxLength = 2048) {
|
|
57
|
+
try {
|
|
58
|
+
let result = sql;
|
|
59
|
+
// Step 1: Strip block comments /* ... */
|
|
60
|
+
result = result.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
61
|
+
// Step 2: Strip line comments -- ...
|
|
62
|
+
result = result.replace(/--[^\n]*/g, '');
|
|
63
|
+
// Step 3: Replace string literals (handle escaped quotes like O''Brien)
|
|
64
|
+
result = result.replace(/'(?:[^']|'')*'/g, '$?');
|
|
65
|
+
// Step 4: Replace numeric literals (not preceded by $ for parameter placeholders)
|
|
66
|
+
result = result.replace(/(?<!\$)\b\d+(?:\.\d+)?\b/g, '$?');
|
|
67
|
+
// Step 5: Replace boolean literals
|
|
68
|
+
result = result.replace(/\b(?:TRUE|FALSE|true|false)\b/g, '$?');
|
|
69
|
+
// Step 6: Normalize whitespace
|
|
70
|
+
result = result.replace(/\s+/g, ' ').trim();
|
|
71
|
+
// Step 7: Truncate
|
|
72
|
+
if (result.length > maxLength) {
|
|
73
|
+
result = result.substring(0, maxLength - 3) + '...';
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// If sanitization fails on malformed SQL, truncate the raw query
|
|
79
|
+
const trimmed = sql.replace(/\s+/g, ' ').trim();
|
|
80
|
+
if (trimmed.length > maxLength) {
|
|
81
|
+
return trimmed.substring(0, maxLength - 3) + '...';
|
|
82
|
+
}
|
|
83
|
+
return trimmed;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract the SQL operation keyword from a query string.
|
|
88
|
+
*
|
|
89
|
+
* Handles: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP,
|
|
90
|
+
* BEGIN, COMMIT, ROLLBACK, TRUNCATE, COPY, EXPLAIN, ANALYZE, WITH (CTE)
|
|
91
|
+
*
|
|
92
|
+
* @param sql - Raw or sanitized SQL query
|
|
93
|
+
* @returns Uppercase operation keyword (e.g., "SELECT"), or "UNKNOWN" if not recognized
|
|
94
|
+
*/
|
|
95
|
+
function extractSqlOperation(sql) {
|
|
96
|
+
const trimmed = sql.trimStart();
|
|
97
|
+
const match = trimmed.match(/^(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|BEGIN|COMMIT|ROLLBACK|TRUNCATE|COPY|EXPLAIN|ANALYZE|WITH)\b/i);
|
|
98
|
+
return match ? match[1].toUpperCase() : 'UNKNOWN';
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Extract the primary table name from a SQL query (best effort).
|
|
102
|
+
*
|
|
103
|
+
* Patterns handled:
|
|
104
|
+
* - SELECT ... FROM table_name
|
|
105
|
+
* - INSERT INTO table_name
|
|
106
|
+
* - UPDATE table_name
|
|
107
|
+
* - DELETE FROM table_name
|
|
108
|
+
* - Handles schema-qualified names: schema.table
|
|
109
|
+
* - Handles quoted identifiers: "table_name"
|
|
110
|
+
*
|
|
111
|
+
* @param sql - Raw or sanitized SQL query
|
|
112
|
+
* @returns Table name, or null if extraction fails
|
|
113
|
+
*/
|
|
114
|
+
function extractTableName(sql) {
|
|
115
|
+
const patterns = [
|
|
116
|
+
/\bFROM\s+(?:"([^"]+)"|(\w+)(?:\.(?:"([^"]+)"|(\w+)))?)/i,
|
|
117
|
+
/\bINTO\s+(?:"([^"]+)"|(\w+)(?:\.(?:"([^"]+)"|(\w+)))?)/i,
|
|
118
|
+
/\bUPDATE\s+(?:"([^"]+)"|(\w+)(?:\.(?:"([^"]+)"|(\w+)))?)/i,
|
|
119
|
+
/\bJOIN\s+(?:"([^"]+)"|(\w+)(?:\.(?:"([^"]+)"|(\w+)))?)/i,
|
|
120
|
+
];
|
|
121
|
+
for (const pattern of patterns) {
|
|
122
|
+
const match = sql.match(pattern);
|
|
123
|
+
if (match) {
|
|
124
|
+
// Return the last non-undefined capture group (table name after schema)
|
|
125
|
+
const captures = match.slice(1).filter(Boolean);
|
|
126
|
+
return captures.length > 0 ? captures[captures.length - 1] : null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Build a sanitized connection string from pg client config.
|
|
133
|
+
* Replaces password with '***'.
|
|
134
|
+
*
|
|
135
|
+
* @param connStr - Raw connection string potentially containing a password
|
|
136
|
+
* @returns Sanitized connection string with password masked
|
|
137
|
+
*/
|
|
138
|
+
function sanitizeConnectionString(connStr) {
|
|
139
|
+
// Replace password in postgresql://user:password@host:port/db format
|
|
140
|
+
return connStr.replace(/^(postgresql:\/\/[^:]+:)([^@]+)(@)/, '$1***$3');
|
|
141
|
+
}
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// Query Argument Normalization
|
|
144
|
+
// ============================================================================
|
|
145
|
+
/**
|
|
146
|
+
* Normalize the various overloaded argument forms of pg.Client.query
|
|
147
|
+
* into a consistent shape.
|
|
148
|
+
*
|
|
149
|
+
* pg supports:
|
|
150
|
+
* - query(text: string, values?: any[], callback?: Function)
|
|
151
|
+
* - query(config: { text: string, values?: any[], name?: string, ... })
|
|
152
|
+
* - query(config: { text: string, ... }, values?: any[], callback?: Function)
|
|
153
|
+
*
|
|
154
|
+
* @param args - The arguments passed to query()
|
|
155
|
+
* @returns { text, callback, isPromise }
|
|
156
|
+
*/
|
|
157
|
+
function normalizeQueryArgs(args) {
|
|
158
|
+
let text;
|
|
159
|
+
let callback = null;
|
|
160
|
+
if (typeof args[0] === 'string') {
|
|
161
|
+
text = args[0];
|
|
162
|
+
// Find callback (last function argument)
|
|
163
|
+
for (let i = args.length - 1; i >= 1; i--) {
|
|
164
|
+
if (typeof args[i] === 'function') {
|
|
165
|
+
callback = args[i];
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else if (typeof args[0] === 'object' && args[0] !== null && 'text' in args[0]) {
|
|
171
|
+
text = args[0].text;
|
|
172
|
+
for (let i = args.length - 1; i >= 1; i--) {
|
|
173
|
+
if (typeof args[i] === 'function') {
|
|
174
|
+
callback = args[i];
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
text = '';
|
|
181
|
+
}
|
|
182
|
+
return { text, callback, isPromise: callback === null };
|
|
183
|
+
}
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// PgIntegration Class
|
|
186
|
+
// ============================================================================
|
|
187
|
+
/**
|
|
188
|
+
* PgIntegration monkey-patches pg.Client.prototype.query,
|
|
189
|
+
* pg.Pool.prototype.query, and pg.Pool.prototype.connect to auto-create
|
|
190
|
+
* db.query and db.connect spans for all PostgreSQL operations.
|
|
191
|
+
*
|
|
192
|
+
* Follows the same pattern as HttpIntegration (Story 036):
|
|
193
|
+
* - Constructor accepts serviceName, options, onSpanEnd callback
|
|
194
|
+
* - enable() patches, disable() restores
|
|
195
|
+
* - Original functions preserved for clean teardown
|
|
196
|
+
* - Fail-open design: instrumentation failures never crash the host process
|
|
197
|
+
*/
|
|
198
|
+
class PgIntegration {
|
|
199
|
+
/**
|
|
200
|
+
* Create a new PgIntegration.
|
|
201
|
+
*
|
|
202
|
+
* @param serviceName - The service name for span attribution
|
|
203
|
+
* @param options - Integration configuration options
|
|
204
|
+
* @param onSpanEnd - Callback invoked when a span ends (enqueues to transport)
|
|
205
|
+
*/
|
|
206
|
+
constructor(serviceName, options, onSpanEnd) {
|
|
207
|
+
this._enabled = false;
|
|
208
|
+
// Store original functions for restoration
|
|
209
|
+
this._originalClientQuery = null;
|
|
210
|
+
this._originalPoolQuery = null;
|
|
211
|
+
this._originalPoolConnect = null;
|
|
212
|
+
// Store references to prototypes for restoration
|
|
213
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
214
|
+
this._pgClient = null;
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
216
|
+
this._pgPool = null;
|
|
217
|
+
this._serviceName = serviceName;
|
|
218
|
+
this._onSpanEnd = onSpanEnd;
|
|
219
|
+
// Resolve options with defaults
|
|
220
|
+
const opts = options || {};
|
|
221
|
+
this._options = {
|
|
222
|
+
enabled: opts.enabled !== false,
|
|
223
|
+
maxQueryLength: opts.maxQueryLength ?? 2048,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Activate the integration: load pg module and patch prototypes.
|
|
228
|
+
*
|
|
229
|
+
* Calling enable() when already enabled is a no-op (idempotent).
|
|
230
|
+
*/
|
|
231
|
+
enable() {
|
|
232
|
+
if (this._enabled)
|
|
233
|
+
return;
|
|
234
|
+
if (!this._options.enabled)
|
|
235
|
+
return;
|
|
236
|
+
try {
|
|
237
|
+
// Dynamic require: pg is an optional peer dependency
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
239
|
+
let pg;
|
|
240
|
+
try {
|
|
241
|
+
pg = require('pg');
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// pg module is not installed -- silently skip
|
|
245
|
+
if (typeof console !== 'undefined') {
|
|
246
|
+
console.debug('[JustAnalytics] pg module not found. Skipping PostgreSQL auto-instrumentation.');
|
|
247
|
+
}
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const Client = pg.Client;
|
|
251
|
+
const Pool = pg.Pool;
|
|
252
|
+
if (!Client || !Client.prototype) {
|
|
253
|
+
if (typeof console !== 'undefined') {
|
|
254
|
+
console.debug('[JustAnalytics] pg.Client not found. Skipping PostgreSQL auto-instrumentation.');
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Store references for restoration
|
|
259
|
+
this._pgClient = Client.prototype;
|
|
260
|
+
this._originalClientQuery = Client.prototype.query;
|
|
261
|
+
// Patch Client.prototype.query
|
|
262
|
+
Client.prototype.query = this._wrapClientQuery(this._originalClientQuery);
|
|
263
|
+
// Patch Pool if available
|
|
264
|
+
if (Pool && Pool.prototype) {
|
|
265
|
+
this._pgPool = Pool.prototype;
|
|
266
|
+
// Patch Pool.prototype.query
|
|
267
|
+
this._originalPoolQuery = Pool.prototype.query;
|
|
268
|
+
Pool.prototype.query = this._wrapPoolQuery(this._originalPoolQuery);
|
|
269
|
+
// Patch Pool.prototype.connect
|
|
270
|
+
this._originalPoolConnect = Pool.prototype.connect;
|
|
271
|
+
Pool.prototype.connect = this._wrapPoolConnect(this._originalPoolConnect);
|
|
272
|
+
}
|
|
273
|
+
this._enabled = true;
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
// Monkey-patching failed; fall back to no-op and restore any partial patches
|
|
277
|
+
this._restoreOriginals();
|
|
278
|
+
if (typeof console !== 'undefined') {
|
|
279
|
+
console.warn('[JustAnalytics] Failed to enable PostgreSQL integration:', error instanceof Error ? error.message : String(error));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Deactivate: restore original pg functions.
|
|
285
|
+
*
|
|
286
|
+
* Calling disable() when not enabled is a no-op (idempotent).
|
|
287
|
+
*/
|
|
288
|
+
disable() {
|
|
289
|
+
if (!this._enabled)
|
|
290
|
+
return;
|
|
291
|
+
this._restoreOriginals();
|
|
292
|
+
this._enabled = false;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Restore all patched functions to their originals.
|
|
296
|
+
*/
|
|
297
|
+
_restoreOriginals() {
|
|
298
|
+
if (this._pgClient && this._originalClientQuery) {
|
|
299
|
+
this._pgClient.query = this._originalClientQuery;
|
|
300
|
+
this._originalClientQuery = null;
|
|
301
|
+
this._pgClient = null;
|
|
302
|
+
}
|
|
303
|
+
if (this._pgPool) {
|
|
304
|
+
if (this._originalPoolQuery) {
|
|
305
|
+
this._pgPool.query = this._originalPoolQuery;
|
|
306
|
+
this._originalPoolQuery = null;
|
|
307
|
+
}
|
|
308
|
+
if (this._originalPoolConnect) {
|
|
309
|
+
this._pgPool.connect = this._originalPoolConnect;
|
|
310
|
+
this._originalPoolConnect = null;
|
|
311
|
+
}
|
|
312
|
+
this._pgPool = null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Wrap pg.Client.prototype.query to create db.query spans.
|
|
317
|
+
*
|
|
318
|
+
* Handles all pg query signatures:
|
|
319
|
+
* 1. client.query(text, callback)
|
|
320
|
+
* 2. client.query(text, values, callback)
|
|
321
|
+
* 3. client.query(text) -- promise
|
|
322
|
+
* 4. client.query(text, values) -- promise
|
|
323
|
+
* 5. client.query(config) -- QueryConfig object, promise
|
|
324
|
+
* 6. client.query(config, callback) -- QueryConfig object, callback
|
|
325
|
+
*
|
|
326
|
+
* @param original - The original query function
|
|
327
|
+
* @returns A wrapped version of the query function
|
|
328
|
+
*/
|
|
329
|
+
_wrapClientQuery(original) {
|
|
330
|
+
const integration = this;
|
|
331
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
332
|
+
return function patchedQuery(...args) {
|
|
333
|
+
try {
|
|
334
|
+
const { text, callback, isPromise } = normalizeQueryArgs(args);
|
|
335
|
+
if (!text) {
|
|
336
|
+
return original.apply(this, args);
|
|
337
|
+
}
|
|
338
|
+
// Get active span context
|
|
339
|
+
const parentSpan = (0, context_1.getActiveSpan)();
|
|
340
|
+
const traceId = parentSpan?.traceId ?? (0, id_1.generateTraceId)();
|
|
341
|
+
const parentSpanId = parentSpan?.id ?? null;
|
|
342
|
+
const operation = extractSqlOperation(text);
|
|
343
|
+
const table = extractTableName(text);
|
|
344
|
+
const sanitizedSql = sanitizeSql(text, integration._options.maxQueryLength);
|
|
345
|
+
const operationName = operation !== 'UNKNOWN' ? `db.query ${operation}` : 'db.query';
|
|
346
|
+
// Build attributes (OpenTelemetry Database Semantic Conventions)
|
|
347
|
+
const attributes = {
|
|
348
|
+
'db.system': 'postgresql',
|
|
349
|
+
'db.statement': sanitizedSql,
|
|
350
|
+
};
|
|
351
|
+
if (operation !== 'UNKNOWN')
|
|
352
|
+
attributes['db.operation'] = operation;
|
|
353
|
+
if (table)
|
|
354
|
+
attributes['db.sql.table'] = table;
|
|
355
|
+
// Extract connection info from pg Client config
|
|
356
|
+
const config = this.connectionParameters || this._connectionParameters || {};
|
|
357
|
+
if (config.database)
|
|
358
|
+
attributes['db.name'] = config.database;
|
|
359
|
+
if (config.user)
|
|
360
|
+
attributes['db.user'] = config.user;
|
|
361
|
+
// Build sanitized connection string
|
|
362
|
+
if (config.host || config.user || config.database) {
|
|
363
|
+
const host = config.host || 'localhost';
|
|
364
|
+
const port = config.port || 5432;
|
|
365
|
+
const database = config.database || '';
|
|
366
|
+
const user = config.user || '';
|
|
367
|
+
attributes['db.connection_string'] = `postgresql://${user}:***@${host}:${port}/${database}`;
|
|
368
|
+
}
|
|
369
|
+
// Create span
|
|
370
|
+
const span = new span_1.Span({
|
|
371
|
+
operationName,
|
|
372
|
+
serviceName: integration._serviceName,
|
|
373
|
+
kind: 'client',
|
|
374
|
+
traceId,
|
|
375
|
+
parentSpanId,
|
|
376
|
+
attributes,
|
|
377
|
+
});
|
|
378
|
+
if (isPromise) {
|
|
379
|
+
// Promise-style: call original, then end span on resolve/reject
|
|
380
|
+
try {
|
|
381
|
+
const result = original.apply(this, args);
|
|
382
|
+
if (result && typeof result.then === 'function') {
|
|
383
|
+
return result.then((value) => {
|
|
384
|
+
span.end();
|
|
385
|
+
integration._onSpanEnd(span);
|
|
386
|
+
return value;
|
|
387
|
+
}, (error) => {
|
|
388
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
389
|
+
span.end();
|
|
390
|
+
integration._onSpanEnd(span);
|
|
391
|
+
throw error;
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
// Sync return (unlikely but defensive)
|
|
395
|
+
span.end();
|
|
396
|
+
integration._onSpanEnd(span);
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
401
|
+
span.end();
|
|
402
|
+
integration._onSpanEnd(span);
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// Callback-style: wrap callback to end span
|
|
408
|
+
const wrappedArgs = [...args];
|
|
409
|
+
const cbIndex = wrappedArgs.findIndex((a) => typeof a === 'function');
|
|
410
|
+
if (cbIndex !== -1) {
|
|
411
|
+
const originalCb = wrappedArgs[cbIndex];
|
|
412
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
413
|
+
wrappedArgs[cbIndex] = function wrappedCallback(err, result) {
|
|
414
|
+
if (err) {
|
|
415
|
+
span.setStatus('error', err instanceof Error ? err.message : String(err));
|
|
416
|
+
}
|
|
417
|
+
span.end();
|
|
418
|
+
integration._onSpanEnd(span);
|
|
419
|
+
return originalCb.call(this, err, result);
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return original.apply(this, wrappedArgs);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
// If instrumentation code fails, fall through to original
|
|
427
|
+
return original.apply(this, args);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Wrap pg.Pool.prototype.query to create db.query spans.
|
|
433
|
+
*
|
|
434
|
+
* Pool.query is a convenience method that acquires a client, runs the query,
|
|
435
|
+
* and releases the client. We patch it separately to track pool-level queries.
|
|
436
|
+
*
|
|
437
|
+
* @param original - The original Pool.prototype.query function
|
|
438
|
+
* @returns A wrapped version of the query function
|
|
439
|
+
*/
|
|
440
|
+
_wrapPoolQuery(original) {
|
|
441
|
+
const integration = this;
|
|
442
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
443
|
+
return function patchedPoolQuery(...args) {
|
|
444
|
+
try {
|
|
445
|
+
const { text, callback, isPromise } = normalizeQueryArgs(args);
|
|
446
|
+
if (!text) {
|
|
447
|
+
return original.apply(this, args);
|
|
448
|
+
}
|
|
449
|
+
// Get active span context
|
|
450
|
+
const parentSpan = (0, context_1.getActiveSpan)();
|
|
451
|
+
const traceId = parentSpan?.traceId ?? (0, id_1.generateTraceId)();
|
|
452
|
+
const parentSpanId = parentSpan?.id ?? null;
|
|
453
|
+
const operation = extractSqlOperation(text);
|
|
454
|
+
const table = extractTableName(text);
|
|
455
|
+
const sanitizedSql = sanitizeSql(text, integration._options.maxQueryLength);
|
|
456
|
+
const operationName = operation !== 'UNKNOWN' ? `db.query ${operation}` : 'db.query';
|
|
457
|
+
// Build attributes
|
|
458
|
+
const attributes = {
|
|
459
|
+
'db.system': 'postgresql',
|
|
460
|
+
'db.statement': sanitizedSql,
|
|
461
|
+
};
|
|
462
|
+
if (operation !== 'UNKNOWN')
|
|
463
|
+
attributes['db.operation'] = operation;
|
|
464
|
+
if (table)
|
|
465
|
+
attributes['db.sql.table'] = table;
|
|
466
|
+
// Extract connection info from Pool options
|
|
467
|
+
const poolOptions = this.options || {};
|
|
468
|
+
if (poolOptions.database)
|
|
469
|
+
attributes['db.name'] = poolOptions.database;
|
|
470
|
+
if (poolOptions.user)
|
|
471
|
+
attributes['db.user'] = poolOptions.user;
|
|
472
|
+
if (poolOptions.host || poolOptions.user || poolOptions.database) {
|
|
473
|
+
const host = poolOptions.host || 'localhost';
|
|
474
|
+
const port = poolOptions.port || 5432;
|
|
475
|
+
const database = poolOptions.database || '';
|
|
476
|
+
const user = poolOptions.user || '';
|
|
477
|
+
attributes['db.connection_string'] = `postgresql://${user}:***@${host}:${port}/${database}`;
|
|
478
|
+
}
|
|
479
|
+
// Create span
|
|
480
|
+
const span = new span_1.Span({
|
|
481
|
+
operationName,
|
|
482
|
+
serviceName: integration._serviceName,
|
|
483
|
+
kind: 'client',
|
|
484
|
+
traceId,
|
|
485
|
+
parentSpanId,
|
|
486
|
+
attributes,
|
|
487
|
+
});
|
|
488
|
+
if (isPromise) {
|
|
489
|
+
try {
|
|
490
|
+
const result = original.apply(this, args);
|
|
491
|
+
if (result && typeof result.then === 'function') {
|
|
492
|
+
return result.then((value) => {
|
|
493
|
+
span.end();
|
|
494
|
+
integration._onSpanEnd(span);
|
|
495
|
+
return value;
|
|
496
|
+
}, (error) => {
|
|
497
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
498
|
+
span.end();
|
|
499
|
+
integration._onSpanEnd(span);
|
|
500
|
+
throw error;
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
span.end();
|
|
504
|
+
integration._onSpanEnd(span);
|
|
505
|
+
return result;
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
509
|
+
span.end();
|
|
510
|
+
integration._onSpanEnd(span);
|
|
511
|
+
throw error;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
const wrappedArgs = [...args];
|
|
516
|
+
const cbIndex = wrappedArgs.findIndex((a) => typeof a === 'function');
|
|
517
|
+
if (cbIndex !== -1) {
|
|
518
|
+
const originalCb = wrappedArgs[cbIndex];
|
|
519
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
520
|
+
wrappedArgs[cbIndex] = function wrappedCallback(err, result) {
|
|
521
|
+
if (err) {
|
|
522
|
+
span.setStatus('error', err instanceof Error ? err.message : String(err));
|
|
523
|
+
}
|
|
524
|
+
span.end();
|
|
525
|
+
integration._onSpanEnd(span);
|
|
526
|
+
return originalCb.call(this, err, result);
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
return original.apply(this, wrappedArgs);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
return original.apply(this, args);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Wrap pg.Pool.prototype.connect to create db.connect spans that measure
|
|
539
|
+
* the time to acquire a connection from the pool.
|
|
540
|
+
*
|
|
541
|
+
* @param original - The original Pool.prototype.connect function
|
|
542
|
+
* @returns A wrapped version of the connect function
|
|
543
|
+
*/
|
|
544
|
+
_wrapPoolConnect(original) {
|
|
545
|
+
const integration = this;
|
|
546
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
547
|
+
return function patchedPoolConnect(...args) {
|
|
548
|
+
try {
|
|
549
|
+
// Get active span context
|
|
550
|
+
const parentSpan = (0, context_1.getActiveSpan)();
|
|
551
|
+
const traceId = parentSpan?.traceId ?? (0, id_1.generateTraceId)();
|
|
552
|
+
const parentSpanId = parentSpan?.id ?? null;
|
|
553
|
+
// Build attributes
|
|
554
|
+
const attributes = {
|
|
555
|
+
'db.system': 'postgresql',
|
|
556
|
+
};
|
|
557
|
+
// Extract connection info from Pool options
|
|
558
|
+
const poolOptions = this.options || {};
|
|
559
|
+
if (poolOptions.database)
|
|
560
|
+
attributes['db.name'] = poolOptions.database;
|
|
561
|
+
// Create span
|
|
562
|
+
const span = new span_1.Span({
|
|
563
|
+
operationName: 'db.connect',
|
|
564
|
+
serviceName: integration._serviceName,
|
|
565
|
+
kind: 'client',
|
|
566
|
+
traceId,
|
|
567
|
+
parentSpanId,
|
|
568
|
+
attributes,
|
|
569
|
+
});
|
|
570
|
+
// Check if callback-style or promise-style
|
|
571
|
+
const callback = typeof args[args.length - 1] === 'function'
|
|
572
|
+
? args[args.length - 1]
|
|
573
|
+
: null;
|
|
574
|
+
if (callback) {
|
|
575
|
+
// Callback-style
|
|
576
|
+
const wrappedArgs = [...args];
|
|
577
|
+
wrappedArgs[wrappedArgs.length - 1] = function wrappedConnectCallback(err, client, release) {
|
|
578
|
+
if (err) {
|
|
579
|
+
span.setStatus('error', err instanceof Error ? err.message : String(err));
|
|
580
|
+
}
|
|
581
|
+
span.end();
|
|
582
|
+
integration._onSpanEnd(span);
|
|
583
|
+
return callback.call(this, err, client, release);
|
|
584
|
+
};
|
|
585
|
+
return original.apply(this, wrappedArgs);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
// Promise-style
|
|
589
|
+
const result = original.apply(this, args);
|
|
590
|
+
if (result && typeof result.then === 'function') {
|
|
591
|
+
return result.then((client) => {
|
|
592
|
+
span.end();
|
|
593
|
+
integration._onSpanEnd(span);
|
|
594
|
+
return client;
|
|
595
|
+
}, (error) => {
|
|
596
|
+
span.setStatus('error', error instanceof Error ? error.message : String(error));
|
|
597
|
+
span.end();
|
|
598
|
+
integration._onSpanEnd(span);
|
|
599
|
+
throw error;
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
// Sync return (unlikely)
|
|
603
|
+
span.end();
|
|
604
|
+
integration._onSpanEnd(span);
|
|
605
|
+
return result;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
catch (error) {
|
|
609
|
+
// If instrumentation code fails, fall through to original
|
|
610
|
+
return original.apply(this, args);
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
exports.PgIntegration = PgIntegration;
|
|
616
|
+
//# sourceMappingURL=pg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/integrations/pg.ts"],"names":[],"mappings":"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"}
|