refactor(core-shared): delete SentryLogger (replaced by OtelLogger)
Some checks failed
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled

Removes sentry-logger.ts and its test now that OtelLogger is the active
ILogger impl in bind-otel-instrumentation.ts. Updates the binder test to
assert OtelLogger (not SentryLogger) is bound. Fixes TypeScript errors:
SentryLogRecordForwarder registers directly as LogRecordProcessor (not
wrapped in BatchLogRecordProcessor which expects a LogRecordExporter);
severityNumber undefined guard added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-11 11:54:54 +02:00
parent ad64009e86
commit 5c9cba318a
5 changed files with 14 additions and 138 deletions

View File

@@ -1,82 +0,0 @@
// packages/core-shared/src/instrumentation/sentry/sentry-logger.test.ts
import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("@sentry/nextjs", () => ({
captureException: vi.fn(),
captureMessage: vi.fn(),
addBreadcrumb: vi.fn(),
setUser: vi.fn(),
}));
import * as Sentry from "@sentry/nextjs";
import { SentryLogger } from "@/instrumentation/sentry/sentry-logger";
describe("SentryLogger", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("captureException forwards to Sentry on first call", () => {
const logger = new SentryLogger();
const err = new Error("boom");
logger.captureException(err, { tags: { feature: "blog" } });
expect(Sentry.captureException).toHaveBeenCalledTimes(1);
expect((Sentry.captureException as ReturnType<typeof vi.fn>).mock.calls[0]![0]).toBe(err);
});
it("captureException is a no-op when err already marked __sentryReported", () => {
const logger = new SentryLogger();
const err = new Error("already-reported");
Object.defineProperty(err, "__sentryReported", { value: true });
logger.captureException(err);
expect(Sentry.captureException).not.toHaveBeenCalled();
});
it("captureException marks err as __sentryReported after sending", () => {
const logger = new SentryLogger();
const err = new Error("once");
logger.captureException(err);
expect((err as unknown as { __sentryReported: boolean }).__sentryReported).toBe(true);
// Second call: no-op
logger.captureException(err);
expect(Sentry.captureException).toHaveBeenCalledTimes(1);
});
it("__sentryReported is non-enumerable", () => {
const logger = new SentryLogger();
const err = new Error("x");
logger.captureException(err);
expect(Object.keys(err)).not.toContain("__sentryReported");
expect(JSON.stringify(err)).not.toContain("__sentryReported");
});
it("captureMessage forwards to Sentry", () => {
const logger = new SentryLogger();
logger.captureMessage("hello", "warning", { tags: { foo: "bar" } });
expect(Sentry.captureMessage).toHaveBeenCalledWith(
"hello",
expect.objectContaining({ level: "warning" }),
);
});
it("addBreadcrumb forwards to Sentry", () => {
const logger = new SentryLogger();
logger.addBreadcrumb({ category: "test", message: "x", data: { k: "v" } });
expect(Sentry.addBreadcrumb).toHaveBeenCalledTimes(1);
});
it("setUser strips non-id keys and warns in dev", () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const logger = new SentryLogger();
logger.setUser({ id: "u1", email: "a@b.c", username: "alice" } as unknown as { id: string });
expect(Sentry.setUser).toHaveBeenCalledWith({ id: "u1" });
expect(warn).toHaveBeenCalled();
warn.mockRestore();
});
it("setUser passes null through", () => {
const logger = new SentryLogger();
logger.setUser(null);
expect(Sentry.setUser).toHaveBeenCalledWith(null);
});
});

View File

@@ -1,45 +0,0 @@
// packages/core-shared/src/instrumentation/sentry/sentry-logger.ts
import * as Sentry from "@sentry/nextjs";
import type { ILogger, Breadcrumb, CaptureContext } from "../logger.interface";
import { isReported, markReported } from "../reported-flag";
export class SentryLogger implements ILogger {
captureException(err: unknown, ctx?: CaptureContext): void {
if (isReported(err)) return;
Sentry.captureException(err, ctx);
markReported(err);
}
captureMessage(
msg: string,
level: "info" | "warning" | "error" = "info",
ctx?: CaptureContext,
): void {
Sentry.captureMessage(msg, { level, ...ctx });
}
addBreadcrumb(b: Breadcrumb): void {
Sentry.addBreadcrumb({
category: b.category,
message: b.message,
level: b.level,
data: b.data,
});
}
setUser(user: { id: string } | null): void {
if (user === null) {
Sentry.setUser(null);
return;
}
const { id, ...extra } = user as { id: string } & Record<string, unknown>;
if (Object.keys(extra).length > 0) {
// R36 — strip non-id keys; warn in dev for visibility
console.warn(
"[SentryLogger.setUser] stripped non-id keys for PII safety:",
Object.keys(extra),
);
}
Sentry.setUser({ id });
}
}