Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ jobs:
- name: Set up Deno
uses: denoland/setup-deno@v1.1.4
with:
deno-version: v1.38.5
deno-version: v1.x
Copy link
Copy Markdown
Author

@brc-dd brc-dd Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jsr wasn't supported on deno 1.38. deno.land/std/... won't receive non-critical updates and jsr is the recommended way

if needed we can lock it to some minor

re-running CI should pass I guess 👀

- name: Restore caches
uses: ./.github/actions/restore-cache
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ tmp.js
packages/deno/build-types
packages/deno/build-test
packages/deno/lib.deno.d.ts
deno.lock

# gatsby
packages/gatsby/gatsby-node.d.ts
4 changes: 2 additions & 2 deletions packages/deno/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
"test": "run-s install:deno test:types test:unit",
"test:build": "tsc -p tsconfig.test.types.json && rollup -c rollup.test.config.mjs",
"test:types": "deno check ./build/index.mjs",
"test:unit": "deno test --allow-read --allow-run",
"test:unit:update": "deno test --allow-read --allow-write --allow-run -- --update",
"test:unit": "deno test --allow-read --allow-run --allow-net",
"test:unit:update": "deno test --allow-read --allow-write --allow-run --allow-net -- --update",
"yalc:publish": "ts-node ../../scripts/prepack.ts && yalc publish build --push --sig"
},
"volta": {
Expand Down
3 changes: 3 additions & 0 deletions packages/deno/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export {
spanToJSON,
spanToTraceHeader,
spanToBaggageHeader,
spanIsSampled,
getDynamicSamplingContextFromSpan,
} from '@sentry/core';

export { DenoClient } from './client';
Expand All @@ -96,3 +98,4 @@ export { normalizePathsIntegration } from './integrations/normalizepaths';
export { contextLinesIntegration } from './integrations/contextlines';
export { denoCronIntegration } from './integrations/deno-cron';
export { breadcrumbsIntegration } from './integrations/breadcrumbs';
export { denoServerIntegration } from './integrations/denoserver';
136 changes: 136 additions & 0 deletions packages/deno/src/integrations/denoserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import {
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
captureException,
continueTrace,
defineIntegration,
setHttpStatus,
startSpan,
withIsolationScope,
} from '@sentry/core';
import type { IntegrationFn, SpanAttributes } from '@sentry/types';
import { getSanitizedUrlString, parseUrl } from '@sentry/utils';

type RawHandler = (request: Request, info: Deno.ServeHandlerInfo) => Response | Promise<Response>;

const INTEGRATION_NAME = 'DenoServer';

const _denoServerIntegration = (() => {
return {
name: INTEGRATION_NAME,
setupOnce() {
instrumentDenoServe();
},
};
}) satisfies IntegrationFn;

/**
* Instruments `Deno.serve` to automatically create transactions and capture errors.
*
* Enabled by default in the Deno SDK.
*
* ```js
* Sentry.init({
* integrations: [
* Sentry.denoServerIntegration(),
* ],
* })
* ```
*/
export const denoServerIntegration = defineIntegration(_denoServerIntegration);

/**
* Instruments Deno.serve by patching it's options.
*/
export function instrumentDenoServe(): void {
Deno.serve = new Proxy(Deno.serve, {
apply(serveTarget, serveThisArg, serveArgs: unknown[]) {
const [arg1, arg2] = serveArgs;

if (typeof arg1 === 'function') {
serveArgs[0] = instrumentDenoServeOptions(arg1 as RawHandler);
} else if (typeof arg2 === 'function') {
serveArgs[1] = instrumentDenoServeOptions(arg2 as RawHandler);
} else if (arg1 && typeof arg1 === 'object' && 'handler' in arg1 && typeof arg1.handler === 'function') {
arg1.handler = instrumentDenoServeOptions(arg1.handler as RawHandler);
}

return serveTarget.apply(serveThisArg, serveArgs as Parameters<typeof Deno.serve>);
},
});
}

/**
* Instruments Deno.serve handler to automatically create spans and capture errors.
*/
function instrumentDenoServeOptions(handler: RawHandler): RawHandler {
return new Proxy(handler, {
apply(handlerTarget, handlerThisArg, handlerArgs: Parameters<RawHandler>) {
return withIsolationScope(isolationScope => {
isolationScope.clear();
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also this line should be removed when #12450 (comment) is resolved


const request = handlerArgs[0];
if (request.method === 'OPTIONS' || request.method === 'HEAD') {
return handlerTarget.apply(handlerThisArg, handlerArgs);
}

const parsedUrl = parseUrl(request.url);
const attributes: SpanAttributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.deno.serve',
'http.request.method': request.method || 'GET',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
};
if (parsedUrl.search) {
attributes['http.query'] = parsedUrl.search;
}

const url = getSanitizedUrlString(parsedUrl);

isolationScope.setSDKProcessingMetadata({
request: {
url,
method: request.method,
headers: Object.fromEntries(request.headers),
},
});

return continueTrace(
{ sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },
() => {
return startSpan(
{
attributes,
op: 'http.server',
name: `${request.method} ${parsedUrl.path || '/'}`,
},
async span => {
try {
const response = await (handlerTarget.apply(handlerThisArg, handlerArgs) as ReturnType<RawHandler>);
if (response && response.status) {
setHttpStatus(span, response.status);
isolationScope.setContext('response', {
headers: Object.fromEntries(response.headers),
status_code: response.status,
});
}
return response;
} catch (e) {
captureException(e, {
mechanism: {
type: 'deno',
handled: false,
data: {
function: 'serve',
},
},
});
throw e;
}
},
);
},
);
});
},
});
}
4 changes: 4 additions & 0 deletions packages/deno/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
functionToStringIntegration,
inboundFiltersIntegration,
linkedErrorsIntegration,
requestDataIntegration,
} from '@sentry/core';
import { getIntegrationsToSetup, initAndBind } from '@sentry/core';
import type { Integration, Options, StackParser } from '@sentry/types';
Expand All @@ -13,6 +14,7 @@ import { DenoClient } from './client';
import { breadcrumbsIntegration } from './integrations/breadcrumbs';
import { denoContextIntegration } from './integrations/context';
import { contextLinesIntegration } from './integrations/contextlines';
import { denoServerIntegration } from './integrations/denoserver';
import { globalHandlersIntegration } from './integrations/globalhandlers';
import { normalizePathsIntegration } from './integrations/normalizepaths';
import { makeFetchTransport } from './transports';
Expand All @@ -26,13 +28,15 @@ export function getDefaultIntegrations(_options: Options): Integration[] {
inboundFiltersIntegration(),
functionToStringIntegration(),
linkedErrorsIntegration(),
requestDataIntegration(),
dedupeIntegration(),
// Deno Specific
breadcrumbsIntegration(),
denoContextIntegration(),
contextLinesIntegration(),
normalizePathsIntegration(),
globalHandlersIntegration(),
denoServerIntegration(),
];
}

Expand Down
12 changes: 10 additions & 2 deletions packages/deno/test/__snapshots__/mod.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ snapshot[`captureException 1`] = `
filename: "app:///test/mod.test.ts",
function: "?",
in_app: true,
lineno: 46,
lineno: 23,
post_context: [
"",
" await delay(200);",
Expand All @@ -74,7 +74,7 @@ snapshot[`captureException 1`] = `
filename: "app:///test/mod.test.ts",
function: "something",
in_app: true,
lineno: 43,
lineno: 20,
post_context: [
" }",
"",
Expand Down Expand Up @@ -107,12 +107,14 @@ snapshot[`captureException 1`] = `
"InboundFilters",
"FunctionToString",
"LinkedErrors",
"RequestData",
"Dedupe",
"Breadcrumbs",
"DenoContext",
"ContextLines",
"NormalizePaths",
"GlobalHandlers",
"DenoServer",
],
name: "sentry.javascript.deno",
packages: [
Expand Down Expand Up @@ -177,12 +179,14 @@ snapshot[`captureMessage 1`] = `
"InboundFilters",
"FunctionToString",
"LinkedErrors",
"RequestData",
"Dedupe",
"Breadcrumbs",
"DenoContext",
"ContextLines",
"NormalizePaths",
"GlobalHandlers",
"DenoServer",
],
name: "sentry.javascript.deno",
packages: [
Expand Down Expand Up @@ -254,12 +258,14 @@ snapshot[`captureMessage twice 1`] = `
"InboundFilters",
"FunctionToString",
"LinkedErrors",
"RequestData",
"Dedupe",
"Breadcrumbs",
"DenoContext",
"ContextLines",
"NormalizePaths",
"GlobalHandlers",
"DenoServer",
],
name: "sentry.javascript.deno",
packages: [
Expand Down Expand Up @@ -338,12 +344,14 @@ snapshot[`captureMessage twice 2`] = `
"InboundFilters",
"FunctionToString",
"LinkedErrors",
"RequestData",
"Dedupe",
"Breadcrumbs",
"DenoContext",
"ContextLines",
"NormalizePaths",
"GlobalHandlers",
"DenoServer",
],
name: "sentry.javascript.deno",
packages: [
Expand Down
25 changes: 25 additions & 0 deletions packages/deno/test/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { sentryTypes } from '../build-test/index.js';
import { sentryUtils } from '../build-test/index.js';
import { DenoClient, getCurrentScope, getDefaultIntegrations } from '../build/index.mjs';
import { getNormalizedEvent } from './normalize.ts';
import { makeTestTransport } from './transport.ts';

export function getTestClient(
callback: (event?: sentryTypes.Event) => void,
integrations: sentryTypes.Integration[] = [],
): DenoClient {
const client = new DenoClient({
dsn: 'https://233a45e5efe34c47a3536797ce15dafa@nothing.here/5650507',
debug: true,
integrations: [...getDefaultIntegrations({}), ...integrations],
stackParser: sentryUtils.createStackParser(sentryUtils.nodeStackLineParser()),
transport: makeTestTransport(envelope => {
callback(getNormalizedEvent(envelope));
}),
});

client.init();
getCurrentScope().setClient(client);

return client;
}
Loading