From 19712f62e3c3261ff4013d2acf6a00f7632dcf61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Mon, 24 Mar 2025 16:01:20 -0700 Subject: [PATCH] feat: improved observability on api v1 and webapp (#20302) * feat: associate errors to users on api v1 * Added webapp * Update layout.tsx * Update captureUserId.ts --- apps/api/v1/lib/helpers/captureUserId.ts | 8 ++++++++ apps/api/v1/lib/helpers/withMiddleware.ts | 11 +++++++---- .../web/app/(use-page-wrapper)/(main-nav)/layout.tsx | 12 +++++++++++- .../trpc/server/middlewares/sessionMiddleware.ts | 3 +++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 apps/api/v1/lib/helpers/captureUserId.ts diff --git a/apps/api/v1/lib/helpers/captureUserId.ts b/apps/api/v1/lib/helpers/captureUserId.ts new file mode 100644 index 0000000000..0256bb8345 --- /dev/null +++ b/apps/api/v1/lib/helpers/captureUserId.ts @@ -0,0 +1,8 @@ +import { setUser as SentrySetUser } from "@sentry/nextjs"; +import type { NextMiddleware } from "next-api-middleware"; + +export const captureUserId: NextMiddleware = async (req, res, next) => { + if (req.userId) SentrySetUser({ id: req.userId }); + + await next(); +}; diff --git a/apps/api/v1/lib/helpers/withMiddleware.ts b/apps/api/v1/lib/helpers/withMiddleware.ts index 95b8984ee1..3b06627ccc 100644 --- a/apps/api/v1/lib/helpers/withMiddleware.ts +++ b/apps/api/v1/lib/helpers/withMiddleware.ts @@ -2,15 +2,16 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; +import { captureUserId } from "./captureUserId"; import { checkIsInMaintenanceMode } from "./checkIsInMaintenanceMode"; import { extendRequest } from "./extendRequest"; import { - HTTP_POST, HTTP_DELETE, - HTTP_PATCH, HTTP_GET, - HTTP_GET_OR_POST, HTTP_GET_DELETE_PATCH, + HTTP_GET_OR_POST, + HTTP_PATCH, + HTTP_POST, } from "./httpMethods"; import { rateLimitApiKey } from "./rateLimitApiKey"; import { verifyApiKey } from "./verifyApiKey"; @@ -31,6 +32,7 @@ const middleware = { extendRequest, pagination: withPagination, captureErrors, + captureUserId, verifyCredentialSyncEnabled, }; @@ -44,8 +46,9 @@ const middlewareOrder = [ "verifyApiKey", "rateLimitApiKey", "addRequestId", + "captureUserId", ] as Middleware[]; // <-- Provide a list of middleware to call automatically const withMiddleware = label(middleware, middlewareOrder); -export { withMiddleware, middleware, middlewareOrder }; +export { middleware, middlewareOrder, withMiddleware }; diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/layout.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/layout.tsx index a669b6edc0..e33202da76 100644 --- a/apps/web/app/(use-page-wrapper)/(main-nav)/layout.tsx +++ b/apps/web/app/(use-page-wrapper)/(main-nav)/layout.tsx @@ -1,6 +1,16 @@ +import { setUser as SentrySetUser } from "@sentry/nextjs"; +import { cookies, headers } from "next/headers"; +import React from "react"; + +import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import Shell from "@calcom/features/shell/Shell"; -const Layout = ({ children }: { children: React.ReactNode }) => { +import { buildLegacyRequest } from "@lib/buildLegacyCtx"; + +const Layout = async ({ children }: { children: React.ReactNode }) => { + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); + if (session?.user?.id) SentrySetUser({ id: session.user.id }); + return {children}; }; diff --git a/packages/trpc/server/middlewares/sessionMiddleware.ts b/packages/trpc/server/middlewares/sessionMiddleware.ts index 7148229577..5b9226fc78 100644 --- a/packages/trpc/server/middlewares/sessionMiddleware.ts +++ b/packages/trpc/server/middlewares/sessionMiddleware.ts @@ -1,3 +1,4 @@ +import { setUser as SentrySetUser } from "@sentry/nextjs"; import type { Session } from "next-auth"; import { WEBAPP_URL } from "@calcom/lib/constants"; @@ -154,6 +155,8 @@ export const isAuthed = middleware(async ({ ctx, next }) => { throw new TRPCError({ code: "UNAUTHORIZED" }); } + SentrySetUser({ id: user.id }); + return next({ ctx: { user, session }, });