@sentry/cloudflare 10.47.0 → 10.49.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/build/cjs/client.js.map +1 -1
- package/build/cjs/durableobject.js +42 -16
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/index.js +3 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrument.js +72 -8
- package/build/cjs/instrument.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js +56 -0
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js.map +1 -0
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +38 -3
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js +101 -0
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentEmail.js +16 -13
- package/build/cjs/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEnv.js +83 -0
- package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentFetch.js +36 -10
- package/build/cjs/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentFetcher.js +38 -0
- package/build/cjs/instrumentations/worker/instrumentFetcher.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentQueue.js +36 -10
- package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentScheduled.js +36 -13
- package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentTail.js +34 -10
- package/build/cjs/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/cjs/integrations/tracing/vercelai.js +2 -1
- package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/request.js +5 -6
- package/build/cjs/request.js.map +1 -1
- package/build/cjs/scope-utils.js.map +1 -1
- package/build/cjs/sdk.js +6 -1
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/utils/instrumentContext.js +2 -1
- package/build/cjs/utils/instrumentContext.js.map +1 -1
- package/build/cjs/utils/isBinding.js +32 -0
- package/build/cjs/utils/isBinding.js.map +1 -0
- package/build/cjs/utils/isCloudflareClass.js +29 -0
- package/build/cjs/utils/isCloudflareClass.js.map +1 -0
- package/build/cjs/utils/rpcOptions.js +84 -0
- package/build/cjs/utils/rpcOptions.js.map +1 -0
- package/build/cjs/utils/traceLinks.js +78 -0
- package/build/cjs/utils/traceLinks.js.map +1 -0
- package/build/cjs/withSentry.js +31 -20
- package/build/cjs/withSentry.js.map +1 -1
- package/build/cjs/workflows.js +3 -2
- package/build/cjs/workflows.js.map +1 -1
- package/build/cjs/wrapMethodWithSentry.js +157 -112
- package/build/cjs/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/durableobject.js +43 -17
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/instrument.js +71 -8
- package/build/esm/instrument.js.map +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js +54 -0
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js.map +1 -0
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js +39 -4
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js +99 -0
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentEmail.js +17 -14
- package/build/esm/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEnv.js +81 -0
- package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentFetch.js +37 -12
- package/build/esm/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentFetcher.js +36 -0
- package/build/esm/instrumentations/worker/instrumentFetcher.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentQueue.js +37 -12
- package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentScheduled.js +37 -15
- package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentTail.js +35 -12
- package/build/esm/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/esm/integrations/tracing/vercelai.js +2 -1
- package/build/esm/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/request.js +5 -6
- package/build/esm/request.js.map +1 -1
- package/build/esm/scope-utils.js.map +1 -1
- package/build/esm/sdk.js +7 -2
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/utils/instrumentContext.js +2 -1
- package/build/esm/utils/instrumentContext.js.map +1 -1
- package/build/esm/utils/isBinding.js +29 -0
- package/build/esm/utils/isBinding.js.map +1 -0
- package/build/esm/utils/isCloudflareClass.js +27 -0
- package/build/esm/utils/isCloudflareClass.js.map +1 -0
- package/build/esm/utils/rpcOptions.js +81 -0
- package/build/esm/utils/rpcOptions.js.map +1 -0
- package/build/esm/utils/traceLinks.js +73 -0
- package/build/esm/utils/traceLinks.js.map +1 -0
- package/build/esm/withSentry.js +32 -21
- package/build/esm/withSentry.js.map +1 -1
- package/build/esm/workflows.js +3 -2
- package/build/esm/workflows.js.map +1 -1
- package/build/esm/wrapMethodWithSentry.js +159 -114
- package/build/esm/wrapMethodWithSentry.js.map +1 -1
- package/build/types/client.d.ts +39 -10
- package/build/types/client.d.ts.map +1 -1
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrument.d.ts +15 -4
- package/build/types/instrument.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts +12 -0
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts.map +1 -0
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts +8 -1
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts +42 -0
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentEmail.d.ts +2 -1
- package/build/types/instrumentations/worker/instrumentEmail.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEnv.d.ts +16 -0
- package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentFetch.d.ts +6 -1
- package/build/types/instrumentations/worker/instrumentFetch.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentFetcher.d.ts +10 -0
- package/build/types/instrumentations/worker/instrumentFetcher.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentQueue.d.ts +6 -1
- package/build/types/instrumentations/worker/instrumentQueue.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts +6 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentTail.d.ts +6 -1
- package/build/types/instrumentations/worker/instrumentTail.d.ts.map +1 -1
- package/build/types/integrations/tracing/vercelai.d.ts +9 -1
- package/build/types/integrations/tracing/vercelai.d.ts.map +1 -1
- package/build/types/request.d.ts +3 -3
- package/build/types/request.d.ts.map +1 -1
- package/build/types/scope-utils.d.ts +2 -2
- package/build/types/scope-utils.d.ts.map +1 -1
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types/utils/instrumentContext.d.ts.map +1 -1
- package/build/types/utils/isBinding.d.ts +49 -0
- package/build/types/utils/isBinding.d.ts.map +1 -0
- package/build/types/utils/isCloudflareClass.d.ts +30 -0
- package/build/types/utils/isCloudflareClass.d.ts.map +1 -0
- package/build/types/utils/rpcOptions.d.ts +24 -0
- package/build/types/utils/rpcOptions.d.ts.map +1 -0
- package/build/types/utils/traceLinks.d.ts +27 -0
- package/build/types/utils/traceLinks.d.ts.map +1 -0
- package/build/types/withSentry.d.ts +3 -2
- package/build/types/withSentry.d.ts.map +1 -1
- package/build/types/workflows.d.ts.map +1 -1
- package/build/types/wrapMethodWithSentry.d.ts +19 -2
- package/build/types/wrapMethodWithSentry.d.ts.map +1 -1
- package/build/types-ts3.8/client.d.ts +39 -10
- package/build/types-ts3.8/index.d.ts +1 -1
- package/build/types-ts3.8/instrument.d.ts +15 -4
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectNamespace.d.ts +12 -0
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectStorage.d.ts +8 -1
- package/build/types-ts3.8/instrumentations/instrumentWorkerEntrypoint.d.ts +42 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentEmail.d.ts +2 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentEnv.d.ts +16 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentFetch.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentFetcher.d.ts +10 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentQueue.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentScheduled.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentTail.d.ts +6 -1
- package/build/types-ts3.8/integrations/tracing/vercelai.d.ts +9 -1
- package/build/types-ts3.8/request.d.ts +3 -3
- package/build/types-ts3.8/scope-utils.d.ts +2 -2
- package/build/types-ts3.8/utils/isBinding.d.ts +49 -0
- package/build/types-ts3.8/utils/isCloudflareClass.d.ts +30 -0
- package/build/types-ts3.8/utils/rpcOptions.d.ts +24 -0
- package/build/types-ts3.8/utils/traceLinks.d.ts +27 -0
- package/build/types-ts3.8/withSentry.d.ts +3 -2
- package/build/types-ts3.8/wrapMethodWithSentry.d.ts +19 -2
- package/package.json +2 -2
package/build/cjs/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n\n // Track span lifecycle to know when to flush\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n * If a timeout is provided, the operation will be completed within the specified time limit.\n *\n * It will wait for all pending spans to complete before flushing.\n *\n * @param {number} [timeout] - Optional timeout in milliseconds to force the completion of the flush operation.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n if (this._flushLock) {\n await this._flushLock.finalize();\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n return super.flush(timeout);\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * This feature adds runtime overhead as it wraps methods at the prototype level.\n * Only enable this if you need automatic instrumentation of prototype methods.\n *\n * @default false\n * @example\n * ```ts\n * // Instrument all prototype methods\n * instrumentPrototypeMethods: true\n *\n * // Instrument only specific methods\n * instrumentPrototypeMethods: ['myMethod', 'anotherMethod']\n * ```\n */\n instrumentPrototypeMethods?: boolean | string[];\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContext;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":["ServerRuntimeClient","applySdkMetadata","DEBUG_BUILD","debug"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n\n // Track span lifecycle to know when to flush\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n * If a timeout is provided, the operation will be completed within the specified time limit.\n *\n * It will wait for all pending spans to complete before flushing.\n *\n * @param {number} [timeout] - Optional timeout in milliseconds to force the completion of the flush operation.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n if (this._flushLock) {\n await this._flushLock.finalize();\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n return super.flush(timeout);\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable trace propagation for RPC calls between Workers, Durable Objects, and Service Bindings.\n *\n * When enabled, trace context (sentry-trace + baggage) is propagated across:\n * - `stub.fetch()` calls to Durable Objects (via HTTP headers)\n * - Service binding `fetch()` calls (via HTTP headers)\n * - RPC method calls to Durable Objects (via trailing argument)\n *\n * When enabled on the **receiver side** (DurableObject), the SDK will also:\n * - Extract and continue traces from incoming RPC calls\n * - Create spans for each RPC method invocation\n * - Capture errors thrown by RPC methods\n *\n * **Important:** This option should be enabled on **both sides** for full trace propagation.\n *\n * @default false\n * @example\n * ```ts\n * // Worker side (caller)\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * handler,\n * );\n *\n * // Durable Object side (receiver)\n * export const MyDO = Sentry.instrumentDurableObjectWithSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * MyDOBase,\n * );\n * ```\n */\n enableRpcTracePropagation?: boolean;\n\n /**\n * @deprecated Use `enableRpcTracePropagation` instead. This option will be removed in a future major version.\n *\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * @default false\n */\n instrumentPrototypeMethods?: boolean | string[];\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContext;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":["ServerRuntimeClient","applySdkMetadata","DEBUG_BUILD","debug"],"mappings":"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"}
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
const async = require('./async.js');
|
|
5
5
|
const instrument = require('./instrument.js');
|
|
6
|
+
const instrumentEnv = require('./instrumentations/worker/instrumentEnv.js');
|
|
6
7
|
const options = require('./options.js');
|
|
7
8
|
const request = require('./request.js');
|
|
8
9
|
const instrumentContext = require('./utils/instrumentContext.js');
|
|
10
|
+
const rpcOptions = require('./utils/rpcOptions.js');
|
|
9
11
|
const wrapMethodWithSentry = require('./wrapMethodWithSentry.js');
|
|
10
12
|
|
|
11
13
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
@@ -50,10 +52,10 @@ function instrumentDurableObjectWithSentry
|
|
|
50
52
|
construct(target, [ctx, env]) {
|
|
51
53
|
async.setAsyncLocalStorageAsyncContextStrategy();
|
|
52
54
|
const context = instrumentContext.instrumentContext(ctx);
|
|
53
|
-
|
|
54
55
|
const options$1 = options.getFinalOptions(optionsCallback(env), env);
|
|
56
|
+
const instrumentedEnv = instrumentEnv.instrumentEnv(env, options$1);
|
|
55
57
|
|
|
56
|
-
const obj = new target(context,
|
|
58
|
+
const obj = new target(context, instrumentedEnv);
|
|
57
59
|
|
|
58
60
|
// These are the methods that are available on a Durable Object
|
|
59
61
|
// ref: https://developers.cloudflare.com/durable-objects/api/base/
|
|
@@ -65,20 +67,26 @@ function instrumentDurableObjectWithSentry
|
|
|
65
67
|
|
|
66
68
|
// Any other public methods on the Durable Object instance are RPC calls.
|
|
67
69
|
|
|
68
|
-
if (obj.fetch && typeof obj.fetch === 'function'
|
|
69
|
-
obj.fetch =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
if (obj.fetch && typeof obj.fetch === 'function') {
|
|
71
|
+
obj.fetch = instrument.ensureInstrumented(
|
|
72
|
+
obj.fetch,
|
|
73
|
+
original =>
|
|
74
|
+
new Proxy(original, {
|
|
75
|
+
apply(target, thisArg, args) {
|
|
76
|
+
return request.wrapRequestHandler({ options: options$1, request: args[0], context }, () => {
|
|
77
|
+
return Reflect.apply(target, thisArg, args);
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
if (obj.alarm && typeof obj.alarm === 'function') {
|
|
81
|
-
|
|
85
|
+
// Alarms are independent invocations, so we start a new trace and link to the previous alarm
|
|
86
|
+
obj.alarm = wrapMethodWithSentry.wrapMethodWithSentry(
|
|
87
|
+
{ options: options$1, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },
|
|
88
|
+
obj.alarm,
|
|
89
|
+
);
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {
|
|
@@ -143,8 +151,10 @@ function instrumentDurableObjectWithSentry
|
|
|
143
151
|
configurable: false,
|
|
144
152
|
});
|
|
145
153
|
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
const methodFilter = rpcOptions.getPrototypeMethodFilter(options$1);
|
|
155
|
+
|
|
156
|
+
if (methodFilter) {
|
|
157
|
+
instrumentPrototype(target, methodFilter);
|
|
148
158
|
}
|
|
149
159
|
|
|
150
160
|
return obj;
|
|
@@ -175,7 +185,18 @@ function instrumentPrototype(target, methodsToInstrument) {
|
|
|
175
185
|
methodNames.forEach(methodName => {
|
|
176
186
|
const originalMethod = (proto )[methodName];
|
|
177
187
|
|
|
178
|
-
if (!originalMethod
|
|
188
|
+
if (!originalMethod) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const existingInstrumented = instrument.getInstrumented(originalMethod);
|
|
193
|
+
if (existingInstrumented) {
|
|
194
|
+
Object.defineProperty(proto, methodName, {
|
|
195
|
+
value: existingInstrumented,
|
|
196
|
+
enumerable: false,
|
|
197
|
+
writable: true,
|
|
198
|
+
configurable: true,
|
|
199
|
+
});
|
|
179
200
|
return;
|
|
180
201
|
}
|
|
181
202
|
|
|
@@ -213,6 +234,11 @@ function instrumentPrototype(target, methodsToInstrument) {
|
|
|
213
234
|
return wrapper.apply(this, args);
|
|
214
235
|
};
|
|
215
236
|
|
|
237
|
+
// Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).
|
|
238
|
+
// originalMethod must stay unmapped because wrappedMethod calls
|
|
239
|
+
// wrapMethodWithSentry(options, originalMethod) on each invocation to create
|
|
240
|
+
// a per-instance proxy. If originalMethod mapped to wrappedMethod, that call
|
|
241
|
+
// would return wrappedMethod itself, causing infinite recursion.
|
|
216
242
|
instrument.markAsInstrumented(wrappedMethod);
|
|
217
243
|
|
|
218
244
|
// Replace the prototype method
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { isInstrumented, markAsInstrumented } from './instrument';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport type { UncheckedMethod } from './wrapMethodWithSentry';\nimport { wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * as well as any other public RPC methods on the Durable Object instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env]) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n const obj = new target(context, env);\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function' && !isInstrumented(obj.fetch)) {\n obj.fetch = new Proxy(obj.fetch, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () =>\n Reflect.apply(target, thisArg, args),\n );\n },\n });\n\n markAsInstrumented(obj.fetch);\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n obj.alarm = wrapMethodWithSentry({ options, context, spanName: 'alarm' }, obj.alarm);\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n for (const method of Object.getOwnPropertyNames(obj)) {\n if (\n method === 'fetch' ||\n method === 'alarm' ||\n method === 'webSocketError' ||\n method === 'webSocketClose' ||\n method === 'webSocketMessage'\n ) {\n continue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n const value = (obj as any)[method] as unknown;\n if (typeof value === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n (obj as any)[method] = wrapMethodWithSentry(\n { options, context, spanName: method, spanOp: 'rpc' },\n value as UncheckedMethod,\n );\n }\n }\n\n // Store context and options on the instance for prototype methods to access\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n if (options?.instrumentPrototypeMethods) {\n instrumentPrototype(target, options.instrumentPrototypeMethods);\n }\n\n return obj;\n },\n });\n}\n\nfunction instrumentPrototype<T extends NewableFunction>(target: T, methodsToInstrument: boolean | string[]): void {\n const proto = target.prototype;\n\n // Get all methods from the prototype chain\n const methodNames = new Set<string>();\n let current = proto;\n\n while (current && current !== Object.prototype) {\n Object.getOwnPropertyNames(current).forEach(name => {\n if (name !== 'constructor' && typeof (current as Record<string, unknown>)[name] === 'function') {\n methodNames.add(name);\n }\n });\n current = Object.getPrototypeOf(current);\n }\n\n // Create a set for efficient lookups when methodsToInstrument is an array\n const methodsToInstrumentSet = Array.isArray(methodsToInstrument) ? new Set(methodsToInstrument) : null;\n\n // Instrument each method on the prototype\n methodNames.forEach(methodName => {\n const originalMethod = (proto as Record<string, unknown>)[methodName];\n\n if (!originalMethod || isInstrumented(originalMethod)) {\n return;\n }\n\n // If methodsToInstrument is an array, only instrument methods in that set\n if (methodsToInstrumentSet && !methodsToInstrumentSet.has(methodName)) {\n return;\n }\n\n // Create a wrapper that gets context/options from the instance at runtime\n const wrappedMethod = function (this: unknown, ...args: unknown[]): unknown {\n const thisWithSentry = this as {\n __SENTRY_CONTEXT__: DurableObjectState;\n __SENTRY_OPTIONS__: CloudflareOptions;\n };\n const instanceContext = thisWithSentry.__SENTRY_CONTEXT__;\n const instanceOptions = thisWithSentry.__SENTRY_OPTIONS__;\n\n if (!instanceOptions) {\n // Fallback to original method if no Sentry data found\n return (originalMethod as UncheckedMethod).apply(this, args);\n }\n\n // Use the existing wrapper but with instance-specific context/options\n const wrapper = wrapMethodWithSentry(\n {\n options: instanceOptions,\n context: instanceContext,\n spanName: methodName,\n spanOp: 'rpc',\n },\n originalMethod as UncheckedMethod,\n undefined,\n true, // noMark = true since we'll mark the prototype method\n );\n\n return wrapper.apply(this, args);\n };\n\n markAsInstrumented(wrappedMethod);\n\n // Replace the prototype method\n Object.defineProperty(proto, methodName, {\n value: wrappedMethod,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n });\n}\n"],"names":["setAsyncLocalStorageAsyncContextStrategy","instrumentContext","options","getFinalOptions","isInstrumented","wrapRequestHandler","markAsInstrumented","wrapMethodWithSentry","captureException"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented, getInstrumented, markAsInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { getPrototypeMethodFilter } from './utils/rpcOptions';\nimport type { UncheckedMethod } from './wrapMethodWithSentry';\nimport { wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * as well as any other public RPC methods on the Durable Object instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env]) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n\n const obj = new target(context, instrumentedEnv);\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function') {\n obj.fetch = ensureInstrumented(\n obj.fetch,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () => {\n return Reflect.apply(target, thisArg, args);\n });\n },\n }),\n );\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n // Alarms are independent invocations, so we start a new trace and link to the previous alarm\n obj.alarm = wrapMethodWithSentry(\n { options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },\n obj.alarm,\n );\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n for (const method of Object.getOwnPropertyNames(obj)) {\n if (\n method === 'fetch' ||\n method === 'alarm' ||\n method === 'webSocketError' ||\n method === 'webSocketClose' ||\n method === 'webSocketMessage'\n ) {\n continue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n const value = (obj as any)[method] as unknown;\n if (typeof value === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n (obj as any)[method] = wrapMethodWithSentry(\n { options, context, spanName: method, spanOp: 'rpc' },\n value as UncheckedMethod,\n );\n }\n }\n\n // Store context and options on the instance for prototype methods to access\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n const methodFilter = getPrototypeMethodFilter(options);\n\n if (methodFilter) {\n instrumentPrototype(target, methodFilter);\n }\n\n return obj;\n },\n });\n}\n\nfunction instrumentPrototype<T extends NewableFunction>(target: T, methodsToInstrument: boolean | string[]): void {\n const proto = target.prototype;\n\n // Get all methods from the prototype chain\n const methodNames = new Set<string>();\n let current = proto;\n\n while (current && current !== Object.prototype) {\n Object.getOwnPropertyNames(current).forEach(name => {\n if (name !== 'constructor' && typeof (current as Record<string, unknown>)[name] === 'function') {\n methodNames.add(name);\n }\n });\n current = Object.getPrototypeOf(current);\n }\n\n // Create a set for efficient lookups when methodsToInstrument is an array\n const methodsToInstrumentSet = Array.isArray(methodsToInstrument) ? new Set(methodsToInstrument) : null;\n\n // Instrument each method on the prototype\n methodNames.forEach(methodName => {\n const originalMethod = (proto as Record<string, unknown>)[methodName];\n\n if (!originalMethod) {\n return;\n }\n\n const existingInstrumented = getInstrumented(originalMethod);\n if (existingInstrumented) {\n Object.defineProperty(proto, methodName, {\n value: existingInstrumented,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n return;\n }\n\n // If methodsToInstrument is an array, only instrument methods in that set\n if (methodsToInstrumentSet && !methodsToInstrumentSet.has(methodName)) {\n return;\n }\n\n // Create a wrapper that gets context/options from the instance at runtime\n const wrappedMethod = function (this: unknown, ...args: unknown[]): unknown {\n const thisWithSentry = this as {\n __SENTRY_CONTEXT__: DurableObjectState;\n __SENTRY_OPTIONS__: CloudflareOptions;\n };\n const instanceContext = thisWithSentry.__SENTRY_CONTEXT__;\n const instanceOptions = thisWithSentry.__SENTRY_OPTIONS__;\n\n if (!instanceOptions) {\n // Fallback to original method if no Sentry data found\n return (originalMethod as UncheckedMethod).apply(this, args);\n }\n\n // Use the existing wrapper but with instance-specific context/options\n const wrapper = wrapMethodWithSentry(\n {\n options: instanceOptions,\n context: instanceContext,\n spanName: methodName,\n spanOp: 'rpc',\n },\n originalMethod as UncheckedMethod,\n undefined,\n true, // noMark = true since we'll mark the prototype method\n );\n\n return wrapper.apply(this, args);\n };\n\n // Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).\n // originalMethod must stay unmapped because wrappedMethod calls\n // wrapMethodWithSentry(options, originalMethod) on each invocation to create\n // a per-instance proxy. If originalMethod mapped to wrappedMethod, that call\n // would return wrappedMethod itself, causing infinite recursion.\n markAsInstrumented(wrappedMethod);\n\n // Replace the prototype method\n Object.defineProperty(proto, methodName, {\n value: wrappedMethod,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n });\n}\n"],"names":["setAsyncLocalStorageAsyncContextStrategy","instrumentContext","options","getFinalOptions","instrumentEnv","ensureInstrumented","wrapRequestHandler","wrapMethodWithSentry","captureException","getPrototypeMethodFilter","getInstrumented","markAsInstrumented"],"mappings":"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"}
|
package/build/cjs/index.js
CHANGED
|
@@ -58,6 +58,7 @@ exports.growthbookIntegration = core.growthbookIntegration;
|
|
|
58
58
|
exports.inboundFiltersIntegration = core.inboundFiltersIntegration;
|
|
59
59
|
exports.instrumentAnthropicAiClient = core.instrumentAnthropicAiClient;
|
|
60
60
|
exports.instrumentGoogleGenAIClient = core.instrumentGoogleGenAIClient;
|
|
61
|
+
exports.instrumentLangChainEmbeddings = core.instrumentLangChainEmbeddings;
|
|
61
62
|
exports.instrumentLangGraph = core.instrumentLangGraph;
|
|
62
63
|
exports.instrumentOpenAiClient = core.instrumentOpenAiClient;
|
|
63
64
|
exports.instrumentPostgresJsSql = core.instrumentPostgresJsSql;
|
|
@@ -81,6 +82,7 @@ exports.setMeasurement = core.setMeasurement;
|
|
|
81
82
|
exports.setTag = core.setTag;
|
|
82
83
|
exports.setTags = core.setTags;
|
|
83
84
|
exports.setUser = core.setUser;
|
|
85
|
+
exports.spanStreamingIntegration = core.spanStreamingIntegration;
|
|
84
86
|
exports.spanToBaggageHeader = core.spanToBaggageHeader;
|
|
85
87
|
exports.spanToJSON = core.spanToJSON;
|
|
86
88
|
exports.spanToTraceHeader = core.spanToTraceHeader;
|
|
@@ -96,6 +98,7 @@ exports.withActiveSpan = core.withActiveSpan;
|
|
|
96
98
|
exports.withIsolationScope = core.withIsolationScope;
|
|
97
99
|
exports.withMonitor = core.withMonitor;
|
|
98
100
|
exports.withScope = core.withScope;
|
|
101
|
+
exports.withStreamedSpan = core.withStreamedSpan;
|
|
99
102
|
exports.wrapMcpServerWithSentry = core.wrapMcpServerWithSentry;
|
|
100
103
|
exports.zodErrorsIntegration = core.zodErrorsIntegration;
|
|
101
104
|
exports.withSentry = withSentry.withSentry;
|
package/build/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/build/cjs/instrument.js
CHANGED
|
@@ -1,27 +1,91 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
|
+
// Use a global WeakMap to track instrumented objects across module instances.
|
|
4
|
+
// This is important for Cloudflare Workers where the module may be bundled
|
|
5
|
+
// separately for workers and Durable Objects, but they share the same global scope.
|
|
6
|
+
// The WeakMap stores original -> instrumented mappings so we can retrieve the
|
|
7
|
+
// instrumented version even if we only have a reference to the original.
|
|
8
|
+
const GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' ;
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
function getInstrumentedMap() {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
const globalObj = globalThis ;
|
|
14
|
+
if (!globalObj[GLOBAL_KEY]) {
|
|
15
|
+
globalObj[GLOBAL_KEY] = new WeakMap();
|
|
16
|
+
}
|
|
17
|
+
return globalObj[GLOBAL_KEY];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if a value can be used as a WeakMap key.
|
|
22
|
+
* WeakMap keys must be objects or non-registered symbols.
|
|
23
|
+
*/
|
|
24
|
+
function isWeakMapKey(value) {
|
|
25
|
+
return (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
/**
|
|
4
|
-
* Mark an object as instrumented.
|
|
29
|
+
* Mark an object as instrumented, storing the instrumented version.
|
|
30
|
+
* @param original The original uninstrumented object
|
|
31
|
+
* @param instrumented The instrumented version (defaults to original if not provided)
|
|
5
32
|
*/
|
|
6
|
-
function markAsInstrumented(
|
|
33
|
+
function markAsInstrumented(original, instrumented) {
|
|
7
34
|
try {
|
|
8
|
-
(
|
|
35
|
+
if (isWeakMapKey(original)) {
|
|
36
|
+
// Store mapping from original to instrumented version
|
|
37
|
+
// If instrumented is not provided, store original (for backwards compat)
|
|
38
|
+
getInstrumentedMap().set(original, instrumented ?? original);
|
|
39
|
+
}
|
|
40
|
+
// Also mark the instrumented version itself so we recognize it
|
|
41
|
+
if (isWeakMapKey(instrumented) && instrumented !== original) {
|
|
42
|
+
getInstrumentedMap().set(instrumented, instrumented);
|
|
43
|
+
}
|
|
9
44
|
} catch {
|
|
10
45
|
// ignore errors here
|
|
11
46
|
}
|
|
12
47
|
}
|
|
13
48
|
|
|
14
49
|
/**
|
|
15
|
-
*
|
|
50
|
+
* Get the instrumented version of an object, if available.
|
|
51
|
+
* Returns the instrumented version if the object was previously instrumented,
|
|
52
|
+
* or undefined if not found.
|
|
16
53
|
*/
|
|
17
|
-
function
|
|
54
|
+
function getInstrumented(obj) {
|
|
18
55
|
try {
|
|
19
|
-
|
|
56
|
+
if (isWeakMapKey(obj)) {
|
|
57
|
+
return getInstrumentedMap().get(obj) ;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return undefined;
|
|
20
61
|
} catch {
|
|
21
|
-
return
|
|
62
|
+
return undefined;
|
|
22
63
|
}
|
|
23
64
|
}
|
|
24
65
|
|
|
25
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Returns the already-instrumented version of `original` if one exists,
|
|
68
|
+
* otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.
|
|
69
|
+
*
|
|
70
|
+
* @param noMark - If true, skips storing the original→instrumented mapping.
|
|
71
|
+
*/
|
|
72
|
+
function ensureInstrumented(original, instrumentFn, noMark) {
|
|
73
|
+
const existing = getInstrumented(original);
|
|
74
|
+
|
|
75
|
+
if (existing) {
|
|
76
|
+
return existing;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const instrumented = instrumentFn(original);
|
|
80
|
+
|
|
81
|
+
if (!noMark) {
|
|
82
|
+
markAsInstrumented(original, instrumented);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return instrumented;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
exports.ensureInstrumented = ensureInstrumented;
|
|
89
|
+
exports.getInstrumented = getInstrumented;
|
|
26
90
|
exports.markAsInstrumented = markAsInstrumented;
|
|
27
91
|
//# sourceMappingURL=instrument.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return (typeof value === 'object' && value !== null) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA,MAAM,UAAA,GAAa,6BAAA;;AAEnB;AACA,SAAS,kBAAkB,GAAsB;AACjD;AACA,EAAE,MAAM,SAAA,GAAY,UAAA;AACpB,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;AAC9B,IAAI,SAAS,CAAC,UAAU,CAAA,GAAI,IAAI,OAAO,EAAE;AACzC,EAAE;AACF,EAAE,OAAO,SAAS,CAAC,UAAU,CAAC;AAC9B;;AAEA;AACA;AACA;AACA;AACA,SAAS,YAAY,CAAC,KAAK,EAA4B;AACvD,EAAE,OAAO,CAAC,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAI,KAAK,OAAO,KAAA,KAAU,UAAU;AACrF;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAI,QAAQ,EAAK,YAAY,EAAY;AAC3E,EAAE,IAAI;AACN,IAAI,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE;AAChC;AACA;AACA,MAAM,kBAAkB,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAA,IAAgB,QAAQ,CAAC;AAClE,IAAI;AACJ;AACA,IAAI,IAAI,YAAY,CAAC,YAAY,KAAK,YAAA,KAAiB,QAAQ,EAAE;AACjE,MAAM,kBAAkB,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;AAC1D,IAAI;AACJ,EAAE,EAAE,MAAM;AACV;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAI,GAAG,EAAoB;AAC1D,EAAE,IAAI;AACN,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE;AAC3B,MAAM,OAAO,kBAAkB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;AACzC,IAAI;;AAEJ,IAAI,OAAO,SAAS;AACpB,EAAE,EAAE,MAAM;AACV,IAAI,OAAO,SAAS;AACpB,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAI,QAAQ,EAAK,YAAY,EAAsB,MAAM,EAAe;AAC1G,EAAE,MAAM,QAAA,GAAW,eAAe,CAAC,QAAQ,CAAC;;AAE5C,EAAE,IAAI,QAAQ,EAAE;AAChB,IAAI,OAAO,QAAQ;AACnB,EAAE;;AAEF,EAAE,MAAM,YAAA,GAAe,YAAY,CAAC,QAAQ,CAAC;;AAE7C,EAAE,IAAI,CAAC,MAAM,EAAE;AACf,IAAI,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC;AAC9C,EAAE;;AAEF,EAAE,OAAO,YAAY;AACrB;;;;;;"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const instrumentFetcher = require('./worker/instrumentFetcher.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Instruments a DurableObjectNamespace binding to create spans for DO interactions.
|
|
7
|
+
*
|
|
8
|
+
* Wraps:
|
|
9
|
+
* - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub
|
|
10
|
+
* - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs
|
|
11
|
+
*
|
|
12
|
+
* @param namespace - The DurableObjectNamespace to instrument
|
|
13
|
+
*/
|
|
14
|
+
function instrumentDurableObjectNamespace(namespace) {
|
|
15
|
+
return new Proxy(namespace, {
|
|
16
|
+
get(target, prop, _receiver) {
|
|
17
|
+
const value = Reflect.get(target, prop) ;
|
|
18
|
+
|
|
19
|
+
if (typeof value !== 'function') {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (prop === 'get' || prop === 'getByName') {
|
|
24
|
+
return function ( ...args) {
|
|
25
|
+
const stub = Reflect.apply(value, target, args);
|
|
26
|
+
|
|
27
|
+
return instrumentDurableObjectStub(stub);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return value.bind(target);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Instruments a DurableObjectStub to propagate trace context across fetch calls.
|
|
38
|
+
*
|
|
39
|
+
* @param stub - The DurableObjectStub to instrument
|
|
40
|
+
*/
|
|
41
|
+
function instrumentDurableObjectStub(stub) {
|
|
42
|
+
return new Proxy(stub, {
|
|
43
|
+
get(target, prop, receiver) {
|
|
44
|
+
const value = Reflect.get(target, prop, receiver);
|
|
45
|
+
|
|
46
|
+
if (prop === 'fetch' && typeof value === 'function') {
|
|
47
|
+
return instrumentFetcher.instrumentFetcher((input, init) => Reflect.apply(value, target, [input, init]));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return value;
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
exports.instrumentDurableObjectNamespace = instrumentDurableObjectNamespace;
|
|
56
|
+
//# sourceMappingURL=instrumentDurableObjectNamespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectNamespace.js","sources":["../../../src/instrumentations/instrumentDurableObjectNamespace.ts"],"sourcesContent":["import type { DurableObjectNamespace, DurableObjectStub } from '@cloudflare/workers-types';\nimport { instrumentFetcher } from './worker/instrumentFetcher';\n\n/**\n * Instruments a DurableObjectNamespace binding to create spans for DO interactions.\n *\n * Wraps:\n * - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub\n * - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs\n *\n * @param namespace - The DurableObjectNamespace to instrument\n */\nexport function instrumentDurableObjectNamespace(namespace: DurableObjectNamespace): DurableObjectNamespace {\n return new Proxy(namespace, {\n get(target, prop, _receiver) {\n const value = Reflect.get(target, prop) as unknown;\n\n if (typeof value !== 'function') {\n return value;\n }\n\n if (prop === 'get' || prop === 'getByName') {\n return function (this: unknown, ...args: unknown[]) {\n const stub = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectStub(stub);\n };\n }\n\n return value.bind(target);\n },\n });\n}\n\n/**\n * Instruments a DurableObjectStub to propagate trace context across fetch calls.\n *\n * @param stub - The DurableObjectStub to instrument\n */\nfunction instrumentDurableObjectStub(stub: DurableObjectStub): DurableObjectStub {\n return new Proxy(stub, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((input, init) => Reflect.apply(value, target, [input, init]));\n }\n\n return value;\n },\n });\n}\n"],"names":["instrumentFetcher"],"mappings":";;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gCAAgC,CAAC,SAAS,EAAkD;AAC5G,EAAE,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE;AAC9B,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;AACjC,MAAM,MAAM,KAAA,GAAQ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAA;;AAE5C,MAAM,IAAI,OAAO,KAAA,KAAU,UAAU,EAAE;AACvC,QAAQ,OAAO,KAAK;AACpB,MAAM;;AAEN,MAAM,IAAI,IAAA,KAAS,SAAS,IAAA,KAAS,WAAW,EAAE;AAClD,QAAQ,OAAO,WAAyB,GAAG,IAAI,EAAa;AAC5D,UAAU,MAAM,IAAA,GAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;;AAEzD,UAAU,OAAO,2BAA2B,CAAC,IAAI,CAAC;AAClD,QAAQ,CAAC;AACT,MAAM;;AAEN,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B,IAAI,CAAC;AACL,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS,2BAA2B,CAAC,IAAI,EAAwC;AACjF,EAAE,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE;AACzB,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;AAChC,MAAM,MAAM,KAAA,GAAQ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;;AAEvD,MAAM,IAAI,IAAA,KAAS,OAAA,IAAW,OAAO,KAAA,KAAU,UAAU,EAAE;AAC3D,QAAQ,OAAOA,mCAAiB,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9F,MAAM;;AAEN,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC;AACL,GAAG,CAAC;AACJ;;;;"}
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
|
+
const traceLinks = require('../utils/traceLinks.js');
|
|
4
5
|
|
|
5
|
-
const STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list'] ;
|
|
6
|
+
const STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list', 'setAlarm', 'getAlarm', 'deleteAlarm'] ;
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Instruments DurableObjectStorage methods with Sentry spans.
|
|
9
10
|
*
|
|
10
11
|
* Wraps the following async methods:
|
|
11
12
|
* - get, put, delete, list (KV API)
|
|
13
|
+
* - setAlarm, getAlarm, deleteAlarm (Alarm API)
|
|
14
|
+
*
|
|
15
|
+
* When setAlarm is called, it also stores the current span context so that when
|
|
16
|
+
* the alarm fires later, it can link back to the trace that called setAlarm.
|
|
12
17
|
*
|
|
13
18
|
* @param storage - The DurableObjectStorage instance to instrument
|
|
19
|
+
* @param waitUntil - Optional waitUntil function to defer span context storage
|
|
14
20
|
* @returns An instrumented DurableObjectStorage instance
|
|
15
21
|
*/
|
|
16
|
-
function instrumentDurableObjectStorage(
|
|
22
|
+
function instrumentDurableObjectStorage(
|
|
23
|
+
storage,
|
|
24
|
+
waitUntil,
|
|
25
|
+
) {
|
|
17
26
|
return new Proxy(storage, {
|
|
18
27
|
get(target, prop, _receiver) {
|
|
19
28
|
// Use `target` as the receiver instead of the proxy (`_receiver`).
|
|
@@ -45,7 +54,33 @@ function instrumentDurableObjectStorage(storage) {
|
|
|
45
54
|
},
|
|
46
55
|
},
|
|
47
56
|
() => {
|
|
48
|
-
|
|
57
|
+
const teardown = async () => {
|
|
58
|
+
// When setAlarm is called, store the current span context so that when the alarm
|
|
59
|
+
// fires later, it can link back to the trace that called setAlarm.
|
|
60
|
+
// We use the original (uninstrumented) storage (target) to avoid creating a span
|
|
61
|
+
// for this internal operation. The storage is deferred via waitUntil to not block.
|
|
62
|
+
if (methodName === 'setAlarm') {
|
|
63
|
+
await traceLinks.storeSpanContext(target, 'alarm');
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const result = (original ).apply(target, args);
|
|
68
|
+
|
|
69
|
+
if (!core.isThenable(result)) {
|
|
70
|
+
waitUntil?.(teardown());
|
|
71
|
+
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result.then(
|
|
76
|
+
res => {
|
|
77
|
+
waitUntil?.(teardown());
|
|
78
|
+
return res;
|
|
79
|
+
},
|
|
80
|
+
e => {
|
|
81
|
+
throw e;
|
|
82
|
+
},
|
|
83
|
+
);
|
|
49
84
|
},
|
|
50
85
|
);
|
|
51
86
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentDurableObjectStorage.js","sources":["../../../src/instrumentations/instrumentDurableObjectStorage.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list'] as const;\n\ntype StorageMethod = (typeof STORAGE_METHODS_TO_INSTRUMENT)[number];\n\n/**\n * Instruments DurableObjectStorage methods with Sentry spans.\n *\n * Wraps the following async methods:\n * - get, put, delete, list (KV API)\n *\n * @param storage - The DurableObjectStorage instance to instrument\n * @returns An instrumented DurableObjectStorage instance\n */\nexport function instrumentDurableObjectStorage(storage: DurableObjectStorage): DurableObjectStorage {\n return new Proxy(storage, {\n get(target, prop, _receiver) {\n // Use `target` as the receiver instead of the proxy (`_receiver`).\n // Native workerd getters (e.g., `storage.sql`) validate `this` via\n // internal slots. Passing the proxy as receiver breaks that check,\n // causing \"Illegal invocation: function called with incorrect `this`\n // reference\" errors.\n const original = Reflect.get(target, prop, target);\n\n if (typeof original !== 'function') {\n return original;\n }\n\n const methodName = prop as string;\n if (!STORAGE_METHODS_TO_INSTRUMENT.includes(methodName as StorageMethod)) {\n return (original as (...args: unknown[]) => unknown).bind(target);\n }\n\n return function (this: unknown, ...args: unknown[]) {\n return startSpan(\n {\n // Use underscore naming to match Cloudflare's native instrumentation (e.g., \"durable_object_storage_get\")\n name: `durable_object_storage_${methodName}`,\n op: 'db',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object',\n 'db.system.name': 'cloudflare.durable_object.storage',\n 'db.operation.name': methodName,\n },\n },\n () => {\n
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectStorage.js","sources":["../../../src/instrumentations/instrumentDurableObjectStorage.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport { isThenable, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\nimport { storeSpanContext } from '../utils/traceLinks';\n\nconst STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list', 'setAlarm', 'getAlarm', 'deleteAlarm'] as const;\n\ntype StorageMethod = (typeof STORAGE_METHODS_TO_INSTRUMENT)[number];\n\ntype WaitUntil = (promise: Promise<unknown>) => void;\n\n/**\n * Instruments DurableObjectStorage methods with Sentry spans.\n *\n * Wraps the following async methods:\n * - get, put, delete, list (KV API)\n * - setAlarm, getAlarm, deleteAlarm (Alarm API)\n *\n * When setAlarm is called, it also stores the current span context so that when\n * the alarm fires later, it can link back to the trace that called setAlarm.\n *\n * @param storage - The DurableObjectStorage instance to instrument\n * @param waitUntil - Optional waitUntil function to defer span context storage\n * @returns An instrumented DurableObjectStorage instance\n */\nexport function instrumentDurableObjectStorage(\n storage: DurableObjectStorage,\n waitUntil?: WaitUntil,\n): DurableObjectStorage {\n return new Proxy(storage, {\n get(target, prop, _receiver) {\n // Use `target` as the receiver instead of the proxy (`_receiver`).\n // Native workerd getters (e.g., `storage.sql`) validate `this` via\n // internal slots. Passing the proxy as receiver breaks that check,\n // causing \"Illegal invocation: function called with incorrect `this`\n // reference\" errors.\n const original = Reflect.get(target, prop, target);\n\n if (typeof original !== 'function') {\n return original;\n }\n\n const methodName = prop as string;\n if (!STORAGE_METHODS_TO_INSTRUMENT.includes(methodName as StorageMethod)) {\n return (original as (...args: unknown[]) => unknown).bind(target);\n }\n\n return function (this: unknown, ...args: unknown[]) {\n return startSpan(\n {\n // Use underscore naming to match Cloudflare's native instrumentation (e.g., \"durable_object_storage_get\")\n name: `durable_object_storage_${methodName}`,\n op: 'db',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object',\n 'db.system.name': 'cloudflare.durable_object.storage',\n 'db.operation.name': methodName,\n },\n },\n () => {\n const teardown = async (): Promise<void> => {\n // When setAlarm is called, store the current span context so that when the alarm\n // fires later, it can link back to the trace that called setAlarm.\n // We use the original (uninstrumented) storage (target) to avoid creating a span\n // for this internal operation. The storage is deferred via waitUntil to not block.\n if (methodName === 'setAlarm') {\n await storeSpanContext(target, 'alarm');\n }\n };\n\n const result = (original as (...args: unknown[]) => unknown).apply(target, args);\n\n if (!isThenable(result)) {\n waitUntil?.(teardown());\n\n return result;\n }\n\n return result.then(\n res => {\n waitUntil?.(teardown());\n return res;\n },\n e => {\n throw e;\n },\n );\n },\n );\n };\n },\n });\n}\n"],"names":["startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","storeSpanContext","isThenable"],"mappings":";;;;;AAIA,MAAM,gCAAgC,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,CAAA;;AAM5G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,8BAA8B;AAC9C,EAAE,OAAO;AACT,EAAE,SAAS;AACX,EAAwB;AACxB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;AAC5B,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;AACjC;AACA;AACA;AACA;AACA;AACA,MAAM,MAAM,QAAA,GAAW,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;;AAExD,MAAM,IAAI,OAAO,QAAA,KAAa,UAAU,EAAE;AAC1C,QAAQ,OAAO,QAAQ;AACvB,MAAM;;AAEN,MAAM,MAAM,UAAA,GAAa,IAAA;AACzB,MAAM,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC,UAAA,EAA4B,EAAE;AAChF,QAAQ,OAAO,CAAC,QAAA,GAA6C,IAAI,CAAC,MAAM,CAAC;AACzE,MAAM;;AAEN,MAAM,OAAO,WAAyB,GAAG,IAAI,EAAa;AAC1D,QAAQ,OAAOA,cAAS;AACxB,UAAU;AACV;AACA,YAAY,IAAI,EAAE,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAA;AACA,YAAA,EAAA,EAAA,IAAA;AACA,YAAA,UAAA,EAAA;AACA,cAAA,CAAAC,qCAAA,GAAA,mCAAA;AACA,cAAA,gBAAA,EAAA,mCAAA;AACA,cAAA,mBAAA,EAAA,UAAA;AACA,aAAA;AACA,WAAA;AACA,UAAA,MAAA;AACA,YAAA,MAAA,QAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,cAAA,IAAA,UAAA,KAAA,UAAA,EAAA;AACA,gBAAA,MAAAC,2BAAA,CAAA,MAAA,EAAA,OAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;;AAEA,YAAA,MAAA,MAAA,GAAA,CAAA,QAAA,GAAA,KAAA,CAAA,MAAA,EAAA,IAAA,CAAA;;AAEA,YAAA,IAAA,CAAAC,eAAA,CAAA,MAAA,CAAA,EAAA;AACA,cAAA,SAAA,GAAA,QAAA,EAAA,CAAA;;AAEA,cAAA,OAAA,MAAA;AACA,YAAA;;AAEA,YAAA,OAAA,MAAA,CAAA,IAAA;AACA,cAAA,GAAA,IAAA;AACA,gBAAA,SAAA,GAAA,QAAA,EAAA,CAAA;AACA,gBAAA,OAAA,GAAA;AACA,cAAA,CAAA;AACA,cAAA,CAAA,IAAA;AACA,gBAAA,MAAA,CAAA;AACA,cAAA,CAAA;AACA,aAAA;AACA,UAAA,CAAA;AACA,SAAA;AACA,MAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;;;"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const async = require('../async.js');
|
|
4
|
+
const instrumentFetch = require('./worker/instrumentFetch.js');
|
|
5
|
+
const instrumentQueue = require('./worker/instrumentQueue.js');
|
|
6
|
+
const instrumentScheduled = require('./worker/instrumentScheduled.js');
|
|
7
|
+
const instrumentTail = require('./worker/instrumentTail.js');
|
|
8
|
+
const options = require('../options.js');
|
|
9
|
+
const instrumentContext = require('../utils/instrumentContext.js');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Instruments a WorkerEntrypoint class to capture errors and performance data.
|
|
13
|
+
*
|
|
14
|
+
* Instruments the following methods (same as `withSentry` for ExportedHandler):
|
|
15
|
+
* - fetch (HTTP requests)
|
|
16
|
+
* - scheduled (cron triggers)
|
|
17
|
+
* - queue (queue consumers)
|
|
18
|
+
* - email (email handlers)
|
|
19
|
+
* - tail (tail workers)
|
|
20
|
+
*
|
|
21
|
+
* as well as any other public RPC methods on the WorkerEntrypoint instance.
|
|
22
|
+
*
|
|
23
|
+
* @param optionsCallback Function that returns the options for the SDK initialization.
|
|
24
|
+
* @param WorkerEntrypointClass The WorkerEntrypoint class to instrument.
|
|
25
|
+
* @returns The instrumented WorkerEntrypoint class.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* class MyWorkerBase extends WorkerEntrypoint<Env> {
|
|
30
|
+
* async fetch(request: Request): Promise<Response> {
|
|
31
|
+
* return new Response('Hello World!');
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* async myRpcMethod(arg: string): Promise<string> {
|
|
35
|
+
* return `Hello ${arg}!`;
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* export default instrumentWorkerEntrypoint(
|
|
40
|
+
* env => ({
|
|
41
|
+
* dsn: env.SENTRY_DSN,
|
|
42
|
+
* tracesSampleRate: 1.0,
|
|
43
|
+
* }),
|
|
44
|
+
* MyWorkerBase,
|
|
45
|
+
* );
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
function instrumentWorkerEntrypoint(
|
|
49
|
+
optionsCallback,
|
|
50
|
+
WorkerEntrypointClass,
|
|
51
|
+
) {
|
|
52
|
+
// Set up AsyncLocalStorage strategy ONCE at instrumentation time, not per-request
|
|
53
|
+
// This is critical - calling this per-request would create a new AsyncLocalStorage
|
|
54
|
+
// each time, breaking scope isolation for concurrent requests
|
|
55
|
+
async.setAsyncLocalStorageAsyncContextStrategy();
|
|
56
|
+
|
|
57
|
+
return new Proxy(WorkerEntrypointClass, {
|
|
58
|
+
construct(target, [ctx, env]) {
|
|
59
|
+
const context = instrumentContext.instrumentContext(ctx);
|
|
60
|
+
const options$1 = options.getFinalOptions(optionsCallback(env), env);
|
|
61
|
+
const obj = new target(context, env);
|
|
62
|
+
|
|
63
|
+
// Override this.ctx to ensure the instrumented context is used
|
|
64
|
+
// This is necessary because the base WorkerEntrypoint class sets this.ctx
|
|
65
|
+
// from the constructor parameter, but we want users accessing this.ctx
|
|
66
|
+
// to get the instrumented version
|
|
67
|
+
if ('ctx' in obj) {
|
|
68
|
+
Object.defineProperty(obj, 'ctx', {
|
|
69
|
+
value: context,
|
|
70
|
+
writable: true,
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Object.defineProperty(obj, '__SENTRY_CONTEXT__', {
|
|
77
|
+
value: context,
|
|
78
|
+
enumerable: false,
|
|
79
|
+
writable: false,
|
|
80
|
+
configurable: false,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
Object.defineProperty(obj, '__SENTRY_OPTIONS__', {
|
|
84
|
+
value: options$1,
|
|
85
|
+
enumerable: false,
|
|
86
|
+
writable: false,
|
|
87
|
+
configurable: false,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
instrumentFetch.instrumentWorkerEntrypointFetch(obj, options$1, context);
|
|
91
|
+
instrumentScheduled.instrumentWorkerEntrypointScheduled(obj, options$1, context);
|
|
92
|
+
instrumentQueue.instrumentWorkerEntrypointQueue(obj, options$1, context);
|
|
93
|
+
instrumentTail.instrumentWorkerEntrypointTail(obj, options$1, context);
|
|
94
|
+
|
|
95
|
+
return obj;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.instrumentWorkerEntrypoint = instrumentWorkerEntrypoint;
|
|
101
|
+
//# sourceMappingURL=instrumentWorkerEntrypoint.js.map
|