Skip to content

Commit 7b5f046

Browse files
committed
wip hono stuff
1 parent 65fc6d4 commit 7b5f046

44 files changed

Lines changed: 602 additions & 2186 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
traceLifecycle: 'static',
6+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
7+
tracesSampleRate: 1.0,
8+
transport: loggingTransport,
9+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { serve } from '@hono/node-server';
2+
import { sendPortToRunner } from '@sentry-internal/node-integration-tests';
3+
import { Hono } from 'hono';
4+
5+
// No `@sentry/hono` and no `sentry()` middleware: the app is instrumented automatically by the
6+
// `honoIntegration` default in `@sentry/node` (via orchestrion hooking the `Hono` constructor).
7+
const app = new Hono();
8+
9+
app.get('/', c => {
10+
return c.text('Hello from Hono on Node!');
11+
});
12+
13+
app.get('/hello/:name', c => {
14+
const name = c.req.param('name');
15+
return c.text(`Hello, ${name}!`);
16+
});
17+
18+
app.get('/error/:param', () => {
19+
throw new Error('Test error from Hono app');
20+
});
21+
22+
serve({ fetch: app.fetch, port: 0 }, info => {
23+
sendPortToRunner(info.port);
24+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { afterAll, describe, expect } from 'vitest';
2+
import { cleanupChildProcesses, createEsmAndCjsTests } from '../../utils/runner';
3+
4+
// Verifies that Hono is auto-instrumented out of the box by `@sentry/node` (the `honoIntegration`
5+
// default), without importing `@sentry/hono` or registering the `sentry()` middleware manually.
6+
describe('hono auto-instrumentation (Node)', () => {
7+
afterAll(() => {
8+
cleanupChildProcesses();
9+
});
10+
11+
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => {
12+
test('creates a transaction for a basic GET request', async () => {
13+
const runner = createRunner()
14+
.expect({
15+
transaction: {
16+
transaction: 'GET /',
17+
contexts: {
18+
trace: {
19+
op: 'http.server',
20+
status: 'ok',
21+
},
22+
},
23+
},
24+
})
25+
.start();
26+
runner.makeRequest('get', '/');
27+
await runner.completed();
28+
});
29+
30+
test('creates a transaction with a parametrized route name', async () => {
31+
const runner = createRunner()
32+
.expect({
33+
transaction: {
34+
transaction: 'GET /hello/:name',
35+
transaction_info: {
36+
source: 'route',
37+
},
38+
contexts: {
39+
trace: {
40+
op: 'http.server',
41+
status: 'ok',
42+
},
43+
},
44+
},
45+
})
46+
.start();
47+
runner.makeRequest('get', '/hello/world');
48+
await runner.completed();
49+
});
50+
51+
test('captures an error with the correct mechanism', async () => {
52+
const runner = createRunner()
53+
.ignore('transaction')
54+
.expect({
55+
event: {
56+
exception: {
57+
values: [
58+
{
59+
type: 'Error',
60+
value: 'Test error from Hono app',
61+
mechanism: {
62+
type: 'auto.http.hono.context_error',
63+
handled: false,
64+
},
65+
},
66+
],
67+
},
68+
transaction: 'GET /error/:param',
69+
},
70+
})
71+
.start();
72+
runner.makeRequest('get', '/error/param-123', { expectError: true });
73+
await runner.completed();
74+
});
75+
76+
test('creates a transaction with internal_error status when an error occurs', async () => {
77+
const runner = createRunner()
78+
.ignore('event')
79+
.expect({
80+
transaction: {
81+
transaction: 'GET /error/:param',
82+
contexts: {
83+
trace: {
84+
op: 'http.server',
85+
status: 'internal_error',
86+
data: expect.objectContaining({
87+
'http.response.status_code': 500,
88+
}),
89+
},
90+
},
91+
},
92+
})
93+
.start();
94+
runner.makeRequest('get', '/error/param-456', { expectError: true });
95+
await runner.completed();
96+
});
97+
});
98+
});

‎packages/hono/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@
7474
"dependencies": {
7575
"@opentelemetry/api": "^1.9.1",
7676
"@sentry/core": "10.67.0",
77-
"@sentry/conventions": "^0.23.0"
77+
"@sentry/conventions": "^0.23.0",
78+
"@sentry/server-utils": "10.67.0"
7879
},
7980
"peerDependencies": {
8081
"@cloudflare/workers-types": "^4.x",
Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { type BaseTransportOptions, debug, type Options } from '@sentry/core';
22
import { init } from './sdk';
33
import { getConnInfo } from 'hono/bun';
4+
import { applyHonoPatches, createHonoRequestMiddleware, type SentryHonoMiddlewareOptions } from '@sentry/server-utils';
45
import type { Env, Hono, MiddlewareHandler } from 'hono';
5-
import { requestHandler, responseHandler } from '../shared/middlewareHandlers';
6-
import { applyPatches } from '../shared/applyPatches';
7-
import type { SentryHonoMiddlewareOptions } from '../shared/types';
86

97
export interface HonoBunOptions extends Options<BaseTransportOptions>, SentryHonoMiddlewareOptions {}
108

@@ -16,13 +14,7 @@ export const sentry = <E extends Env>(app: Hono<E>, options: HonoBunOptions): Mi
1614

1715
init(options);
1816

19-
applyPatches(app);
17+
applyHonoPatches(app);
2018

21-
return async (context, next) => {
22-
requestHandler(context, getConnInfo);
23-
24-
await next(); // Handler runs in between Request above ⤴ and Response below ⤵
25-
26-
responseHandler(context, options.shouldHandleError);
27-
};
19+
return createHonoRequestMiddleware({ getConnInfo, shouldHandleError: options.shouldHandleError });
2820
};

‎packages/hono/src/cloudflare/middleware.ts‎

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { withSentry } from '@sentry/cloudflare';
22
import { applySdkMetadata, type BaseTransportOptions, debug, type Options } from '@sentry/core';
33
import { getConnInfo } from 'hono/cloudflare-workers';
4+
import { applyHonoPatches, createHonoRequestMiddleware, type SentryHonoMiddlewareOptions } from '@sentry/server-utils';
45
import type { Env, Hono, MiddlewareHandler } from 'hono';
56
import { buildFilteredIntegrations } from '../shared/buildFilteredIntegrations';
67
import { LOW_QUALITY_TRANSACTION_PATTERNS } from '../shared/lowQualityTransactionPatterns';
7-
import { requestHandler, responseHandler } from '../shared/middlewareHandlers';
8-
import { applyPatches } from '../shared/applyPatches';
9-
import type { SentryHonoMiddlewareOptions } from '../shared/types';
108

119
export interface HonoCloudflareOptions extends Options<BaseTransportOptions>, SentryHonoMiddlewareOptions {}
1210

@@ -41,18 +39,15 @@ export function sentry<E extends Env>(
4139
app as unknown as ExportedHandler<unknown>,
4240
);
4341

44-
applyPatches(app);
42+
applyHonoPatches(app);
4543

46-
return async (context, next) => {
47-
const shouldHandleError =
44+
return createHonoRequestMiddleware({
45+
getConnInfo,
46+
// Cloudflare accepts middleware options as a function of `env`, so `shouldHandleError` is only
47+
// known per request.
48+
resolveShouldHandleError: context =>
4849
typeof options === 'function'
4950
? options(context.env as E['Bindings']).shouldHandleError
50-
: options.shouldHandleError;
51-
52-
requestHandler(context, getConnInfo);
53-
54-
await next(); // Handler runs in between Request above ⤴ and Response below ⤵
55-
56-
responseHandler(context, shouldHandleError);
57-
};
51+
: options.shouldHandleError,
52+
});
5853
}

‎packages/hono/src/debug-build.ts‎

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { type BaseTransportOptions, debug, type Options } from '@sentry/core';
22
import { init } from './sdk';
3-
import type { Env, Hono, MiddlewareHandler } from 'hono';
43
import { getConnInfo } from 'hono/deno';
5-
import { requestHandler, responseHandler } from '../shared/middlewareHandlers';
6-
import { applyPatches } from '../shared/applyPatches';
7-
import type { SentryHonoMiddlewareOptions } from '../shared/types';
4+
import { applyHonoPatches, createHonoRequestMiddleware, type SentryHonoMiddlewareOptions } from '@sentry/server-utils';
5+
import type { Env, Hono, MiddlewareHandler } from 'hono';
86

97
export interface HonoDenoOptions extends Options<BaseTransportOptions>, SentryHonoMiddlewareOptions {}
108

@@ -16,13 +14,7 @@ export const sentry = <E extends Env>(app: Hono<E>, options: HonoDenoOptions): M
1614

1715
init(options);
1816

19-
applyPatches(app);
20-
21-
return async (context, next) => {
22-
requestHandler(context, getConnInfo);
23-
24-
await next(); // Handler runs in between Request above ⤴ and Response below ⤵
17+
applyHonoPatches(app);
2518

26-
responseHandler(context, options.shouldHandleError);
27-
};
19+
return createHonoRequestMiddleware({ getConnInfo, shouldHandleError: options.shouldHandleError });
2820
};

‎packages/hono/src/index.bun.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { earlyPatchHono } from './shared/applyPatches';
1+
import { earlyPatchHono } from '@sentry/server-utils';
2+
import { Hono } from 'hono';
23

3-
earlyPatchHono();
4+
earlyPatchHono(Hono);
45

56
export { sentry } from './bun/middleware';
67

‎packages/hono/src/index.cloudflare.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { earlyPatchHono } from './shared/applyPatches';
1+
import { earlyPatchHono } from '@sentry/server-utils';
2+
import { Hono } from 'hono';
23

3-
earlyPatchHono();
4+
earlyPatchHono(Hono);
45

56
export { sentry } from './cloudflare/middleware';
67

0 commit comments

Comments
 (0)