Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 20 additions & 6 deletions packages/hono/src/node/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type BaseTransportOptions, debug, type Options, getClient } from '@sentry/core';
import { type BaseTransportOptions, consoleSandbox, debug, getClient, type Options } from '@sentry/core';
import type { Env, Hono, MiddlewareHandler } from 'hono';
import { requestHandler, responseHandler } from '../shared/middlewareHandlers';
import { applyPatches } from '../shared/applyPatches';
Expand All @@ -17,12 +17,26 @@ export interface HonoNodeOptions extends Options<BaseTransportOptions> {}
export const sentry = <E extends Env>(app: Hono<E>, options?: SentryHonoMiddlewareOptions): MiddlewareHandler => {
const sentryClient = getClient();
if (sentryClient === undefined) {
debug.warn(
'Sentry is not initialized. Call `init()` from @sentry/hono/node in an `instrument.ts` file loaded via `--import` to set up Sentry for your application.',
);
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
'[@sentry/hono] Sentry is not initialized. Call `init()` from `@sentry/hono/node` in an `instrument.ts` file loaded via `--import` to set up Sentry for your application.',
);
});
} else {
sentryClient.getOptions().debug &&
debug.log('Sentry is initialized, proceeding to set up Hono `sentry` middleware.');
const isInitializedWithHonoSdk = sentryClient.getOptions()._metadata?.sdk?.name === 'sentry.javascript.hono';

if (!isInitializedWithHonoSdk) {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

l: so this one we want to always show and the other warnings only as debug logs? is that intentional?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's intentional as it should always be shown (it's pretty important). The first log is also pretty important, I'm gonna change this to console. The third log in the file is really just a debug log.

'[Sentry] Sentry was not initialized with `@sentry/hono/node`. Please import from `@sentry/hono/node` to ensure Hono-specific instrumentation is applied correctly.',
);
});
} else {
sentryClient.getOptions().debug &&
debug.log('Sentry is initialized, proceeding to set up Hono `sentry` middleware.');
}
}

applyPatches(app);
Expand Down
69 changes: 56 additions & 13 deletions packages/hono/test/node/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,61 @@ describe('Hono Node Middleware', () => {
expect(middleware.constructor.name).toBe('AsyncFunction');
});

it('emits a warning when Sentry is not initialized', () => {
const warnSpy = vi.spyOn(SentryCore.debug, 'warn');
it('emits a console.warn when Sentry is not initialized', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
vi.spyOn(SentryCore, 'getClient').mockReturnValue(undefined);

const app = new Hono();
sentry(app);

expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry is not initialized'));
expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry is not initialized'));
consoleWarnSpy.mockRestore();
});

it('does not emit a warning when Sentry is already initialized', () => {
const warnSpy = vi.spyOn(SentryCore.debug, 'warn');
it('does not emit a warning when Sentry is already initialized with @sentry/hono/node', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const fakeClient = {
getOptions: () => ({
debug: false,
_metadata: { sdk: { name: 'sentry.javascript.hono' } },
}),
};
vi.spyOn(SentryCore, 'getClient').mockReturnValue(fakeClient as unknown as SentryCore.Client);

const app = new Hono();
sentry(app);

expect(consoleWarnSpy).not.toHaveBeenCalled();
consoleWarnSpy.mockRestore();
});

it('emits a console.warn when Sentry is initialized with @sentry/node instead of @sentry/hono/node', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const fakeClient = {
getOptions: () => ({
debug: false,
_metadata: { sdk: { name: 'sentry.javascript.node' } },
}),
};
vi.spyOn(SentryCore, 'getClient').mockReturnValue(fakeClient as unknown as SentryCore.Client);

const app = new Hono();
sentry(app);

expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('not initialized with `@sentry/hono/node`'));
consoleWarnSpy.mockRestore();
});

it('emits a console.warn when Sentry is initialized without any SDK metadata', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const fakeClient = { getOptions: () => ({ debug: false }) };
vi.spyOn(SentryCore, 'getClient').mockReturnValue(fakeClient as unknown as SentryCore.Client);

const app = new Hono();
sentry(app);

expect(warnSpy).not.toHaveBeenCalled();
expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('not initialized with `@sentry/hono/node`'));
consoleWarnSpy.mockRestore();
});
});

Expand Down Expand Up @@ -135,26 +171,33 @@ describe('Hono Node Middleware', () => {
expect(middleware.constructor.name).toBe('AsyncFunction');
});

it('emits a warning when Sentry is not initialized', () => {
const warnSpy = vi.spyOn(SentryCore.debug, 'warn');
it('emits a console.warn when Sentry is not initialized', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
vi.spyOn(SentryCore, 'getClient').mockReturnValue(undefined);

const app = new Hono();
sentry(app);

expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry is not initialized'));
expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry is not initialized'));
consoleWarnSpy.mockRestore();
});

it('does not emit a warning when Sentry is already initialized', () => {
const warnSpy = vi.spyOn(SentryCore.debug, 'warn');
const fakeClient = { getOptions: () => ({ debug: false }) };
it('does not emit a warning when Sentry is already initialized with @sentry/hono/node', () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const fakeClient = {
getOptions: () => ({
debug: false,
_metadata: { sdk: { name: 'sentry.javascript.hono' } },
}),
};
vi.spyOn(SentryCore, 'getClient').mockReturnValue(fakeClient as unknown as SentryCore.Client);

const app = new Hono();
const middleware = sentry(app);

expect(warnSpy).not.toHaveBeenCalled();
expect(consoleWarnSpy).not.toHaveBeenCalled();
expect(middleware.constructor.name).toBe('AsyncFunction');
consoleWarnSpy.mockRestore();
});
});

Expand Down
Loading