@sentry/core 10.41.0-beta.0 → 10.42.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.
Files changed (54) hide show
  1. package/build/cjs/client.js +10 -0
  2. package/build/cjs/client.js.map +1 -1
  3. package/build/cjs/index.js +2 -0
  4. package/build/cjs/index.js.map +1 -1
  5. package/build/cjs/integrations/consola.js +103 -12
  6. package/build/cjs/integrations/consola.js.map +1 -1
  7. package/build/cjs/integrations/postgresjs.js +434 -0
  8. package/build/cjs/integrations/postgresjs.js.map +1 -0
  9. package/build/cjs/server-runtime-client.js +28 -0
  10. package/build/cjs/server-runtime-client.js.map +1 -1
  11. package/build/cjs/tracing/langchain/index.js +11 -2
  12. package/build/cjs/tracing/langchain/index.js.map +1 -1
  13. package/build/cjs/tracing/langchain/utils.js +39 -6
  14. package/build/cjs/tracing/langchain/utils.js.map +1 -1
  15. package/build/cjs/utils/version.js +1 -1
  16. package/build/cjs/utils/version.js.map +1 -1
  17. package/build/esm/client.js +10 -0
  18. package/build/esm/client.js.map +1 -1
  19. package/build/esm/index.js +1 -0
  20. package/build/esm/index.js.map +1 -1
  21. package/build/esm/integrations/consola.js +104 -13
  22. package/build/esm/integrations/consola.js.map +1 -1
  23. package/build/esm/integrations/postgresjs.js +430 -0
  24. package/build/esm/integrations/postgresjs.js.map +1 -0
  25. package/build/esm/package.json +1 -1
  26. package/build/esm/server-runtime-client.js +28 -0
  27. package/build/esm/server-runtime-client.js.map +1 -1
  28. package/build/esm/tracing/langchain/index.js +11 -2
  29. package/build/esm/tracing/langchain/index.js.map +1 -1
  30. package/build/esm/tracing/langchain/utils.js +39 -6
  31. package/build/esm/tracing/langchain/utils.js.map +1 -1
  32. package/build/esm/utils/version.js +1 -1
  33. package/build/esm/utils/version.js.map +1 -1
  34. package/build/types/client.d.ts +13 -3
  35. package/build/types/client.d.ts.map +1 -1
  36. package/build/types/index.d.ts +1 -0
  37. package/build/types/index.d.ts.map +1 -1
  38. package/build/types/integrations/consola.d.ts +9 -4
  39. package/build/types/integrations/consola.d.ts.map +1 -1
  40. package/build/types/integrations/postgresjs.d.ts +62 -0
  41. package/build/types/integrations/postgresjs.d.ts.map +1 -0
  42. package/build/types/server-runtime-client.d.ts +12 -0
  43. package/build/types/server-runtime-client.d.ts.map +1 -1
  44. package/build/types/tracing/langchain/index.d.ts.map +1 -1
  45. package/build/types/tracing/langchain/utils.d.ts.map +1 -1
  46. package/build/types/types-hoist/replay.d.ts +0 -1
  47. package/build/types/types-hoist/replay.d.ts.map +1 -1
  48. package/build/types-ts3.8/client.d.ts +13 -3
  49. package/build/types-ts3.8/index.d.ts +1 -0
  50. package/build/types-ts3.8/integrations/consola.d.ts +9 -4
  51. package/build/types-ts3.8/integrations/postgresjs.d.ts +62 -0
  52. package/build/types-ts3.8/server-runtime-client.d.ts +12 -0
  53. package/build/types-ts3.8/types-hoist/replay.d.ts +0 -4
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"consola.js","sources":["../../../src/integrations/consola.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { getClient } from '../currentScopes';\nimport { _INTERNAL_captureLog } from '../logs/internal';\nimport { formatConsoleArgs } from '../logs/utils';\nimport type { LogSeverityLevel } from '../types-hoist/log';\n\n/**\n * Options for the Sentry Consola reporter.\n */\ninterface ConsolaReporterOptions {\n /**\n * Use this option to filter which levels should be captured. By default, all levels are captured.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Only capture error and warn logs\n * levels: ['error', 'warn'],\n * });\n * consola.addReporter(sentryReporter);\n * ```\n */\n levels?: Array<LogSeverityLevel>;\n\n /**\n * Optionally provide a specific Sentry client instance to use for capturing logs.\n * If not provided, the current client will be retrieved using `getClient()`.\n *\n * This is useful when you want to use specific client options for log normalization\n * or when working with multiple client instances.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * client: myCustomClient,\n * });\n * ```\n */\n client?: Client;\n}\n\nexport interface ConsolaReporter {\n log: (logObj: ConsolaLogObject) => void;\n}\n\n/**\n * Represents a log object that Consola reporters receive.\n *\n * This interface matches the structure of log objects passed to Consola reporters.\n * See: https://github.com/unjs/consola#custom-reporters\n *\n * @example\n * ```ts\n * const reporter = {\n * log(logObj: ConsolaLogObject) {\n * console.log(`[${logObj.type}] ${logObj.message || logObj.args?.join(' ')}`);\n * }\n * };\n * consola.addReporter(reporter);\n * ```\n */\nexport interface ConsolaLogObject {\n /**\n * Allows additional custom properties to be set on the log object.\n * These properties will be captured as log attributes with a 'consola.' prefix.\n *\n * @example\n * ```ts\n * const reporter = Sentry.createConsolaReporter();\n * reporter.log({\n * type: 'info',\n * message: 'User action',\n * userId: 123,\n * sessionId: 'abc-123'\n * });\n * // Will create attributes: consola.userId and consola.sessionId\n * ```\n */\n [key: string]: unknown;\n\n /**\n * The numeric log level (0-5) or null.\n *\n * Consola log levels:\n * - 0: Fatal and Error\n * - 1: Warnings\n * - 2: Normal logs\n * - 3: Informational logs, success, fail, ready, start, box, ...\n * - 4: Debug logs\n * - 5: Trace logs\n * - null: Some special types like 'verbose'\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-level\n */\n level?: number | null;\n\n /**\n * The log type/method name (e.g., 'error', 'warn', 'info', 'debug', 'trace', 'success', 'fail', etc.).\n *\n * Consola built-in types include:\n * - Standard: silent, fatal, error, warn, log, info, success, fail, ready, start, box, debug, trace, verbose\n * - Custom types can also be defined\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-types\n */\n type?: string;\n\n /**\n * An optional tag/scope for the log entry.\n *\n * Tags are created using `consola.withTag('scope')` and help categorize logs.\n *\n * @example\n * ```ts\n * const scopedLogger = consola.withTag('auth');\n * scopedLogger.info('User logged in'); // tag will be 'auth'\n * ```\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#withtagtag\n */\n tag?: string;\n\n /**\n * The raw arguments passed to the log method.\n *\n * These args are typically formatted into the final `message`. In Consola reporters, `message` is not provided.\n *\n * @example\n * ```ts\n * consola.info('Hello', 'world', { user: 'john' });\n * // args = ['Hello', 'world', { user: 'john' }]\n * ```\n *\n * @example\n * ```ts\n * // `message` is a reserved property in Consola\n * consola.log({ message: 'Hello' });\n * // args = ['Hello']\n * ```\n */\n args?: unknown[];\n\n /**\n * The timestamp when the log was created.\n *\n * This is automatically set by Consola when the log is created.\n */\n date?: Date;\n\n /**\n * The formatted log message.\n *\n * When provided, this is the final formatted message. When not provided,\n * the message should be constructed from the `args` array.\n */\n message?: string;\n}\n\nconst DEFAULT_CAPTURED_LEVELS: Array<LogSeverityLevel> = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Creates a new Sentry reporter for Consola that forwards logs to Sentry. Requires the `enableLogs` option to be enabled.\n *\n * **Note: This integration supports Consola v3.x only.** The reporter interface and log object structure\n * may differ in other versions of Consola.\n *\n * @param options - Configuration options for the reporter.\n * @returns A Consola reporter that can be added to consola instances.\n *\n * @example\n * ```ts\n * import * as Sentry from '@sentry/node';\n * import { consola } from 'consola';\n *\n * Sentry.init({\n * enableLogs: true,\n * });\n *\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Optional: filter levels to capture\n * levels: ['error', 'warn', 'info'],\n * });\n *\n * consola.addReporter(sentryReporter);\n *\n * // Now consola logs will be captured by Sentry\n * consola.info('This will be sent to Sentry');\n * consola.error('This error will also be sent to Sentry');\n * ```\n */\nexport function createConsolaReporter(options: ConsolaReporterOptions = {}): ConsolaReporter {\n const levels = new Set(options.levels ?? DEFAULT_CAPTURED_LEVELS);\n const providedClient = options.client;\n\n return {\n log(logObj: ConsolaLogObject) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type, level, message: consolaMessage, args, tag, date: _date, ...attributes } = logObj;\n\n // Get client - use provided client or current client\n const client = providedClient || getClient();\n if (!client) {\n return;\n }\n\n // Determine the log severity level\n const logSeverityLevel = getLogSeverityLevel(type, level);\n\n // Early exit if this level should not be captured\n if (!levels.has(logSeverityLevel)) {\n return;\n }\n\n const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = client.getOptions();\n\n // Format the log message using the same approach as consola's basic reporter\n const messageParts = [];\n if (consolaMessage) {\n messageParts.push(consolaMessage);\n }\n if (args && args.length > 0) {\n messageParts.push(formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth));\n }\n const message = messageParts.join(' ');\n\n // Build attributes\n attributes['sentry.origin'] = 'auto.log.consola';\n\n if (tag) {\n attributes['consola.tag'] = tag;\n }\n\n if (type) {\n attributes['consola.type'] = type;\n }\n\n // Only add level if it's a valid number (not null/undefined)\n if (level != null && typeof level === 'number') {\n attributes['consola.level'] = level;\n }\n\n _INTERNAL_captureLog({\n level: logSeverityLevel,\n message,\n attributes,\n });\n },\n };\n}\n\n// Mapping from consola log types to Sentry log severity levels\nconst CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP: Record<string, LogSeverityLevel> = {\n // Consola built-in types\n silent: 'trace',\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n log: 'info',\n info: 'info',\n success: 'info',\n fail: 'error',\n ready: 'info',\n start: 'info',\n box: 'info',\n debug: 'debug',\n trace: 'trace',\n verbose: 'debug',\n // Custom types that might exist\n critical: 'fatal',\n notice: 'info',\n};\n\n// Mapping from consola log levels (numbers) to Sentry log severity levels\nconst CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP: Record<number, LogSeverityLevel> = {\n 0: 'fatal', // Fatal and Error\n 1: 'warn', // Warnings\n 2: 'info', // Normal logs\n 3: 'info', // Informational logs, success, fail, ready, start, ...\n 4: 'debug', // Debug logs\n 5: 'trace', // Trace logs\n};\n\n/**\n * Determines the log severity level from Consola type and level.\n *\n * @param type - The Consola log type (e.g., 'error', 'warn', 'info')\n * @param level - The Consola numeric log level (0-5) or null for some types like 'verbose'\n * @returns The corresponding Sentry log severity level\n */\nfunction getLogSeverityLevel(type?: string, level?: number | null): LogSeverityLevel {\n // Handle special case for verbose logs (level can be null with infinite level in Consola)\n if (type === 'verbose') {\n return 'debug';\n }\n\n // Handle silent logs - these should be at trace level\n if (type === 'silent') {\n return 'trace';\n }\n\n // First try to map by type (more specific)\n if (type) {\n const mappedLevel = CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP[type];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Fallback to level mapping (handle null level)\n if (typeof level === 'number') {\n const mappedLevel = CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP[level];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Default fallback\n return 'info';\n}\n"],"names":[],"mappings":";;;;AAMA;AACA;AACA;;AAsJA,MAAM,uBAAuB,GAA4B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;;AAE7G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,OAAO,GAA2B,EAAE,EAAmB;AAC7F,EAAE,MAAM,MAAA,GAAS,IAAI,GAAG,CAAC,OAAO,CAAC,MAAA,IAAU,uBAAuB,CAAC;AACnE,EAAE,MAAM,cAAA,GAAiB,OAAO,CAAC,MAAM;;AAEvC,EAAE,OAAO;AACT,IAAI,GAAG,CAAC,MAAM,EAAoB;AAClC;AACA,MAAM,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAA,EAAW,GAAI,MAAM;;AAEpG;AACA,MAAM,MAAM,MAAA,GAAS,kBAAkB,SAAS,EAAE;AAClD,MAAM,IAAI,CAAC,MAAM,EAAE;AACnB,QAAQ;AACR,MAAM;;AAEN;AACA,MAAM,MAAM,mBAAmB,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC;;AAE/D;AACA,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE;AACzC,QAAQ;AACR,MAAM;;AAEN,MAAM,MAAM,EAAE,cAAA,GAAiB,CAAC,EAAE,mBAAA,GAAsB,IAAA,KAAU,MAAM,CAAC,UAAU,EAAE;;AAErF;AACA,MAAM,MAAM,YAAA,GAAe,EAAE;AAC7B,MAAM,IAAI,cAAc,EAAE;AAC1B,QAAQ,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC;AACzC,MAAM;AACN,MAAM,IAAI,IAAA,IAAQ,IAAI,CAAC,MAAA,GAAS,CAAC,EAAE;AACnC,QAAQ,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC;AACvF,MAAM;AACN,MAAM,MAAM,UAAU,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;;AAE5C;AACA,MAAM,UAAU,CAAC,eAAe,CAAA,GAAI,kBAAkB;;AAEtD,MAAM,IAAI,GAAG,EAAE;AACf,QAAQ,UAAU,CAAC,aAAa,CAAA,GAAI,GAAG;AACvC,MAAM;;AAEN,MAAM,IAAI,IAAI,EAAE;AAChB,QAAQ,UAAU,CAAC,cAAc,CAAA,GAAI,IAAI;AACzC,MAAM;;AAEN;AACA,MAAM,IAAI,KAAA,IAAS,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAQ,EAAE;AACtD,QAAQ,UAAU,CAAC,eAAe,CAAA,GAAI,KAAK;AAC3C,MAAM;;AAEN,MAAM,oBAAoB,CAAC;AAC3B,QAAQ,KAAK,EAAE,gBAAgB;AAC/B,QAAQ,OAAO;AACf,QAAQ,UAAU;AAClB,OAAO,CAAC;AACR,IAAI,CAAC;AACL,GAAG;AACH;;AAEA;AACA,MAAM,sCAAsC,GAAqC;AACjF;AACA,EAAE,MAAM,EAAE,OAAO;AACjB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,IAAI,EAAE,MAAM;AACd,EAAE,GAAG,EAAE,MAAM;AACb,EAAE,IAAI,EAAE,MAAM;AACd,EAAE,OAAO,EAAE,MAAM;AACjB,EAAE,IAAI,EAAE,OAAO;AACf,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,GAAG,EAAE,MAAM;AACb,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,OAAO,EAAE,OAAO;AAClB;AACA,EAAE,QAAQ,EAAE,OAAO;AACnB,EAAE,MAAM,EAAE,MAAM;AAChB,CAAC;;AAED;AACA,MAAM,uCAAuC,GAAqC;AAClF,EAAE,CAAC,EAAE,OAAO;AACZ,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,OAAO;AACZ,EAAE,CAAC,EAAE,OAAO;AACZ,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,IAAI,EAAW,KAAK,EAAoC;AACrF;AACA,EAAE,IAAI,IAAA,KAAS,SAAS,EAAE;AAC1B,IAAI,OAAO,OAAO;AAClB,EAAE;;AAEF;AACA,EAAE,IAAI,IAAA,KAAS,QAAQ,EAAE;AACzB,IAAI,OAAO,OAAO;AAClB,EAAE;;AAEF;AACA,EAAE,IAAI,IAAI,EAAE;AACZ,IAAI,MAAM,WAAA,GAAc,sCAAsC,CAAC,IAAI,CAAC;AACpE,IAAI,IAAI,WAAW,EAAE;AACrB,MAAM,OAAO,WAAW;AACxB,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,IAAI,OAAO,KAAA,KAAU,QAAQ,EAAE;AACjC,IAAI,MAAM,WAAA,GAAc,uCAAuC,CAAC,KAAK,CAAC;AACtE,IAAI,IAAI,WAAW,EAAE;AACrB,MAAM,OAAO,WAAW;AACxB,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,OAAO,MAAM;AACf;;;;"}
1
+ {"version":3,"file":"consola.js","sources":["../../../src/integrations/consola.ts"],"sourcesContent":["import type { Client } from '../client';\nimport { getClient } from '../currentScopes';\nimport { _INTERNAL_captureLog } from '../logs/internal';\nimport { createConsoleTemplateAttributes, formatConsoleArgs, hasConsoleSubstitutions } from '../logs/utils';\nimport type { LogSeverityLevel } from '../types-hoist/log';\nimport { isPlainObject } from '../utils/is';\nimport { normalize } from '../utils/normalize';\n\n/**\n * Result of extracting structured attributes from console arguments.\n */\ninterface ExtractAttributesResult {\n /**\n * The log message to use for the log entry, typically constructed from the console arguments.\n */\n message?: string;\n\n /**\n * The parameterized template string which is added as `sentry.message.template` attribute if applicable.\n */\n messageTemplate?: string;\n\n /**\n * Remaining arguments to process as attributes with keys like `sentry.message.parameter.0`, `sentry.message.parameter.1`, etc.\n */\n messageParameters?: unknown[];\n\n /**\n * Additional attributes to add to the log.\n */\n attributes?: Record<string, unknown>;\n}\n\n/**\n * Options for the Sentry Consola reporter.\n */\ninterface ConsolaReporterOptions {\n /**\n * Use this option to filter which levels should be captured. By default, all levels are captured.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Only capture error and warn logs\n * levels: ['error', 'warn'],\n * });\n * consola.addReporter(sentryReporter);\n * ```\n */\n levels?: Array<LogSeverityLevel>;\n\n /**\n * Optionally provide a specific Sentry client instance to use for capturing logs.\n * If not provided, the current client will be retrieved using `getClient()`.\n *\n * This is useful when you want to use specific client options for log normalization\n * or when working with multiple client instances.\n *\n * @example\n * ```ts\n * const sentryReporter = Sentry.createConsolaReporter({\n * client: myCustomClient,\n * });\n * ```\n */\n client?: Client;\n}\n\nexport interface ConsolaReporter {\n log: (logObj: ConsolaLogObject) => void;\n}\n\n/**\n * Represents a log object that Consola reporters receive.\n *\n * This interface matches the structure of log objects passed to Consola reporters.\n * See: https://github.com/unjs/consola#custom-reporters\n *\n * @example\n * ```ts\n * const reporter = {\n * log(logObj: ConsolaLogObject) {\n * console.log(`[${logObj.type}] ${logObj.message || logObj.args?.join(' ')}`);\n * }\n * };\n * consola.addReporter(reporter);\n * ```\n */\nexport interface ConsolaLogObject {\n /**\n * Allows additional custom properties to be set on the log object. These properties will be captured as log attributes.\n *\n * Additional properties are set when passing a single object with a `message` (`consola.[type]({ message: '', ... })`) or if the reporter is called directly\n *\n * @example\n * ```ts\n * const reporter = Sentry.createConsolaReporter();\n * reporter.log({\n * type: 'info',\n * message: 'User action',\n * userId: 123,\n * sessionId: 'abc-123'\n * });\n * // Will create attributes: `userId` and `sessionId`\n * ```\n */\n [key: string]: unknown;\n\n /**\n * The numeric log level (0-5) or null.\n *\n * Consola log levels:\n * - 0: Fatal and Error\n * - 1: Warnings\n * - 2: Normal logs\n * - 3: Informational logs, success, fail, ready, start, box, ...\n * - 4: Debug logs\n * - 5: Trace logs\n * - null: Some special types like 'verbose'\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-level\n */\n level?: number | null;\n\n /**\n * The log type/method name (e.g., 'error', 'warn', 'info', 'debug', 'trace', 'success', 'fail', etc.).\n *\n * Consola built-in types include:\n * - Standard: silent, fatal, error, warn, log, info, success, fail, ready, start, box, debug, trace, verbose\n * - Custom types can also be defined\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#log-types\n */\n type?: string;\n\n /**\n * An optional tag/scope for the log entry.\n *\n * Tags are created using `consola.withTag('scope')` and help categorize logs.\n *\n * @example\n * ```ts\n * const scopedLogger = consola.withTag('auth');\n * scopedLogger.info('User logged in'); // tag will be 'auth'\n * ```\n *\n * See: https://github.com/unjs/consola/blob/main/README.md#withtagtag\n */\n tag?: string;\n\n /**\n * The raw arguments passed to the log method.\n *\n * These args are typically formatted into the final `message`. In Consola reporters, `message` is not provided. See: https://github.com/unjs/consola/issues/406#issuecomment-3684792551\n *\n * @example\n * ```ts\n * consola.info('Hello', 'world', { user: 'john' });\n * // args = ['Hello', 'world', { user: 'john' }]\n * ```\n *\n * @example\n * ```ts\n * // `message` is a reserved property in Consola\n * consola.log({ message: 'Hello' });\n * // args = ['Hello']\n * ```\n */\n args?: unknown[];\n\n /**\n * The timestamp when the log was created.\n *\n * This is automatically set by Consola when the log is created.\n */\n date?: Date;\n\n /**\n * The formatted log message.\n *\n * When provided, this is the final formatted message. When not provided,\n * the message should be constructed from the `args` array.\n *\n * Note: In reporters, `message` is typically undefined. It is primarily for\n * `consola.[type]({ message: 'xxx' })` usage and is normalized into `args` before\n * reporters receive the log object. See: https://github.com/unjs/consola/issues/406#issuecomment-3684792551\n */\n message?: string;\n}\n\nconst DEFAULT_CAPTURED_LEVELS: Array<LogSeverityLevel> = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Creates a new Sentry reporter for Consola that forwards logs to Sentry. Requires the `enableLogs` option to be enabled.\n *\n * **Note: This integration supports Consola v3.x only.** The reporter interface and log object structure\n * may differ in other versions of Consola.\n *\n * @param options - Configuration options for the reporter.\n * @returns A Consola reporter that can be added to consola instances.\n *\n * @example\n * ```ts\n * import * as Sentry from '@sentry/node';\n * import { consola } from 'consola';\n *\n * Sentry.init({\n * enableLogs: true,\n * });\n *\n * const sentryReporter = Sentry.createConsolaReporter({\n * // Optional: filter levels to capture\n * levels: ['error', 'warn', 'info'],\n * });\n *\n * consola.addReporter(sentryReporter);\n *\n * // Now consola logs will be captured by Sentry\n * consola.info('This will be sent to Sentry');\n * consola.error('This error will also be sent to Sentry');\n * ```\n */\nexport function createConsolaReporter(options: ConsolaReporterOptions = {}): ConsolaReporter {\n const levels = new Set(options.levels ?? DEFAULT_CAPTURED_LEVELS);\n const providedClient = options.client;\n\n return {\n log(logObj: ConsolaLogObject) {\n // We need to exclude certain known properties from being added as additional attributes\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { type, level, message: consolaMessage, args, tag, date: _date, ...rest } = logObj;\n\n // Get client - use provided client or current client\n const client = providedClient || getClient();\n if (!client) {\n return;\n }\n\n // Determine the log severity level\n const logSeverityLevel = getLogSeverityLevel(type, level);\n\n // Early exit if this level should not be captured\n if (!levels.has(logSeverityLevel)) {\n return;\n }\n\n const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = client.getOptions();\n\n const attributes: Record<string, unknown> = {};\n\n // Build attributes\n for (const [key, value] of Object.entries(rest)) {\n attributes[key] = normalize(value, normalizeDepth, normalizeMaxBreadth);\n }\n\n attributes['sentry.origin'] = 'auto.log.consola';\n\n if (tag) {\n attributes['consola.tag'] = tag;\n }\n\n if (type) {\n attributes['consola.type'] = type;\n }\n\n // Only add level if it's a valid number (not null/undefined)\n if (level != null && typeof level === 'number') {\n attributes['consola.level'] = level;\n }\n\n const extractionResult = processExtractedAttributes(\n defaultExtractAttributes(args, normalizeDepth, normalizeMaxBreadth),\n normalizeDepth,\n normalizeMaxBreadth,\n );\n\n if (extractionResult?.attributes) {\n Object.assign(attributes, extractionResult.attributes);\n }\n\n _INTERNAL_captureLog({\n level: logSeverityLevel,\n message:\n extractionResult?.message ||\n consolaMessage ||\n (args && formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth)) ||\n '',\n attributes,\n });\n },\n };\n}\n\n// Mapping from consola log types to Sentry log severity levels\nconst CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP: Record<string, LogSeverityLevel> = {\n // Consola built-in types\n silent: 'trace',\n fatal: 'fatal',\n error: 'error',\n warn: 'warn',\n log: 'info',\n info: 'info',\n success: 'info',\n fail: 'error',\n ready: 'info',\n start: 'info',\n box: 'info',\n debug: 'debug',\n trace: 'trace',\n verbose: 'debug',\n // Custom types that might exist\n critical: 'fatal',\n notice: 'info',\n};\n\n// Mapping from consola log levels (numbers) to Sentry log severity levels\nconst CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP: Record<number, LogSeverityLevel> = {\n 0: 'fatal', // Fatal and Error\n 1: 'warn', // Warnings\n 2: 'info', // Normal logs\n 3: 'info', // Informational logs, success, fail, ready, start, ...\n 4: 'debug', // Debug logs\n 5: 'trace', // Trace logs\n};\n\n/**\n * Determines the log severity level from Consola type and level.\n *\n * @param type - The Consola log type (e.g., 'error', 'warn', 'info')\n * @param level - The Consola numeric log level (0-5) or null for some types like 'verbose'\n * @returns The corresponding Sentry log severity level\n */\nfunction getLogSeverityLevel(type?: string, level?: number | null): LogSeverityLevel {\n // Handle special case for verbose logs (level can be null with infinite level in Consola)\n if (type === 'verbose') {\n return 'debug';\n }\n\n // Handle silent logs - these should be at trace level\n if (type === 'silent') {\n return 'trace';\n }\n\n // First try to map by type (more specific)\n if (type) {\n const mappedLevel = CONSOLA_TYPE_TO_LOG_SEVERITY_LEVEL_MAP[type];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Fallback to level mapping (handle null level)\n if (typeof level === 'number') {\n const mappedLevel = CONSOLA_LEVEL_TO_LOG_SEVERITY_LEVEL_MAP[level];\n if (mappedLevel) {\n return mappedLevel;\n }\n }\n\n // Default fallback\n return 'info';\n}\n\n/**\n * Extracts structured attributes from console arguments. If the first argument is a plain object, its properties are extracted as attributes.\n */\nfunction defaultExtractAttributes(\n args: unknown[] | undefined,\n normalizeDepth: number,\n normalizeMaxBreadth: number,\n): ExtractAttributesResult {\n if (!args?.length) {\n return { message: '' };\n }\n\n // Message looks like how consola logs the message to the console (all args stringified and joined)\n const message = formatConsoleArgs(args, normalizeDepth, normalizeMaxBreadth);\n\n const firstArg = args[0];\n\n if (isPlainObject(firstArg)) {\n // Remaining args start from index 2 i f we used second arg as message, otherwise from index 1\n const remainingArgsStartIndex = typeof args[1] === 'string' ? 2 : 1;\n const remainingArgs = args.slice(remainingArgsStartIndex);\n\n return {\n message,\n // Object content from first arg is added as attributes\n attributes: firstArg,\n // Add remaining args as message parameters\n messageParameters: remainingArgs,\n };\n } else {\n const followingArgs = args.slice(1);\n\n const shouldAddTemplateAttr =\n followingArgs.length > 0 && typeof firstArg === 'string' && !hasConsoleSubstitutions(firstArg);\n\n return {\n message,\n messageTemplate: shouldAddTemplateAttr ? firstArg : undefined,\n messageParameters: shouldAddTemplateAttr ? followingArgs : undefined,\n };\n }\n}\n\n/**\n * Processes extracted attributes by normalizing them and preparing message parameter attributes if a template is present.\n */\nfunction processExtractedAttributes(\n extractionResult: ExtractAttributesResult,\n normalizeDepth: number,\n normalizeMaxBreadth: number,\n): { message: string | undefined; attributes: Record<string, unknown> } {\n const { message, attributes, messageTemplate, messageParameters } = extractionResult;\n\n const messageParamAttributes: Record<string, unknown> = {};\n\n if (messageTemplate && messageParameters) {\n const templateAttrs = createConsoleTemplateAttributes(messageTemplate, messageParameters);\n\n for (const [key, value] of Object.entries(templateAttrs)) {\n messageParamAttributes[key] = key.startsWith('sentry.message.parameter.')\n ? normalize(value, normalizeDepth, normalizeMaxBreadth)\n : value;\n }\n } else if (messageParameters && messageParameters.length > 0) {\n messageParameters.forEach((arg, index) => {\n messageParamAttributes[`sentry.message.parameter.${index}`] = normalize(arg, normalizeDepth, normalizeMaxBreadth);\n });\n }\n\n return {\n message: message,\n attributes: {\n ...normalize(attributes, normalizeDepth, normalizeMaxBreadth),\n ...messageParamAttributes,\n },\n };\n}\n"],"names":[],"mappings":";;;;;;AAQA;AACA;AACA;;AAoLA,MAAM,uBAAuB,GAA4B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;;AAE7G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,OAAO,GAA2B,EAAE,EAAmB;AAC7F,EAAE,MAAM,MAAA,GAAS,IAAI,GAAG,CAAC,OAAO,CAAC,MAAA,IAAU,uBAAuB,CAAC;AACnE,EAAE,MAAM,cAAA,GAAiB,OAAO,CAAC,MAAM;;AAEvC,EAAE,OAAO;AACT,IAAI,GAAG,CAAC,MAAM,EAAoB;AAClC;AACA;AACA,MAAM,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAA,EAAK,GAAI,MAAM;;AAE9F;AACA,MAAM,MAAM,MAAA,GAAS,kBAAkB,SAAS,EAAE;AAClD,MAAM,IAAI,CAAC,MAAM,EAAE;AACnB,QAAQ;AACR,MAAM;;AAEN;AACA,MAAM,MAAM,mBAAmB,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC;;AAE/D;AACA,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE;AACzC,QAAQ;AACR,MAAM;;AAEN,MAAM,MAAM,EAAE,cAAA,GAAiB,CAAC,EAAE,mBAAA,GAAsB,IAAA,KAAU,MAAM,CAAC,UAAU,EAAE;;AAErF,MAAM,MAAM,UAAU,GAA4B,EAAE;;AAEpD;AACA,MAAM,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAA,IAAK,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACvD,QAAQ,UAAU,CAAC,GAAG,CAAA,GAAI,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,mBAAmB,CAAC;AAC/E,MAAM;;AAEN,MAAM,UAAU,CAAC,eAAe,CAAA,GAAI,kBAAkB;;AAEtD,MAAM,IAAI,GAAG,EAAE;AACf,QAAQ,UAAU,CAAC,aAAa,CAAA,GAAI,GAAG;AACvC,MAAM;;AAEN,MAAM,IAAI,IAAI,EAAE;AAChB,QAAQ,UAAU,CAAC,cAAc,CAAA,GAAI,IAAI;AACzC,MAAM;;AAEN;AACA,MAAM,IAAI,KAAA,IAAS,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAQ,EAAE;AACtD,QAAQ,UAAU,CAAC,eAAe,CAAA,GAAI,KAAK;AAC3C,MAAM;;AAEN,MAAM,MAAM,gBAAA,GAAmB,0BAA0B;AACzD,QAAQ,wBAAwB,CAAC,IAAI,EAAE,cAAc,EAAE,mBAAmB,CAAC;AAC3E,QAAQ,cAAc;AACtB,QAAQ,mBAAmB;AAC3B,OAAO;;AAEP,MAAM,IAAI,gBAAgB,EAAE,UAAU,EAAE;AACxC,QAAQ,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,UAAU,CAAC;AAC9D,MAAM;;AAEN,MAAM,oBAAoB,CAAC;AAC3B,QAAQ,KAAK,EAAE,gBAAgB;AAC/B,QAAQ,OAAO;AACf,UAAU,gBAAgB,EAAE,OAAA;AAC5B,UAAU,cAAA;AACV,WAAW,IAAA,IAAQ,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAA;AAC/E,UAAU,EAAE;AACZ,QAAQ,UAAU;AAClB,OAAO,CAAC;AACR,IAAI,CAAC;AACL,GAAG;AACH;;AAEA;AACA,MAAM,sCAAsC,GAAqC;AACjF;AACA,EAAE,MAAM,EAAE,OAAO;AACjB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,IAAI,EAAE,MAAM;AACd,EAAE,GAAG,EAAE,MAAM;AACb,EAAE,IAAI,EAAE,MAAM;AACd,EAAE,OAAO,EAAE,MAAM;AACjB,EAAE,IAAI,EAAE,OAAO;AACf,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,KAAK,EAAE,MAAM;AACf,EAAE,GAAG,EAAE,MAAM;AACb,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,KAAK,EAAE,OAAO;AAChB,EAAE,OAAO,EAAE,OAAO;AAClB;AACA,EAAE,QAAQ,EAAE,OAAO;AACnB,EAAE,MAAM,EAAE,MAAM;AAChB,CAAC;;AAED;AACA,MAAM,uCAAuC,GAAqC;AAClF,EAAE,CAAC,EAAE,OAAO;AACZ,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,MAAM;AACX,EAAE,CAAC,EAAE,OAAO;AACZ,EAAE,CAAC,EAAE,OAAO;AACZ,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,IAAI,EAAW,KAAK,EAAoC;AACrF;AACA,EAAE,IAAI,IAAA,KAAS,SAAS,EAAE;AAC1B,IAAI,OAAO,OAAO;AAClB,EAAE;;AAEF;AACA,EAAE,IAAI,IAAA,KAAS,QAAQ,EAAE;AACzB,IAAI,OAAO,OAAO;AAClB,EAAE;;AAEF;AACA,EAAE,IAAI,IAAI,EAAE;AACZ,IAAI,MAAM,WAAA,GAAc,sCAAsC,CAAC,IAAI,CAAC;AACpE,IAAI,IAAI,WAAW,EAAE;AACrB,MAAM,OAAO,WAAW;AACxB,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,IAAI,OAAO,KAAA,KAAU,QAAQ,EAAE;AACjC,IAAI,MAAM,WAAA,GAAc,uCAAuC,CAAC,KAAK,CAAC;AACtE,IAAI,IAAI,WAAW,EAAE;AACrB,MAAM,OAAO,WAAW;AACxB,IAAI;AACJ,EAAE;;AAEF;AACA,EAAE,OAAO,MAAM;AACf;;AAEA;AACA;AACA;AACA,SAAS,wBAAwB;AACjC,EAAE,IAAI;AACN,EAAE,cAAc;AAChB,EAAE,mBAAmB;AACrB,EAA2B;AAC3B,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE;AACrB,IAAI,OAAO,EAAE,OAAO,EAAE,IAAI;AAC1B,EAAE;;AAEF;AACA,EAAE,MAAM,OAAA,GAAU,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,mBAAmB,CAAC;;AAE9E,EAAE,MAAM,QAAA,GAAW,IAAI,CAAC,CAAC,CAAC;;AAE1B,EAAE,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE;AAC/B;AACA,IAAI,MAAM,uBAAA,GAA0B,OAAO,IAAI,CAAC,CAAC,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,CAAC;AACvE,IAAI,MAAM,gBAAgB,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC;;AAE7D,IAAI,OAAO;AACX,MAAM,OAAO;AACb;AACA,MAAM,UAAU,EAAE,QAAQ;AAC1B;AACA,MAAM,iBAAiB,EAAE,aAAa;AACtC,KAAK;AACL,EAAE,OAAO;AACT,IAAI,MAAM,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;;AAEvC,IAAI,MAAM,qBAAA;AACV,MAAM,aAAa,CAAC,MAAA,GAAS,KAAK,OAAO,QAAA,KAAa,YAAY,CAAC,uBAAuB,CAAC,QAAQ,CAAC;;AAEpG,IAAI,OAAO;AACX,MAAM,OAAO;AACb,MAAM,eAAe,EAAE,qBAAA,GAAwB,QAAA,GAAW,SAAS;AACnE,MAAM,iBAAiB,EAAE,qBAAA,GAAwB,aAAA,GAAgB,SAAS;AAC1E,KAAK;AACL,EAAE;AACF;;AAEA;AACA;AACA;AACA,SAAS,0BAA0B;AACnC,EAAE,gBAAgB;AAClB,EAAE,cAAc;AAChB,EAAE,mBAAmB;AACrB,EAAwE;AACxE,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAA,EAAkB,GAAI,gBAAgB;;AAEtF,EAAE,MAAM,sBAAsB,GAA4B,EAAE;;AAE5D,EAAE,IAAI,eAAA,IAAmB,iBAAiB,EAAE;AAC5C,IAAI,MAAM,gBAAgB,+BAA+B,CAAC,eAAe,EAAE,iBAAiB,CAAC;;AAE7F,IAAI,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAA,IAAK,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE;AAC9D,MAAM,sBAAsB,CAAC,GAAG,CAAA,GAAI,GAAG,CAAC,UAAU,CAAC,2BAA2B;AAC9E,UAAU,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,mBAAmB;AAC9D,UAAU,KAAK;AACf,IAAI;AACJ,EAAE,CAAA,MAAO,IAAI,iBAAA,IAAqB,iBAAiB,CAAC,MAAA,GAAS,CAAC,EAAE;AAChE,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK;AAC9C,MAAM,sBAAsB,CAAC,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAA,CAAA,GAAA,SAAA,CAAA,GAAA,EAAA,cAAA,EAAA,mBAAA,CAAA;AACA,IAAA,CAAA,CAAA;AACA,EAAA;;AAEA,EAAA,OAAA;AACA,IAAA,OAAA,EAAA,OAAA;AACA,IAAA,UAAA,EAAA;AACA,MAAA,GAAA,SAAA,CAAA,UAAA,EAAA,cAAA,EAAA,mBAAA,CAAA;AACA,MAAA,GAAA,sBAAA;AACA,KAAA;AACA,GAAA;AACA;;;;"}
@@ -0,0 +1,430 @@
1
+ import { DEBUG_BUILD } from '../debug-build.js';
2
+ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes.js';
3
+ import { debug } from '../utils/debug-logger.js';
4
+ import { getActiveSpan } from '../utils/spanUtils.js';
5
+ import { SPAN_STATUS_ERROR } from '../tracing/spanstatus.js';
6
+ import { startSpanManual } from '../tracing/trace.js';
7
+
8
+ // Portable instrumentation for https://github.com/porsager/postgres
9
+ // This can be used in any environment (Node.js, Cloudflare Workers, etc.)
10
+ // without depending on OpenTelemetry module hooking.
11
+
12
+
13
+ const SQL_OPERATION_REGEX = /^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/i;
14
+
15
+ const CONNECTION_CONTEXT_SYMBOL = Symbol('sentryPostgresConnectionContext');
16
+
17
+ // Use the same Symbol.for() markers as the Node.js OTel instrumentation
18
+ // so that both approaches recognize each other and prevent double-wrapping.
19
+ const INSTRUMENTED_MARKER = Symbol.for('sentry.instrumented.postgresjs');
20
+ // Marker to track if a query was created from an instrumented sql instance.
21
+ // This prevents double-spanning when both the wrapper and the Node.js Query.prototype
22
+ // fallback patch are active simultaneously.
23
+ const QUERY_FROM_INSTRUMENTED_SQL = Symbol.for('sentry.query.from.instrumented.sql');
24
+
25
+ /**
26
+ * Instruments a postgres.js `sql` instance with Sentry tracing.
27
+ *
28
+ * This is a portable instrumentation function that works in any environment
29
+ * (Node.js, Cloudflare Workers, etc.) without depending on OpenTelemetry.
30
+ *
31
+ * @example
32
+ * ```javascript
33
+ * import postgres from 'postgres';
34
+ * import * as Sentry from '@sentry/cloudflare'; // or '@sentry/deno'
35
+ *
36
+ * const sql = Sentry.instrumentPostgresJsSql(
37
+ * postgres({ host: 'localhost', database: 'mydb' })
38
+ * );
39
+ *
40
+ * // All queries now create Sentry spans
41
+ * await sql`SELECT * FROM users WHERE id = ${userId}`;
42
+ * ```
43
+ */
44
+ function instrumentPostgresJsSql(sql, options) {
45
+ if (!sql || typeof sql !== 'function') {
46
+ DEBUG_BUILD && debug.warn('instrumentPostgresJsSql: provided value is not a valid postgres.js sql instance');
47
+ return sql;
48
+ }
49
+
50
+ return _instrumentSqlInstance(sql, { requireParentSpan: true, ...options }) ;
51
+ }
52
+
53
+ /**
54
+ * Instruments a sql instance by wrapping its query execution methods.
55
+ */
56
+ function _instrumentSqlInstance(
57
+ sql,
58
+ options,
59
+ parentConnectionContext,
60
+ ) {
61
+ // Check if already instrumented to prevent double-wrapping
62
+ // Using Symbol.for() ensures the marker survives proxying
63
+ if ((sql )[INSTRUMENTED_MARKER]) {
64
+ return sql;
65
+ }
66
+
67
+ // Wrap the sql function to intercept query creation
68
+ const proxiedSql = new Proxy(sql , {
69
+ apply(target, thisArg, argumentsList) {
70
+ const query = Reflect.apply(target, thisArg, argumentsList);
71
+
72
+ if (query && typeof query === 'object' && 'handle' in query) {
73
+ _wrapSingleQueryHandle(query , proxiedSql, options);
74
+ }
75
+
76
+ return query;
77
+ },
78
+ get(target, prop) {
79
+ const original = (target )[prop];
80
+
81
+ if (typeof prop !== 'string' || typeof original !== 'function') {
82
+ return original;
83
+ }
84
+
85
+ // Wrap methods that return PendingQuery objects (unsafe, file)
86
+ if (prop === 'unsafe' || prop === 'file') {
87
+ return _wrapQueryMethod(original , target, proxiedSql, options);
88
+ }
89
+
90
+ // Wrap begin and reserve (not savepoint to avoid duplicate spans)
91
+ if (prop === 'begin' || prop === 'reserve') {
92
+ return _wrapCallbackMethod(original , target, proxiedSql, options);
93
+ }
94
+
95
+ return original;
96
+ },
97
+ });
98
+
99
+ // Use provided parent context if available, otherwise extract from sql.options
100
+ if (parentConnectionContext) {
101
+ (proxiedSql )[CONNECTION_CONTEXT_SYMBOL] = parentConnectionContext;
102
+ } else {
103
+ _attachConnectionContext(sql, proxiedSql );
104
+ }
105
+
106
+ // Mark both the original and proxy as instrumented to prevent double-wrapping
107
+ (sql )[INSTRUMENTED_MARKER] = true;
108
+ (proxiedSql )[INSTRUMENTED_MARKER] = true;
109
+
110
+ return proxiedSql;
111
+ }
112
+
113
+ /**
114
+ * Wraps query-returning methods (unsafe, file) to ensure their queries are instrumented.
115
+ */
116
+ function _wrapQueryMethod(
117
+ original,
118
+ target,
119
+ proxiedSql,
120
+ options,
121
+ ) {
122
+ return function ( ...args) {
123
+ const query = Reflect.apply(original, target, args);
124
+
125
+ if (query && typeof query === 'object' && 'handle' in query) {
126
+ _wrapSingleQueryHandle(query , proxiedSql, options);
127
+ }
128
+
129
+ return query;
130
+ };
131
+ }
132
+
133
+ /**
134
+ * Wraps callback-based methods (begin, reserve) to recursively instrument Sql instances.
135
+ * Note: These methods can also be used as tagged templates, which we pass through unchanged.
136
+ *
137
+ * Savepoint is not wrapped to avoid complex nested transaction instrumentation issues.
138
+ * Queries within savepoint callbacks are still instrumented through the parent transaction's Sql instance.
139
+ */
140
+ function _wrapCallbackMethod(
141
+ original,
142
+ target,
143
+ parentSqlInstance,
144
+ options,
145
+ ) {
146
+ return function ( ...args) {
147
+ // Extract parent context to propagate to child instances
148
+ const parentContext = (parentSqlInstance )[CONNECTION_CONTEXT_SYMBOL]
149
+
150
+ ;
151
+
152
+ // Check if this is a callback-based call by verifying the last argument is a function
153
+ const isCallbackBased = typeof args[args.length - 1] === 'function';
154
+
155
+ if (!isCallbackBased) {
156
+ // Not a callback-based call - could be tagged template or promise-based
157
+ const result = Reflect.apply(original, target, args);
158
+ // If result is a Promise (e.g., reserve() without callback), instrument the resolved Sql instance
159
+ if (result && typeof (result ).then === 'function') {
160
+ return (result ).then((sqlInstance) => {
161
+ return _instrumentSqlInstance(sqlInstance, options, parentContext);
162
+ });
163
+ }
164
+ return result;
165
+ }
166
+
167
+ // Callback-based call: wrap the callback to instrument the Sql instance
168
+ const callback = (args.length === 1 ? args[0] : args[1]) ;
169
+ const wrappedCallback = function (sqlInstance) {
170
+ const instrumentedSql = _instrumentSqlInstance(sqlInstance, options, parentContext);
171
+ return callback(instrumentedSql);
172
+ };
173
+
174
+ const newArgs = args.length === 1 ? [wrappedCallback] : [args[0], wrappedCallback];
175
+ return Reflect.apply(original, target, newArgs);
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Wraps a single query's handle method to create spans.
181
+ */
182
+ function _wrapSingleQueryHandle(
183
+ query,
184
+ sqlInstance,
185
+ options,
186
+ ) {
187
+ // Prevent double wrapping - check if the handle itself is already wrapped
188
+ if ((query.handle )?.__sentryWrapped) {
189
+ return;
190
+ }
191
+
192
+ // Mark this query as coming from an instrumented sql instance.
193
+ // This prevents the Node.js Query.prototype fallback patch from double-spanning.
194
+ (query )[QUERY_FROM_INSTRUMENTED_SQL] = true;
195
+
196
+ const originalHandle = query.handle ;
197
+
198
+ // IMPORTANT: We must replace the handle function directly, not use a Proxy,
199
+ // because Query.then() internally calls this.handle(), which would bypass a Proxy wrapper.
200
+ const wrappedHandle = async function ( ...args) {
201
+ if (!_shouldCreateSpans(options)) {
202
+ return originalHandle.apply(this, args);
203
+ }
204
+
205
+ const fullQuery = _reconstructQuery(query.strings);
206
+ const sanitizedSqlQuery = _sanitizeSqlQuery(fullQuery);
207
+
208
+ return startSpanManual(
209
+ {
210
+ name: sanitizedSqlQuery || 'postgresjs.query',
211
+ op: 'db',
212
+ },
213
+ (span) => {
214
+ span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.postgresjs');
215
+
216
+ span.setAttributes({
217
+ 'db.system.name': 'postgres',
218
+ 'db.query.text': sanitizedSqlQuery,
219
+ });
220
+
221
+ const connectionContext = sqlInstance
222
+ ? ((sqlInstance )[CONNECTION_CONTEXT_SYMBOL]
223
+
224
+ )
225
+ : undefined;
226
+
227
+ _setConnectionAttributes(span, connectionContext);
228
+
229
+ if (options.requestHook) {
230
+ try {
231
+ options.requestHook(span, sanitizedSqlQuery, connectionContext);
232
+ } catch (e) {
233
+ span.setAttribute('sentry.hook.error', 'requestHook failed');
234
+ DEBUG_BUILD && debug.error('Error in requestHook for PostgresJs instrumentation:', e);
235
+ }
236
+ }
237
+
238
+ const queryWithCallbacks = this
239
+
240
+ ;
241
+
242
+ queryWithCallbacks.resolve = new Proxy(queryWithCallbacks.resolve , {
243
+ apply: (resolveTarget, resolveThisArg, resolveArgs) => {
244
+ try {
245
+ _setOperationName(span, sanitizedSqlQuery, resolveArgs?.[0]?.command);
246
+ span.end();
247
+ } catch (e) {
248
+ DEBUG_BUILD && debug.error('Error ending span in resolve callback:', e);
249
+ }
250
+
251
+ return Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);
252
+ },
253
+ });
254
+
255
+ queryWithCallbacks.reject = new Proxy(queryWithCallbacks.reject , {
256
+ apply: (rejectTarget, rejectThisArg, rejectArgs) => {
257
+ try {
258
+ span.setStatus({
259
+ code: SPAN_STATUS_ERROR,
260
+ message: rejectArgs?.[0]?.message || 'unknown_error',
261
+ });
262
+
263
+ span.setAttribute('db.response.status_code', rejectArgs?.[0]?.code || 'unknown');
264
+ span.setAttribute('error.type', rejectArgs?.[0]?.name || 'unknown');
265
+
266
+ _setOperationName(span, sanitizedSqlQuery);
267
+ span.end();
268
+ } catch (e) {
269
+ DEBUG_BUILD && debug.error('Error ending span in reject callback:', e);
270
+ }
271
+ return Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);
272
+ },
273
+ });
274
+
275
+ // Handle synchronous errors that might occur before promise is created
276
+ try {
277
+ return originalHandle.apply(this, args);
278
+ } catch (e) {
279
+ span.setStatus({
280
+ code: SPAN_STATUS_ERROR,
281
+ message: e instanceof Error ? e.message : 'unknown_error',
282
+ });
283
+ span.end();
284
+ throw e;
285
+ }
286
+ },
287
+ );
288
+ };
289
+
290
+ (wrappedHandle ).__sentryWrapped = true;
291
+ query.handle = wrappedHandle;
292
+ }
293
+
294
+ /**
295
+ * Determines whether a span should be created based on the current context.
296
+ * If `requireParentSpan` is set to true in the options, a span will
297
+ * only be created if there is a parent span available.
298
+ */
299
+ function _shouldCreateSpans(options) {
300
+ const hasParentSpan = getActiveSpan() !== undefined;
301
+ return hasParentSpan || !options.requireParentSpan;
302
+ }
303
+
304
+ /**
305
+ * Reconstructs the full SQL query from template strings with PostgreSQL placeholders.
306
+ *
307
+ * For sql`SELECT * FROM users WHERE id = ${123} AND name = ${'foo'}`:
308
+ * strings = ["SELECT * FROM users WHERE id = ", " AND name = ", ""]
309
+ * returns: "SELECT * FROM users WHERE id = $1 AND name = $2"
310
+ *
311
+ * @internal Exported for testing only
312
+ */
313
+ function _reconstructQuery(strings) {
314
+ if (!strings?.length) {
315
+ return undefined;
316
+ }
317
+ if (strings.length === 1) {
318
+ return strings[0] || undefined;
319
+ }
320
+ // Join template parts with PostgreSQL placeholders ($1, $2, etc.)
321
+ return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');
322
+ }
323
+
324
+ /**
325
+ * Sanitize SQL query as per the OTEL semantic conventions
326
+ * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext
327
+ *
328
+ * PostgreSQL $n placeholders are preserved per OTEL spec - they're parameterized queries,
329
+ * not sensitive literals. Only actual values (strings, numbers, booleans) are sanitized.
330
+ *
331
+ * @internal Exported for testing only
332
+ */
333
+ function _sanitizeSqlQuery(sqlQuery) {
334
+ if (!sqlQuery) {
335
+ return 'Unknown SQL Query';
336
+ }
337
+
338
+ return (
339
+ sqlQuery
340
+ // Remove comments first (they may contain newlines and extra spaces)
341
+ .replace(/--.*$/gm, '') // Single line comments (multiline mode)
342
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Multi-line comments
343
+ .replace(/;\s*$/, '') // Remove trailing semicolons
344
+ // Collapse whitespace to a single space (after removing comments)
345
+ .replace(/\s+/g, ' ')
346
+ .trim() // Remove extra spaces and trim
347
+ // Sanitize hex/binary literals before string literals
348
+ .replace(/\bX'[0-9A-Fa-f]*'/gi, '?') // Hex string literals
349
+ .replace(/\bB'[01]*'/gi, '?') // Binary string literals
350
+ // Sanitize string literals (handles escaped quotes)
351
+ .replace(/'(?:[^']|'')*'/g, '?')
352
+ // Sanitize hex numbers
353
+ .replace(/\b0x[0-9A-Fa-f]+/gi, '?')
354
+ // Sanitize boolean literals
355
+ .replace(/\b(?:TRUE|FALSE)\b/gi, '?')
356
+ // Sanitize numeric literals (preserve $n placeholders via negative lookbehind)
357
+ .replace(/-?\b\d+\.?\d*[eE][+-]?\d+\b/g, '?') // Scientific notation
358
+ .replace(/-?\b\d+\.\d+\b/g, '?') // Decimals
359
+ .replace(/-?\.\d+\b/g, '?') // Decimals starting with dot
360
+ .replace(/(?<!\$)-?\b\d+\b/g, '?') // Integers (NOT $n placeholders)
361
+ // Collapse IN clauses for cardinality (both ? and $n variants)
362
+ .replace(/\bIN\b\s*\(\s*\?(?:\s*,\s*\?)*\s*\)/gi, 'IN (?)')
363
+ .replace(/\bIN\b\s*\(\s*\$\d+(?:\s*,\s*\$\d+)*\s*\)/gi, 'IN ($?)')
364
+ );
365
+ }
366
+
367
+ /**
368
+ * Sets connection context attributes on a span.
369
+ */
370
+ function _setConnectionAttributes(span, connectionContext) {
371
+ if (!connectionContext) {
372
+ return;
373
+ }
374
+ if (connectionContext.ATTR_DB_NAMESPACE) {
375
+ span.setAttribute('db.namespace', connectionContext.ATTR_DB_NAMESPACE);
376
+ }
377
+ if (connectionContext.ATTR_SERVER_ADDRESS) {
378
+ span.setAttribute('server.address', connectionContext.ATTR_SERVER_ADDRESS);
379
+ }
380
+ if (connectionContext.ATTR_SERVER_PORT !== undefined) {
381
+ // Port is stored as string in PostgresConnectionContext for requestHook backwards compatibility,
382
+ // but semantic conventions expect port as a number for span attributes
383
+ const portNumber = parseInt(connectionContext.ATTR_SERVER_PORT, 10);
384
+ if (!isNaN(portNumber)) {
385
+ span.setAttribute('server.port', portNumber);
386
+ }
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Extracts DB operation name from SQL query and sets it on the span.
392
+ */
393
+ function _setOperationName(span, sanitizedQuery, command) {
394
+ if (command) {
395
+ span.setAttribute('db.operation.name', command);
396
+ return;
397
+ }
398
+ // Fallback: extract operation from the SQL query
399
+ const operationMatch = sanitizedQuery?.match(SQL_OPERATION_REGEX);
400
+ if (operationMatch?.[1]) {
401
+ span.setAttribute('db.operation.name', operationMatch[1].toUpperCase());
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Extracts and stores connection context from sql.options.
407
+ */
408
+ function _attachConnectionContext(sql, proxiedSql) {
409
+ const sqlInstance = sql ;
410
+ if (!sqlInstance.options || typeof sqlInstance.options !== 'object') {
411
+ return;
412
+ }
413
+
414
+ const opts = sqlInstance.options;
415
+ // postgres.js stores parsed options with host and port as arrays
416
+ // The library defaults to 'localhost' and 5432 if not specified, but we're defensive here
417
+ const host = opts.host?.[0] || 'localhost';
418
+ const port = opts.port?.[0] || 5432;
419
+
420
+ const connectionContext = {
421
+ ATTR_DB_NAMESPACE: typeof opts.database === 'string' && opts.database !== '' ? opts.database : undefined,
422
+ ATTR_SERVER_ADDRESS: host,
423
+ ATTR_SERVER_PORT: String(port),
424
+ };
425
+
426
+ proxiedSql[CONNECTION_CONTEXT_SYMBOL] = connectionContext;
427
+ }
428
+
429
+ export { _reconstructQuery, _sanitizeSqlQuery, instrumentPostgresJsSql };
430
+ //# sourceMappingURL=postgresjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresjs.js","sources":["../../../src/integrations/postgresjs.ts"],"sourcesContent":["// Portable instrumentation for https://github.com/porsager/postgres\n// This can be used in any environment (Node.js, Cloudflare Workers, etc.)\n// without depending on OpenTelemetry module hooking.\n\nimport { DEBUG_BUILD } from '../debug-build';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes';\nimport { SPAN_STATUS_ERROR, startSpanManual } from '../tracing';\nimport type { Span } from '../types-hoist/span';\nimport { debug } from '../utils/debug-logger';\nimport { getActiveSpan } from '../utils/spanUtils';\n\nconst SQL_OPERATION_REGEX = /^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/i;\n\ntype PostgresConnectionContext = {\n ATTR_DB_NAMESPACE?: string;\n ATTR_SERVER_ADDRESS?: string;\n ATTR_SERVER_PORT?: string;\n};\n\ninterface PostgresJsSqlInstrumentationOptions {\n /**\n * Whether to require a parent span for the instrumentation.\n * If set to true, the instrumentation will only create spans if there is a parent span\n * available in the current scope.\n * @default true\n */\n requireParentSpan?: boolean;\n /**\n * Hook to modify the span before it is started.\n * This can be used to set additional attributes or modify the span in any way.\n */\n requestHook?: (span: Span, sanitizedSqlQuery: string, postgresConnectionContext?: PostgresConnectionContext) => void;\n}\n\nconst CONNECTION_CONTEXT_SYMBOL = Symbol('sentryPostgresConnectionContext');\n\n// Use the same Symbol.for() markers as the Node.js OTel instrumentation\n// so that both approaches recognize each other and prevent double-wrapping.\nconst INSTRUMENTED_MARKER = Symbol.for('sentry.instrumented.postgresjs');\n// Marker to track if a query was created from an instrumented sql instance.\n// This prevents double-spanning when both the wrapper and the Node.js Query.prototype\n// fallback patch are active simultaneously.\nconst QUERY_FROM_INSTRUMENTED_SQL = Symbol.for('sentry.query.from.instrumented.sql');\n\n/**\n * Instruments a postgres.js `sql` instance with Sentry tracing.\n *\n * This is a portable instrumentation function that works in any environment\n * (Node.js, Cloudflare Workers, etc.) without depending on OpenTelemetry.\n *\n * @example\n * ```javascript\n * import postgres from 'postgres';\n * import * as Sentry from '@sentry/cloudflare'; // or '@sentry/deno'\n *\n * const sql = Sentry.instrumentPostgresJsSql(\n * postgres({ host: 'localhost', database: 'mydb' })\n * );\n *\n * // All queries now create Sentry spans\n * await sql`SELECT * FROM users WHERE id = ${userId}`;\n * ```\n */\nexport function instrumentPostgresJsSql<T>(sql: T, options?: PostgresJsSqlInstrumentationOptions): T {\n if (!sql || typeof sql !== 'function') {\n DEBUG_BUILD && debug.warn('instrumentPostgresJsSql: provided value is not a valid postgres.js sql instance');\n return sql;\n }\n\n return _instrumentSqlInstance(sql, { requireParentSpan: true, ...options }) as T;\n}\n\n/**\n * Instruments a sql instance by wrapping its query execution methods.\n */\nfunction _instrumentSqlInstance(\n sql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n parentConnectionContext?: PostgresConnectionContext,\n): unknown {\n // Check if already instrumented to prevent double-wrapping\n // Using Symbol.for() ensures the marker survives proxying\n if ((sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER]) {\n return sql;\n }\n\n // Wrap the sql function to intercept query creation\n const proxiedSql: unknown = new Proxy(sql as (...args: unknown[]) => unknown, {\n apply(target, thisArg, argumentsList: unknown[]) {\n const query = Reflect.apply(target, thisArg, argumentsList);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n },\n get(target, prop) {\n const original = (target as unknown as Record<string | symbol, unknown>)[prop];\n\n if (typeof prop !== 'string' || typeof original !== 'function') {\n return original;\n }\n\n // Wrap methods that return PendingQuery objects (unsafe, file)\n if (prop === 'unsafe' || prop === 'file') {\n return _wrapQueryMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n // Wrap begin and reserve (not savepoint to avoid duplicate spans)\n if (prop === 'begin' || prop === 'reserve') {\n return _wrapCallbackMethod(original as (...args: unknown[]) => unknown, target, proxiedSql, options);\n }\n\n return original;\n },\n });\n\n // Use provided parent context if available, otherwise extract from sql.options\n if (parentConnectionContext) {\n (proxiedSql as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] = parentConnectionContext;\n } else {\n _attachConnectionContext(sql, proxiedSql as Record<symbol, unknown>);\n }\n\n // Mark both the original and proxy as instrumented to prevent double-wrapping\n (sql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n (proxiedSql as Record<symbol, unknown>)[INSTRUMENTED_MARKER] = true;\n\n return proxiedSql;\n}\n\n/**\n * Wraps query-returning methods (unsafe, file) to ensure their queries are instrumented.\n */\nfunction _wrapQueryMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n proxiedSql: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n const query = Reflect.apply(original, target, args);\n\n if (query && typeof query === 'object' && 'handle' in query) {\n _wrapSingleQueryHandle(query as { handle: unknown; strings?: string[] }, proxiedSql, options);\n }\n\n return query;\n };\n}\n\n/**\n * Wraps callback-based methods (begin, reserve) to recursively instrument Sql instances.\n * Note: These methods can also be used as tagged templates, which we pass through unchanged.\n *\n * Savepoint is not wrapped to avoid complex nested transaction instrumentation issues.\n * Queries within savepoint callbacks are still instrumented through the parent transaction's Sql instance.\n */\nfunction _wrapCallbackMethod(\n original: (...args: unknown[]) => unknown,\n target: unknown,\n parentSqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): (...args: unknown[]) => unknown {\n return function (this: unknown, ...args: unknown[]): unknown {\n // Extract parent context to propagate to child instances\n const parentContext = (parentSqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined;\n\n // Check if this is a callback-based call by verifying the last argument is a function\n const isCallbackBased = typeof args[args.length - 1] === 'function';\n\n if (!isCallbackBased) {\n // Not a callback-based call - could be tagged template or promise-based\n const result = Reflect.apply(original, target, args);\n // If result is a Promise (e.g., reserve() without callback), instrument the resolved Sql instance\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).then((sqlInstance: unknown) => {\n return _instrumentSqlInstance(sqlInstance, options, parentContext);\n });\n }\n return result;\n }\n\n // Callback-based call: wrap the callback to instrument the Sql instance\n const callback = (args.length === 1 ? args[0] : args[1]) as (sql: unknown) => unknown;\n const wrappedCallback = function (sqlInstance: unknown): unknown {\n const instrumentedSql = _instrumentSqlInstance(sqlInstance, options, parentContext);\n return callback(instrumentedSql);\n };\n\n const newArgs = args.length === 1 ? [wrappedCallback] : [args[0], wrappedCallback];\n return Reflect.apply(original, target, newArgs);\n };\n}\n\n/**\n * Wraps a single query's handle method to create spans.\n */\nfunction _wrapSingleQueryHandle(\n query: { handle: unknown; strings?: string[]; __sentryWrapped?: boolean },\n sqlInstance: unknown,\n options: PostgresJsSqlInstrumentationOptions,\n): void {\n // Prevent double wrapping - check if the handle itself is already wrapped\n if ((query.handle as { __sentryWrapped?: boolean })?.__sentryWrapped) {\n return;\n }\n\n // Mark this query as coming from an instrumented sql instance.\n // This prevents the Node.js Query.prototype fallback patch from double-spanning.\n (query as Record<symbol, unknown>)[QUERY_FROM_INSTRUMENTED_SQL] = true;\n\n const originalHandle = query.handle as (...args: unknown[]) => Promise<unknown>;\n\n // IMPORTANT: We must replace the handle function directly, not use a Proxy,\n // because Query.then() internally calls this.handle(), which would bypass a Proxy wrapper.\n const wrappedHandle = async function (this: unknown, ...args: unknown[]): Promise<unknown> {\n if (!_shouldCreateSpans(options)) {\n return originalHandle.apply(this, args);\n }\n\n const fullQuery = _reconstructQuery(query.strings);\n const sanitizedSqlQuery = _sanitizeSqlQuery(fullQuery);\n\n return startSpanManual(\n {\n name: sanitizedSqlQuery || 'postgresjs.query',\n op: 'db',\n },\n (span: Span) => {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.postgresjs');\n\n span.setAttributes({\n 'db.system.name': 'postgres',\n 'db.query.text': sanitizedSqlQuery,\n });\n\n const connectionContext = sqlInstance\n ? ((sqlInstance as Record<symbol, unknown>)[CONNECTION_CONTEXT_SYMBOL] as\n | PostgresConnectionContext\n | undefined)\n : undefined;\n\n _setConnectionAttributes(span, connectionContext);\n\n if (options.requestHook) {\n try {\n options.requestHook(span, sanitizedSqlQuery, connectionContext);\n } catch (e) {\n span.setAttribute('sentry.hook.error', 'requestHook failed');\n DEBUG_BUILD && debug.error('Error in requestHook for PostgresJs instrumentation:', e);\n }\n }\n\n const queryWithCallbacks = this as {\n resolve: unknown;\n reject: unknown;\n };\n\n queryWithCallbacks.resolve = new Proxy(queryWithCallbacks.resolve as (...args: unknown[]) => unknown, {\n apply: (resolveTarget, resolveThisArg, resolveArgs: [{ command?: string }]) => {\n try {\n _setOperationName(span, sanitizedSqlQuery, resolveArgs?.[0]?.command);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in resolve callback:', e);\n }\n\n return Reflect.apply(resolveTarget, resolveThisArg, resolveArgs);\n },\n });\n\n queryWithCallbacks.reject = new Proxy(queryWithCallbacks.reject as (...args: unknown[]) => unknown, {\n apply: (rejectTarget, rejectThisArg, rejectArgs: { message?: string; code?: string; name?: string }[]) => {\n try {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: rejectArgs?.[0]?.message || 'unknown_error',\n });\n\n span.setAttribute('db.response.status_code', rejectArgs?.[0]?.code || 'unknown');\n span.setAttribute('error.type', rejectArgs?.[0]?.name || 'unknown');\n\n _setOperationName(span, sanitizedSqlQuery);\n span.end();\n } catch (e) {\n DEBUG_BUILD && debug.error('Error ending span in reject callback:', e);\n }\n return Reflect.apply(rejectTarget, rejectThisArg, rejectArgs);\n },\n });\n\n // Handle synchronous errors that might occur before promise is created\n try {\n return originalHandle.apply(this, args);\n } catch (e) {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: e instanceof Error ? e.message : 'unknown_error',\n });\n span.end();\n throw e;\n }\n },\n );\n };\n\n (wrappedHandle as { __sentryWrapped?: boolean }).__sentryWrapped = true;\n query.handle = wrappedHandle;\n}\n\n/**\n * Determines whether a span should be created based on the current context.\n * If `requireParentSpan` is set to true in the options, a span will\n * only be created if there is a parent span available.\n */\nfunction _shouldCreateSpans(options: PostgresJsSqlInstrumentationOptions): boolean {\n const hasParentSpan = getActiveSpan() !== undefined;\n return hasParentSpan || !options.requireParentSpan;\n}\n\n/**\n * Reconstructs the full SQL query from template strings with PostgreSQL placeholders.\n *\n * For sql`SELECT * FROM users WHERE id = ${123} AND name = ${'foo'}`:\n * strings = [\"SELECT * FROM users WHERE id = \", \" AND name = \", \"\"]\n * returns: \"SELECT * FROM users WHERE id = $1 AND name = $2\"\n *\n * @internal Exported for testing only\n */\nexport function _reconstructQuery(strings: string[] | undefined): string | undefined {\n if (!strings?.length) {\n return undefined;\n }\n if (strings.length === 1) {\n return strings[0] || undefined;\n }\n // Join template parts with PostgreSQL placeholders ($1, $2, etc.)\n return strings.reduce((acc, str, i) => (i === 0 ? str : `${acc}$${i}${str}`), '');\n}\n\n/**\n * Sanitize SQL query as per the OTEL semantic conventions\n * https://opentelemetry.io/docs/specs/semconv/database/database-spans/#sanitization-of-dbquerytext\n *\n * PostgreSQL $n placeholders are preserved per OTEL spec - they're parameterized queries,\n * not sensitive literals. Only actual values (strings, numbers, booleans) are sanitized.\n *\n * @internal Exported for testing only\n */\nexport function _sanitizeSqlQuery(sqlQuery: string | undefined): string {\n if (!sqlQuery) {\n return 'Unknown SQL Query';\n }\n\n return (\n sqlQuery\n // Remove comments first (they may contain newlines and extra spaces)\n .replace(/--.*$/gm, '') // Single line comments (multiline mode)\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Multi-line comments\n .replace(/;\\s*$/, '') // Remove trailing semicolons\n // Collapse whitespace to a single space (after removing comments)\n .replace(/\\s+/g, ' ')\n .trim() // Remove extra spaces and trim\n // Sanitize hex/binary literals before string literals\n .replace(/\\bX'[0-9A-Fa-f]*'/gi, '?') // Hex string literals\n .replace(/\\bB'[01]*'/gi, '?') // Binary string literals\n // Sanitize string literals (handles escaped quotes)\n .replace(/'(?:[^']|'')*'/g, '?')\n // Sanitize hex numbers\n .replace(/\\b0x[0-9A-Fa-f]+/gi, '?')\n // Sanitize boolean literals\n .replace(/\\b(?:TRUE|FALSE)\\b/gi, '?')\n // Sanitize numeric literals (preserve $n placeholders via negative lookbehind)\n .replace(/-?\\b\\d+\\.?\\d*[eE][+-]?\\d+\\b/g, '?') // Scientific notation\n .replace(/-?\\b\\d+\\.\\d+\\b/g, '?') // Decimals\n .replace(/-?\\.\\d+\\b/g, '?') // Decimals starting with dot\n .replace(/(?<!\\$)-?\\b\\d+\\b/g, '?') // Integers (NOT $n placeholders)\n // Collapse IN clauses for cardinality (both ? and $n variants)\n .replace(/\\bIN\\b\\s*\\(\\s*\\?(?:\\s*,\\s*\\?)*\\s*\\)/gi, 'IN (?)')\n .replace(/\\bIN\\b\\s*\\(\\s*\\$\\d+(?:\\s*,\\s*\\$\\d+)*\\s*\\)/gi, 'IN ($?)')\n );\n}\n\n/**\n * Sets connection context attributes on a span.\n */\nfunction _setConnectionAttributes(span: Span, connectionContext: PostgresConnectionContext | undefined): void {\n if (!connectionContext) {\n return;\n }\n if (connectionContext.ATTR_DB_NAMESPACE) {\n span.setAttribute('db.namespace', connectionContext.ATTR_DB_NAMESPACE);\n }\n if (connectionContext.ATTR_SERVER_ADDRESS) {\n span.setAttribute('server.address', connectionContext.ATTR_SERVER_ADDRESS);\n }\n if (connectionContext.ATTR_SERVER_PORT !== undefined) {\n // Port is stored as string in PostgresConnectionContext for requestHook backwards compatibility,\n // but semantic conventions expect port as a number for span attributes\n const portNumber = parseInt(connectionContext.ATTR_SERVER_PORT, 10);\n if (!isNaN(portNumber)) {\n span.setAttribute('server.port', portNumber);\n }\n }\n}\n\n/**\n * Extracts DB operation name from SQL query and sets it on the span.\n */\nfunction _setOperationName(span: Span, sanitizedQuery: string | undefined, command?: string): void {\n if (command) {\n span.setAttribute('db.operation.name', command);\n return;\n }\n // Fallback: extract operation from the SQL query\n const operationMatch = sanitizedQuery?.match(SQL_OPERATION_REGEX);\n if (operationMatch?.[1]) {\n span.setAttribute('db.operation.name', operationMatch[1].toUpperCase());\n }\n}\n\n/**\n * Extracts and stores connection context from sql.options.\n */\nfunction _attachConnectionContext(sql: unknown, proxiedSql: Record<symbol, unknown>): void {\n const sqlInstance = sql as { options?: { host?: string[]; port?: number[]; database?: string } };\n if (!sqlInstance.options || typeof sqlInstance.options !== 'object') {\n return;\n }\n\n const opts = sqlInstance.options;\n // postgres.js stores parsed options with host and port as arrays\n // The library defaults to 'localhost' and 5432 if not specified, but we're defensive here\n const host = opts.host?.[0] || 'localhost';\n const port = opts.port?.[0] || 5432;\n\n const connectionContext: PostgresConnectionContext = {\n ATTR_DB_NAMESPACE: typeof opts.database === 'string' && opts.database !== '' ? opts.database : undefined,\n ATTR_SERVER_ADDRESS: host,\n ATTR_SERVER_PORT: String(port),\n };\n\n proxiedSql[CONNECTION_CONTEXT_SYMBOL] = connectionContext;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"10.41.0-beta.0","sideEffects":false}
1
+ {"type":"module","version":"10.42.0","sideEffects":false}
@@ -5,8 +5,10 @@ import { DEBUG_BUILD } from './debug-build.js';
5
5
  import { registerSpanErrorInstrumentation } from './tracing/errors.js';
6
6
  import { debug } from './utils/debug-logger.js';
7
7
  import { uuid4 } from './utils/misc.js';
8
+ import { DEFAULT_TRANSPORT_BUFFER_SIZE } from './transports/base.js';
8
9
  import { addUserAgentToTransportHeaders } from './transports/userAgent.js';
9
10
  import { eventFromUnknownInput, eventFromMessage } from './utils/eventbuilder.js';
11
+ import { makePromiseBuffer } from './utils/promisebuffer.js';
10
12
  import { resolvedSyncPromise } from './utils/syncpromise.js';
11
13
  import { _getTraceInfoFromScope } from './utils/trace-info.js';
12
14
 
@@ -139,6 +141,32 @@ class ServerRuntimeClient
139
141
  return id;
140
142
  }
141
143
 
144
+ /**
145
+ * Disposes of the client and releases all resources.
146
+ *
147
+ * This method clears all internal state to allow the client to be garbage collected.
148
+ * It clears hooks, event processors, integrations, transport, and other internal references.
149
+ *
150
+ * Call this method after flushing to allow the client to be garbage collected.
151
+ * After calling dispose(), the client should not be used anymore.
152
+ *
153
+ * Subclasses should override this method to clean up their own resources and call `super.dispose()`.
154
+ */
155
+ dispose() {
156
+ DEBUG_BUILD && debug.log('Disposing client...');
157
+
158
+ for (const hookName of Object.keys(this._hooks)) {
159
+ this._hooks[hookName]?.clear();
160
+ }
161
+
162
+ this._hooks = {};
163
+ this._eventProcessors.length = 0;
164
+ this._integrations = {};
165
+ this._outcomes = {};
166
+ (this )._transport = undefined;
167
+ this._promiseBuffer = makePromiseBuffer(DEFAULT_TRANSPORT_BUFFER_SIZE);
168
+ }
169
+
142
170
  /**
143
171
  * @inheritDoc
144
172
  */