Skip to content

Comments

feat: distributed tracing #24055

Closed
Udit-takkar wants to merge 12 commits intomainfrom
feat/distributed-tracing
Closed

feat: distributed tracing #24055
Udit-takkar wants to merge 12 commits intomainfrom
feat/distributed-tracing

Conversation

@Udit-takkar
Copy link
Contributor

What does this PR do?

Part of #22969

Follow up:-

  • Add more logs and replace all logger with distributedTracer

Screenshot 2025-08-28 at 8 28 50 PM

Reopened PR #22186

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

@Udit-takkar Udit-takkar requested a review from a team as a code owner September 24, 2025 18:29
@Udit-takkar Udit-takkar requested a review from a team September 24, 2025 18:29
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

This change instruments distributed tracing and error-tracing across the codebase: adds TraceContext, a tracing factory, and TracedError; creates and attaches per-request trace contexts in server request handling; propagates traceContext through APIs, TRPC, booking flows, payments, webhooks, workflows, and scheduling; replaces many logger usages with tracingLogger and attaches traceId to errors/responses (X-Trace-Id header); updates numerous function/class signatures and tests; adds a UI locale key and renders trace IDs on booking errors.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title accurately and succinctly conveys the primary change of adding distributed tracing support and aligns with the scope of the extensive tracing updates presented in the diff.
Description Check ✅ Passed The description clearly ties the PR to the overarching distributed tracing issue, outlines the high-level intent and follow-up tasks, and references related work, demonstrating relevance to the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/distributed-tracing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@graphite-app graphite-app bot requested a review from a team September 24, 2025 18:29
@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Sep 24, 2025
@Udit-takkar Udit-takkar marked this pull request as draft September 24, 2025 18:30
@dosubot dosubot bot added platform Anything related to our platform plan ✨ feature New feature or request labels Sep 24, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (20)
packages/features/webhooks/lib/handleWebhookScheduledTriggers.ts (1)

56-59: Fix crash on non‑JSON payloads; parse once and reuse.

JSON.parse(job.payload) will throw when payload is form-encoded (the header logic already anticipates non‑JSON). Parse once using the existing jsonParse, reuse the result for both Content‑Type and tracing, and avoid double parsing.

Apply this diff:

@@
-    const headers: Record<string, string> = {
-      "Content-Type":
-        !job.payload || jsonParse(job.payload) ? "application/json" : "application/x-www-form-urlencoded",
-    };
+    const parsedJobPayload = jsonParse(job.payload) as {
+      id?: number; // booking id
+      endTime?: string;
+      triggerEvent?: string;
+      _traceContext?: TraceContext;
+    } | null;
+
+    const headers: Record<string, string> = {
+      "Content-Type":
+        !job.payload || parsedJobPayload ? "application/json" : "application/x-www-form-urlencoded",
+    };
@@
-    const parsedJobPayload = JSON.parse(job.payload) as {
-      id: number; // booking id
-      endTime: string;
-      triggerEvent: string;
-      _traceContext?: TraceContext;
-    };
+    // parsedJobPayload is set above via jsonParse; may be null for non‑JSON payloads.

Also applies to: 74-79

packages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.ts (1)

106-114: Prisma: replace include with select (project only needed fields).

Our guideline is to avoid include and explicitly select fields to reduce payload and risk.

Apply this diff:

-  const updatedNewBooking = await prisma.booking.findUnique({
-    where: {
-      id: newTimeSlotBooking.id,
-    },
-    include: {
-      attendees: true,
-      references: true,
-    },
-  });
+  const updatedNewBooking = await prisma.booking.findUnique({
+    where: { id: newTimeSlotBooking.id },
+    select: {
+      id: true,
+      attendees: {
+        select: {
+          id: true,
+          email: true,
+          name: true,
+          timeZone: true,
+          locale: true,
+          phoneNumber: true,
+          bookingSeat: { select: { id: true } },
+        },
+      },
+      // If addVideoCallDataToEvent needs specific fields, narrow these accordingly
+      references: true,
+    },
+  });
packages/features/bookings/lib/handleWebhookTrigger.ts (1)

54-55: Include traceContext in all handleWebhookTrigger invocations

  • packages/features/bookings/lib/handleNewBooking.ts (lines 2161, 2301, 2313): add traceContext to each call
  • packages/features/bookings/lib/handleSeats/handleSeats.ts (line 188): add traceContext
  • ensure no remaining calls to handleWebhookTrigger({…}) omit traceContext—otherwise this will break at compile time
packages/features/bookings/lib/handleNewBooking/scheduleNoShowTriggers.ts (1)

24-38: Pass traceContext to all scheduleNoShowTriggers invocations
Update each call to include the new required traceContext parameter to match its signature and avoid runtime errors:

  • packages/trpc/server/routers/loggedInViewer/connectAndJoin.handler.ts (line 239)
  • packages/features/bookings/lib/handleNewBooking/scheduleNoShowTriggers.integration-test.ts (lines 112, 144)
  • packages/features/bookings/lib/handleConfirmation.ts (line 463)
  • packages/features/bookings/lib/handleNewBooking.ts (line 2402)
packages/lib/server/getServerErrorFromUnknown.ts (1)

128-131: Return type mismatch for string causes

Function promises HttpError but returns Error. Fix to return HttpError and propagate trace info.

-  // @ts-expect-error https://github.com/tc39/proposal-error-cause
-  return new Error(cause, { cause });
+  return new HttpError({
+    statusCode: 500,
+    message: String(cause),
+    data: traceId ? { ...(tracedData ?? {}), traceId } : undefined,
+  });
packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts (1)

5-14: Remove unused logger import/variable

logger/log are no longer used; will trigger unused variable lint.

-import logger from "@calcom/lib/logger";
 import { withReporting } from "@calcom/lib/sentryWrapper";
@@
-const log = logger.getSubLogger({ prefix: ["[scheduleMandatoryReminder]"] });
packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts (1)

43-58: Prisma: use select (no include), per repo guidelines

Switch to select with the same fields. Also include id.

-  const newBooking: (Booking & { appsStatus?: AppsStatus[] }) | null = await prisma.booking.update({
+  const newBooking: (Booking & { appsStatus?: AppsStatus[] }) | null = await prisma.booking.update({
     where: {
       id: seatedBooking.id,
     },
     data: {
       startTime: evt.startTime,
       endTime: evt.endTime,
       cancellationReason: rescheduleReason,
     },
-    include: {
-      user: true,
-      references: true,
-      payment: true,
-      attendees: true,
-    },
+    select: {
+      id: true,
+      user: true,
+      references: true,
+      payment: true,
+      attendees: true,
+    },
   });
packages/features/bookings/lib/handleSeats/reschedule/rescheduleSeatedBooking.ts (2)

35-53: Use Prisma select instead of include

Project policy: “only select data you need; never use include.” Replace include with select.

   const newTimeSlotBooking = await prisma.booking.findFirst({
     where: {
       startTime: dayjs(evt.startTime).toDate(),
       eventTypeId: eventType.id,
       status: BookingStatus.ACCEPTED,
     },
     select: {
       id: true,
       uid: true,
       iCalUID: true,
       userId: true,
-      attendees: {
-        include: {
-          bookingSeat: true,
-        },
-      },
+      attendees: {
+        select: {
+          id: true,
+          name: true,
+          email: true,
+          timeZone: true,
+          locale: true,
+          bookingSeat: {
+            select: {
+              id: true,
+              referenceUid: true,
+              attendeeId: true,
+            },
+          },
+        },
+      },
       references: true,
     },
   });

55-57: Propagate traceContext to EventManager

EventManager accepts an optional traceContext. Pass it so event creation/reschedule logs/spans are linked to the current trace.

-  const eventManager = new EventManager({ ...organizerUser, credentials });
+  const eventManager = new EventManager({ ...organizerUser, credentials }, undefined, traceContext);
packages/features/bookings/lib/handleSeats/handleSeats.ts (1)

88-99: Use Prisma select instead of include

Per project guideline, switch to select.

   select: {
     uid: true,
     id: true,
-    attendees: { include: { bookingSeat: true } },
+    attendees: {
+      select: {
+        id: true,
+        email: true,
+        name: true,
+        timeZone: true,
+        bookingSeat: {
+          select: {
+            id: true,
+            referenceUid: true,
+          },
+        },
+      },
+    },
     userId: true,
     references: true,
     startTime: true,
     user: true,
     status: true,
     smsReminderNumber: true,
     endTime: true,
   },
packages/features/bookings/lib/handleNewBooking.ts (1)

520-521: Fix undefined variable: loggerWithEventDetails

loggerWithEventDetails is referenced but never defined, causing a compile-time error. Use the tracing logger instead.

-  const emailsAndSmsHandler = new BookingEmailSmsHandler({ logger: loggerWithEventDetails });
+  const emailsAndSmsHandler = new BookingEmailSmsHandler({ logger: tracingLogger });

Also remove the now-unused import createLoggerWithEventDetails at Line 115 to satisfy linting.

packages/lib/server/service/workflows.ts (1)

76-88: Don't make traceContext required here (breaks callers).

ScheduleWorkflowRemindersArgs already defines traceContext?: TraceContext. Making it required in this wrapper will break existing call sites (see handleConfirmation.ts). Keep it optional and pass through when present.

Apply this diff:

   static async scheduleWorkflowsForNewBooking({
     isNormalBookingOrFirstRecurringSlot,
     isConfirmedByDefault,
     isRescheduleEvent,
     workflows,
     traceContext,
     ...args
   }: ScheduleWorkflowRemindersArgs & {
     isConfirmedByDefault: boolean;
     isRescheduleEvent: boolean;
     isNormalBookingOrFirstRecurringSlot: boolean;
-    traceContext: TraceContext;
+    traceContext?: TraceContext;
   }) {
packages/lib/server/defaultResponder.ts (1)

64-65: Fix performance measure label: literal “$1” likely unintended.

Use operation for clarity.

Apply this diff:

-  performance.measure(`[${ok ? "OK" : "ERROR"}][$1] ${req.method} '${req.url}'`, "Start", "End");
+  performance.measure(`[${ok ? "OK" : "ERROR"}][${operation}] ${req.method} '${req.url}'`, "Start", "End");
packages/features/bookings/lib/handleConfirmation.ts (4)

76-105: Guard createSpan when parent traceContext is absent.

Calling createSpan with undefined may break. Fall back to a new trace with the same metadata.

Apply this diff:

-  const spanContext = distributedTracing.createSpan(traceContext, "handle_confirmation", confirmationMeta);
+  const spanContext = traceContext
+    ? distributedTracing.createSpan(traceContext, "handle_confirmation", confirmationMeta)
+    : distributedTracing.createTrace("handle_confirmation", { meta: confirmationMeta });

108-111: Pass spanContext into EventManager.

Constructor now supports tracing; propagate it for calendar event spans.

Apply this diff:

-  const eventManager = new EventManager(user, apps);
+  const eventManager = new EventManager(user, apps, spanContext);

383-391: Missing traceContext when scheduling workflow reminders.

WorkflowService.scheduleWorkflowsForNewBooking now expects/accepts traceContext. Pass spanContext to keep the chain.

Apply this diff:

   await WorkflowService.scheduleWorkflowsForNewBooking({
     workflows,
     smsReminderNumber: updatedBookings[index].smsReminderNumber,
     calendarEvent: evtOfBooking,
     hideBranding: !!updatedBookings[index].eventType?.owner?.hideBranding,
     isConfirmedByDefault: true,
     isNormalBookingOrFirstRecurringSlot: isFirstBooking,
     isRescheduleEvent: false,
+    traceContext: spanContext,
   });

607-609: Use the tracing logger (and fix undefined log).

log isn’t defined in this file, and we should leverage tracingLogger for consistency.

Apply this diff:

-        log.error("Error while scheduling workflow reminders for booking paid", safeStringify(error));
+        tracingLogger.error("Error while scheduling workflow reminders for booking paid", {
+          error: safeStringify(error),
+        });
packages/app-store/paypal/api/webhook.ts (1)

178-225: Bug: credentials fallback masks errors and proceeds with empty secrets

findPaymentCredentials returns an object with empty strings on error. Upstream if (!foundCredentials) never triggers, and webhook verification proceeds with empty credentials. Return null on error and keep the upstream guard effective. Also avoid raw console.error.

-export const findPaymentCredentials = async (
-  bookingId: number
-): Promise<{ clientId: string; secretKey: string; webhookId: string }> => {
+export const findPaymentCredentials = async (
+  bookingId: number
+): Promise<{ clientId: string; secretKey: string; webhookId: string } | null> => {
   try {
     // @TODO: what about team bookings with paypal?
     const userFromBooking = await prisma.booking.findFirst({
@@
   } catch (err) {
-    console.error(err);
-    return {
-      clientId: "",
-      secretKey: "",
-      webhookId: "",
-    };
+    // Intentionally do not log secrets; let caller handle logging with trace context
+    return null;
   }
 };

No upstream change needed beyond ensuring the existing guard remains before destructuring:

const foundCredentials = await findPaymentCredentials(booking.id);
if (!foundCredentials) throw new HttpCode({ statusCode: 204, message: "No credentials found" });
const { webhookId, ...credentials } = foundCredentials;
packages/features/webhooks/lib/scheduleTrigger.ts (1)

306-314: Bug: instrumented payload is computed but not used (variable shadowing)

You compute payload with trace injection, then re-declare payload inside try, dropping the trace. Use the previously computed value.

-  const payloadData = { triggerEvent, ...booking };
-  const payload = JSON.stringify(
-    spanContext ? distributedTracing.injectTraceIntoPayload(payloadData, spanContext) : payloadData
-  );
+  const payloadData = { triggerEvent, ...booking };
+  const payload = JSON.stringify(
+    spanContext ? distributedTracing.injectTraceIntoPayload(payloadData, spanContext) : payloadData
+  );
@@
-  try {
-    const payload = JSON.stringify({ triggerEvent, ...booking });
+  try {
     await prisma.webhookScheduledTriggers.create({
       data: {
         payload,
packages/features/ee/payments/api/webhook.ts (1)

98-102: Use Prisma select to limit fetched fields

Follow repo guideline: only select what you use (id, bookingId, data).

Apply this diff:

-  const payment = await prisma.payment.findFirst({
-    where: {
-      externalId: setupIntent.id,
-    },
-  });
+  const payment = await prisma.payment.findFirst({
+    where: {
+      externalId: setupIntent.id,
+    },
+    select: {
+      id: true,
+      bookingId: true,
+      data: true,
+    },
+  });
🧹 Nitpick comments (55)
packages/features/bookings/Booker/components/hooks/useBookings.ts (2)

343-346: Make data optional and actually leverage traceId (align with tracing goals).

  • The cast assumes data always exists; make it optional to match runtime.
  • You introduced traceId but don’t use it. At minimum, log or surface it to help users/support correlate issues.

Apply:

-      const error = err as Error & {
-        data: { rescheduleUid: string; startTime: string; attendees: string[] };
-        traceId?: string;
-      };
+      const error = err as Error & {
+        data?: { rescheduleUid: string; startTime: string; attendees: string[] };
+        traceId?: string;
+      };
+      if (error.traceId) {
+        // Prefer tracer logger; temporarily log sanitized info
+        console.error("booking error traceId:", error.traceId);
+      }

Optional: show a toast with a reference for support:

if (error.traceId) {
  showToast(`${t("something_went_wrong_on_our_end")} (${t("trace_reference_id")}: ${error.traceId})`, "error");
}

469-473: Surface a user-facing reference and use sanitized logging in onError.

Show a toast including the trace reference id (when present) and avoid dumping the raw error (may contain PII). Prefer your tracing logger when available.

-    onError: (err, _, ctx) => {
-      console.error("Error creating recurring booking", err);
-      // eslint-disable-next-line @calcom/eslint/no-scroll-into-view-embed -- It is only called when user takes an action in embed
-      bookerFormErrorRef && bookerFormErrorRef.current?.scrollIntoView({ behavior: "smooth" });
-    },
+    onError: (err) => {
+      const traced = err as Error & { traceId?: string };
+      // eslint-disable-next-line @calcom/eslint/no-scroll-into-view-embed -- It is only called when user takes an action in embed
+      bookerFormErrorRef?.current?.scrollIntoView({ behavior: "smooth" });
+      const msg = traced.traceId
+        ? `${t("something_went_wrong_on_our_end")} (${t("trace_reference_id")}: ${traced.traceId})`
+        : t("something_went_wrong_on_our_end");
+      showToast(msg, "error");
+      // Prefer distributed tracer logger; until then, log sanitized details only
+      console.error("Error creating recurring booking", { message: traced.message, traceId: traced.traceId });
+    },

Follow-up: apply the same pattern to createBookingMutation and createInstantBookingMutation for consistency.

packages/features/webhooks/lib/handleWebhookScheduledTriggers.ts (2)

64-72: Create tracing before issuing fetch; attach X-Trace-Id; use tracingLogger; add a timeout.

Right now the fetch is kicked off before tracing is constructed and errors are logged via console.error. Move the request after tracing setup, add a trace header for downstream correlation, log via tracingLogger, and prevent indefinite hangs with a timeout.

Apply this diff to remove the early fetch:

@@
-    fetchPromises.push(
-      fetch(job.subscriberUrl, {
-        method: "POST",
-        body: job.payload,
-        headers,
-      }).catch((error) => {
-        console.error(`Webhook trigger for subscriber url ${job.subscriberUrl} failed with error: ${error}`);
-      })
-    );

Then insert this block just before cleaning the finished job:

@@
+    // Add trace header if available and send request now that tracing is set up
+    const traceIdHeader = spanContext?.traceId ?? parsedJobPayload?._traceContext?.traceId;
+    if (traceIdHeader) headers["X-Trace-Id"] = traceIdHeader;
+
+    const controller = new AbortController();
+    const timeout = setTimeout(() => controller.abort("timeout"), 10_000);
+    fetchPromises.push(
+      fetch(job.subscriberUrl, {
+        method: "POST",
+        body: job.payload,
+        headers,
+        signal: controller.signal,
+      })
+        .catch((error) => {
+          tracingLogger.error("Webhook trigger failed", {
+            subscriberUrl: job.subscriberUrl,
+            error,
+          });
+        })
+        .finally(() => clearTimeout(timeout))
+    );

Note: Consider deleting the job only after a successful dispatch (2xx) to avoid silent drops on failures.

Also applies to: 94-99


24-35: Use startAfter to compute timeSinceScheduled (and select it).

endTime seems unrelated to scheduling latency. Use job.startAfter which reflects when the job became runnable.

Apply this diff:

@@
     select: {
       id: true,
       jobName: true,
       payload: true,
       subscriberUrl: true,
+      startAfter: true,
       webhook: {
         select: {
           secret: true,
         },
       },
     },
@@
-    tracingLogger.info("Executing scheduled webhook", {
+    tracingLogger.info("Executing scheduled webhook", {
       bookingId: parsedJobPayload?.id,
       triggerEvent: parsedJobPayload?.triggerEvent,
       subscriberUrl: job.subscriberUrl,
       originalTraceId: parsedJobPayload?._traceContext?.traceId,
-      timeSinceScheduled: parsedJobPayload?.endTime
-        ? Date.now() - new Date(parsedJobPayload.endTime).getTime()
-        : undefined,
+      timeSinceScheduled: Date.now() - new Date(job.startAfter).getTime(),
     });

Also applies to: 86-93

packages/lib/tracing/error.ts (1)

8-29: Harden TracedError data handling and preserve cause/prototype.

Guard against non-object error.data, set cause for better chaining, and ensure proper Error subclassing across transpilation targets.

Apply this diff:

   constructor(error: unknown, traceContext: TraceContext, additionalData?: Record<string, unknown>) {
     const message = error instanceof Error ? error.message : String(error);
     super(message);
 
+    // Ensure correct prototype when targeting ES5/ES2015
+    Object.setPrototypeOf(this, new.target.prototype);
+
     this.name = error instanceof Error ? error.name : "TracedError";
     this.traceId = traceContext.traceId;
     this.originalError = error;
 
     if (error instanceof Error && error.stack) {
       this.stack = error.stack;
     }
 
-    if (error && typeof error === "object" && "data" in error) {
-      const errorWithData = error as { data: Record<string, unknown> };
-      this.data = {
-        ...errorWithData.data,
-        ...additionalData,
-      };
+    if (error && typeof error === "object" && "data" in error) {
+      const errorWithData = error as { data?: unknown };
+      const baseData =
+        errorWithData && typeof errorWithData.data === "object" && errorWithData.data !== null
+          ? (errorWithData.data as Record<string, unknown>)
+          : undefined;
+      this.data = {
+        ...(baseData || {}),
+        ...(additionalData || {}),
+      };
     } else if (additionalData) {
       this.data = additionalData;
     }
+
+    // Preserve error cause where supported
+    try {
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      (this as any).cause = error instanceof Error ? error : (error as unknown);
+    } catch {
+      // no-op
+    }
   }
packages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.ts (1)

173-173: Prefer named export over default.

Named exports improve tree-shaking and refactors. Consider export { combineTwoSeatedBookings }; and updating imports across callers.

packages/lib/tracing/index.ts (1)

50-67: Redact sensitive/large meta in tracing logger prefixes.

Meta like request bodies can contain PII. Avoid logging them in prefixes and optionally clamp values.

Apply this diff:

   getTracingLogger(context: TraceContext) {
-    const prefixes = [
+    const prefixes = [
       "distributed-trace",
       `trace:${context.traceId}`,
       `span:${context.spanId}`,
       `op:${context.operation}`,
     ];
 
     if (context.meta) {
-      Object.entries(context.meta).forEach(([key, value]) => {
-        if (value !== undefined && value !== null) {
-          prefixes.push(`${key}:${value}`);
-        }
-      });
+      const SENSITIVE_KEYS = new Set(["body", "authorization", "password", "token", "secret"]);
+      Object.entries(context.meta).forEach(([key, value]) => {
+        if (value === undefined || value === null) return;
+        if (SENSITIVE_KEYS.has(key.toLowerCase())) return;
+        const str = String(value);
+        const trimmed = str.length > 200 ? `${str.slice(0, 200)}…` : str;
+        prefixes.push(`${key}:${trimmed}`);
+      });
     }
 
     return this.loggerInstance.getSubLogger({ prefix: prefixes });
   }
packages/lib/server/defaultResponder.test.ts (3)

10-22: Add assertion for X-Trace-Id header.

Since defaultResponder sets X-Trace-Id, assert it in tests.

Apply this diff:

   await defaultResponder(f)(req, res);
   expect(res.json).toHaveBeenCalled();
+  expect(res.setHeader).toHaveBeenCalledWith("X-Trace-Id", expect.any(String));

35-45: Also assert header in error case (NoAvailableUsersFound).

Apply this diff:

   await defaultResponder(f)(req, res);
   expect(res.status).toHaveBeenCalledWith(409);
+  expect(res.setHeader).toHaveBeenCalledWith("X-Trace-Id", expect.any(String));

45-56: Also assert header in rate limit case.

Apply this diff:

   await defaultResponder(f)(req, res);
   expect(res.status).toHaveBeenCalledWith(429);
+  expect(res.setHeader).toHaveBeenCalledWith("X-Trace-Id", expect.any(String));
packages/features/bookings/lib/handleBookingRequested.ts (1)

10-10: TraceContext added but never used; propagate it to webhooks and workflows.

Forward the trace to downstream operations for continuity and better debugging.

Apply:

@@
-import { type TraceContext } from "@calcom/lib/tracing";
+import { type TraceContext } from "@calcom/lib/tracing";
+import { distributedTracing } from "@calcom/lib/tracing/factory";
@@
-    const webhookPayload = getWebhookPayloadForBooking({
+    const rawWebhookPayload = getWebhookPayloadForBooking({
       booking,
       evt,
     });
+    const webhookPayload = distributedTracing.injectTraceIntoPayload(rawWebhookPayload, args.traceContext);
@@
-      await WorkflowService.scheduleWorkflowsFilteredByTriggerEvent({
+      await WorkflowService.scheduleWorkflowsFilteredByTriggerEvent({
         workflows,
         smsReminderNumber: booking.smsReminderNumber,
         hideBranding: !!booking.eventType?.owner?.hideBranding,
         calendarEvent: {
           ...evt,
@@
         },
         triggers: [WorkflowTriggerEvents.BOOKING_REQUESTED],
+        traceContext: args.traceContext,
       });

Also applies to: 58-59

packages/features/bookings/lib/handleWebhookTrigger.ts (2)

16-17: Make traceContext optional or remove fallback.

You typed traceContext as required but still branch on its absence. Either make it optional or drop the fallback.

Apply:

-  traceContext: TraceContext;
+  traceContext?: TraceContext;

No other code changes needed since you already handle the optional case.

Also applies to: 21-31


36-46: Log non-Event payload failures too.

Currently errors for non-Event payloads are swallowed. Add a generic log path to aid debugging.

       (e) => {
         if (isEventPayload(args.webhookData)) {
           tracingLogger.error(
             `Error executing webhook for event: ${args.eventTrigger}, URL: ${sub.subscriberUrl}, booking id: ${args.webhookData.bookingId}, booking uid: ${args.webhookData.uid}`,
             safeStringify(e)
           );
+        } else {
+          tracingLogger.error(
+            `Error executing webhook for event: ${args.eventTrigger}, URL: ${sub.subscriberUrl}`,
+            safeStringify(e)
+          );
         }
       }
packages/features/ee/workflows/lib/reminders/reminderScheduler.ts (1)

16-16: traceContext added but unused; either propagate or drop until needed.

To keep signal continuity, consider creating a span per workflow step and/or passing traceContext into downstream schedulers. Otherwise, remove the arg for now to avoid API surface bloat.

Example minimal propagation (only if providers accept it):

-const processWorkflowStep = async (
+const processWorkflowStep = async (
   workflow: Workflow,
   step: WorkflowStep,
   {
     smsReminderNumber,
     calendarEvent,
     emailAttendeeSendToOverride,
     hideBranding,
     seatReferenceUid,
-  }: ProcessWorkflowStepParams
+  }: ProcessWorkflowStepParams,
+  traceContext?: TraceContext
 ) => {
@@
-    await scheduleSMSReminder({
+    await scheduleSMSReminder({
       evt,
@@
-    });
+      traceContext,
+    });
@@
-    await scheduleEmailReminder({
+    await scheduleEmailReminder({
       evt,
@@
-    });
+      traceContext,
+    });
@@
-    await scheduleWhatsappReminder({
+    await scheduleWhatsappReminder({
       evt,
@@
-    });
+      traceContext,
+    });

And thread args.traceContext through calls to processWorkflowStep in _scheduleWorkflowReminders/_sendCancelledReminders.

Also applies to: 51-52

packages/app-store/btcpayserver/api/webhook.ts (1)

62-65: Header lookup: Node lowercases header names.

Accessing both "btcpay-sig" and "BTCPay-Sig" is redundant. Use the lowercase key only.

-    const signature = req.headers["btcpay-sig"] || req.headers["BTCPay-Sig"];
+    const signature = req.headers["btcpay-sig"];
packages/features/bookings/lib/handleNewBooking/scheduleNoShowTriggers.ts (1)

67-86: Consider propagating trace metadata to async tasks.

To keep end-to-end traceability when tasks execute later, consider including a trace reference (e.g., traceId/spanId) in the task payload/options if Tasker supports it.

Also applies to: 97-118

packages/app-store/hitpay/api/webhook.ts (2)

47-58: Initialize trace per request and return X-Trace-Id header.

Good trace initialization. Recommend setting a response header for client correlation.

Apply:

   const traceContext = distributedTracing.createTrace("hitpay_webhook_handler", {
     meta: webhookMeta,
   });
 
   const tracingLogger = distributedTracing.getTracingLogger(traceContext);
+  // Surface trace id for correlation
+  res.setHeader("X-Trace-Id", traceContext.traceId);

68-90: Scope Prisma select to only needed fields.

Avoid fetching unnecessary columns; explicitly select credentials.key.

Apply:

     const payment = await prisma.payment.findFirst({
       where: {
         externalId: obj.payment_request_id,
       },
       select: {
         id: true,
         amount: true,
         bookingId: true,
         booking: {
           select: {
             user: {
               select: {
-                credentials: {
-                  where: {
-                    type: "hitpay_payment",
-                  },
-                },
+                credentials: {
+                  where: { type: "hitpay_payment" },
+                  select: { key: true },
+                },
               },
             },
           },
         },
       },
     });
packages/app-store/alby/api/webhook.ts (3)

21-32: Per-request trace looks good; add X-Trace-Id header.

Apply:

   const traceContext = distributedTracing.createTrace("alby_webhook_handler", {
     meta: webhookMeta,
   });
 
   const tracingLogger = distributedTracing.getTracingLogger(traceContext);
+  res.setHeader("X-Trace-Id", traceContext.traceId);

42-46: Replace console.error with tracingLogger for consistency.

Apply:

-      console.error(parseHeaders.error);
+      tracingLogger.warn("Invalid webhook headers", { error: parseHeaders.error?.message });
...
-      console.error(parse.error);
+      tracingLogger.warn("Invalid webhook payload", { error: parse.error?.message });

Also applies to: 51-54


62-84: Limit Prisma select to credentials.key only.

Apply:

     const payment = await prisma.payment.findFirst({
       where: {
         uid: parsedPayload.metadata.payer_data.referenceId,
       },
       select: {
         id: true,
         amount: true,
         bookingId: true,
         booking: {
           select: {
             user: {
               select: {
-                credentials: {
-                  where: {
-                    type: "alby_payment",
-                  },
-                },
+                credentials: {
+                  where: { type: "alby_payment" },
+                  select: { key: true },
+                },
               },
             },
           },
         },
       },
     });
packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts (1)

15-22: Unused traceContext parameter.

Either use it (create a local span/logs) or underscore to silence lint until used.

Option A (minimal):

-  traceContext: TraceContext
+  _traceContext: TraceContext

Option B (instrumentation):

+import { distributedTracing } from "@calcom/lib/tracing/factory";
...
   eventManager: EventManager,
-  traceContext: TraceContext
+  traceContext: TraceContext
 ) => {
+  const spanContext = distributedTracing.createSpan(traceContext, "attendee_reschedule_seated_booking");
+  const tracingLogger = distributedTracing.getTracingLogger(spanContext);
+  tracingLogger.info("Attendee reschedule started", { newBookingId: newTimeSlotBooking?.id });
packages/features/bookings/lib/handleSeats/reschedule/owner/ownerRescheduleSeatedBooking.ts (1)

56-56: Prefer named export over default export

Promotes clearer imports/tree-shaking. Optional, can be follow-up.

Apply if/when convenient:

-const ownerRescheduleSeatedBooking = async (
+export const ownerRescheduleSeatedBooking = async (
   /* ... */
 ) => { /* ... */ };
-
-export default ownerRescheduleSeatedBooking;
packages/lib/server/getServerErrorFromUnknown.ts (1)

50-57: Consider keeping original TRPC cause for parity

Optional: include cause for consistency with other branches.

-  return new HttpError({
-    statusCode,
-    message: cause.message,
-    data: traceId ? { ...tracedData, traceId } : undefined,
-  });
+  return new HttpError({
+    statusCode,
+    message: cause.message,
+    cause,
+    data: traceId ? { ...(tracedData ?? {}), traceId } : undefined,
+  });
packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts (2)

96-102: Log structured error objects; avoid stringifying

Pre-stringifying loses structure and may double encode.

-      } catch (error) {
-        tracingLogger.error("Error while scheduling mandatory reminders", JSON.stringify({ error }));
-      }
+      } catch (error) {
+        tracingLogger.error("Error while scheduling mandatory reminders", {
+          error: error instanceof Error ? { message: error.message, stack: error.stack } : String(error),
+        });
+      }

100-102: Ditto for outer catch

Keep logs structured and consistent.

-  } catch (error) {
-    tracingLogger.error("Error while scheduling mandatory reminders", JSON.stringify({ error }));
-  }
+  } catch (error) {
+    tracingLogger.error("Error while scheduling mandatory reminders", {
+      error: error instanceof Error ? { message: error.message, stack: error.stack } : String(error),
+    });
+  }
packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts (3)

82-83: Log structured error/results; avoid stringifying

Preserve structure for observability.

-    tracingLogger.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
+    tracingLogger.error(`Booking ${organizerUser.name} failed`, { error, results });

100-103: Prefer structured debug log

Consistent with above.

-    tracingLogger.debug("Emails: Sending reschedule emails - handleSeats");
+    tracingLogger.debug("Emails: Sending reschedule emails - handleSeats", {
+      bookingId: seatedBooking.id,
+    });

116-116: Prefer named export over default export

Optional follow-up for consistency and tree-shaking.

-export default moveSeatedBookingToNewTimeSlot;
+export { moveSeatedBookingToNewTimeSlot };

Note: adjust imports at call sites accordingly.

packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)

398-399: Use tracing logger instead of console in catch

Surface failures with trace correlation.

-    await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData, traceContext });
+    await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData, traceContext });
@@
-    } catch (error) {
-      // Silently fail
-      console.error(
-        "Error while scheduling workflow reminders for BOOKING_REJECTED:",
-        error instanceof Error ? error.message : String(error)
-      );
-    }
+    } catch (error) {
+      // Silently fail but capture with trace
+      distributedTracing
+        .getTracingLogger(traceContext)
+        .error("Error while scheduling workflow reminders for BOOKING_REJECTED", {
+          error: error instanceof Error ? { message: error.message, stack: error.stack } : String(error),
+        });
+    }

Also applies to: 416-421

packages/features/bookings/lib/EventManager.ts (2)

294-304: Ensure span lifecycle and keep all logs within the trace

You create a span and a tracing logger, but:

  • The span is never explicitly ended.
  • Subsequent logs in this function still use the module-level log, losing the trace context.

Recommend scoping a local log to the tracing logger and (if your tracing API requires it) end the span in a finally block.

   public async create(event: CalendarEvent): Promise<CreateUpdateResult> {
     const spanContext = this.traceContext
       ? distributedTracing.createSpan(this.traceContext, "calendar_event_creation")
       : undefined;
-    const tracingLogger = spanContext ? distributedTracing.getTracingLogger(spanContext) : log;
+    const tracingLogger = spanContext ? distributedTracing.getTracingLogger(spanContext) : log;
+    // Use the tracing-aware logger for all logs in this method
+    const log = tracingLogger;
 
-    tracingLogger.info("EventManager.create started", {
+    log.info("EventManager.create started", {
       eventTitle: event.title,
       attendeeCount: event.attendees.length,
       integrationCount: this.calendarCredentials.length,
     });
+    // Optionally ensure span is ended if your API requires it:
+    // try { ...existing logic... } finally { if (spanContext) distributedTracing.endSpan(spanContext); }

Please confirm the correct API for ending a span (e.g., endSpan, finishSpan, etc.). If your implementation does not require explicit ending, disregard the finally suggestion.


147-152: Trace context stored but not leveraged uniformly across other operations

Constructor accepts and stores traceContext, but only create() uses it. For parity, consider instrumenting other mutating flows (reschedule, updateLocation, deleteEventsAndMeetings, etc.) with child spans/logging.

Also applies to: 181-181

packages/features/bookings/lib/handleSeats/reschedule/rescheduleSeatedBooking.ts (1)

6-8: Remove unused import

distributedTracing is imported but not used.

-import { distributedTracing } from "@calcom/lib/tracing/factory";
packages/features/bookings/lib/handleSeats/handleSeats.ts (2)

45-51: Avoid placing raw user info in trace metadata

userInfo: JSON.stringify(reqBodyUser) can contain PII. Prefer redacting or omitting user details from trace meta.

-  const seatsMeta = {
+  const seatsMeta = {
     eventTypeId: eventType.id.toString(),
-    userInfo: JSON.stringify(reqBodyUser) || "null",
+    // Avoid PII in trace meta
+    userInfo: typeof reqBodyUser === "string" ? "user_ref" : "user_ref",
     eventTypeSlug: eventType.slug || "unknown",
     bookingUid: reqBookingUid || "null",
     rescheduleUid: rescheduleUid || "null",
   };

53-58: End the span if required by your tracing API

You create a span/trace but never end it. Wrap the body in try/finally and end/finish the span if applicable.

-  const spanContext = traceContext
+  const spanContext = traceContext
     ? distributedTracing.createSpan(traceContext, "handle_seats", seatsMeta)
     : distributedTracing.createTrace("handle_seats_fallback", {
         meta: seatsMeta,
       });
-  const tracingLogger = distributedTracing.getTracingLogger(spanContext);
+  const tracingLogger = distributedTracing.getTracingLogger(spanContext);
+  // try { ... } finally { distributedTracing.endSpan?.(spanContext); }
packages/features/bookings/lib/handleNewBooking.ts (4)

1178-1180: Redact guest emails in logs

guestsRemoved will contain emails. Avoid logging raw emails.

-  tracingLogger.info("Removed guests from the booking", guestsRemoved);
+  tracingLogger.info("Removed guests from the booking", { count: guestsRemoved.length });

1702-1703: Propagate trace to EventManager (original host) during organizer-change deletion

To keep deletion operations in the same trace, pass traceContext to the EventManager constructed for the original host.

-      const originalHostEventManager = new EventManager(
-        { ...originalRescheduledBooking.user, credentials: refreshedOriginalHostCredentials },
-        apps
-      );
+      const originalHostEventManager = new EventManager(
+        { ...originalRescheduledBooking.user, credentials: refreshedOriginalHostCredentials },
+        apps,
+        traceContext
+      );

652-676: Be mindful of PII in logs

The structured log includes reqBody.user and other request details. Consider using a PII-free projection for user fields.


2268-2269: End/flush trace if applicable

You create/update a trace at the start of the handler but never close it. If your tracer requires explicit finishing/flushing, add it here (or in a finally). Otherwise, ignore.

packages/lib/server/defaultResponder.ts (1)

36-44: Set X-Trace-Id early to cover handlers that write their own response.

If the handler writes directly and ends the response, the header may be missing. Set it before invoking the handler.

Apply this diff:

   const tracedReq = req as TracedRequest;
   tracedReq.traceContext = traceContext;
+  // Ensure trace id is always present, even if handler writes directly.
+  if (!res.headersSent) {
+    res.setHeader("X-Trace-Id", traceContext.traceId);
+  }
packages/features/bookings/lib/handleNewBooking/logger.ts (1)

9-17: Optional: preserve richer metadata values.

Using .toString() turns objects/arrays into “[object Object]”. Consider JSON-stringifying non-strings and truncating.

Apply this diff:

-  const stringMeta: Record<string, string> = Object.fromEntries(
-    Object.entries(eventMeta).map(([key, value]) => [key, value?.toString() || "null"])
-  );
+  const stringMeta: Record<string, string> = Object.fromEntries(
+    Object.entries(eventMeta).map(([key, value]) => {
+      if (value == null) return [key, "null"];
+      if (typeof value === "string") return [key, value];
+      try {
+        return [key, JSON.stringify(value).slice(0, 1024)];
+      } catch {
+        return [key, String(value)];
+      }
+    })
+  );
packages/app-store/paypal/api/webhook.ts (2)

84-89: Expose trace id to clients via response header

Set X-Trace-Id so the trace can be correlated externally (e.g., in PayPal portal or logs).

   const traceContext = distributedTracing.createTrace("paypal_webhook_handler", {
     meta: webhookMeta,
   });
 
   const tracingLogger = distributedTracing.getTracingLogger(traceContext);
+  // Expose trace id for correlation
+  res.setHeader("X-Trace-Id", traceContext.traceId);

101-108: Use tracing logger instead of console.error (keeps logs correlated with trace)

Replace console.error with tracingLogger.error for structured, correlated logs.

-    if (!parseHeaders.success) {
-      console.error(parseHeaders.error);
+    if (!parseHeaders.success) {
+      tracingLogger.error("Invalid PayPal webhook headers", {
+        error: parseHeaders.error,
+      });
       throw new HttpCode({ statusCode: 400, message: "Bad Request" });
     }
-    const parse = eventSchema.safeParse(JSON.parse(bodyAsString));
-    if (!parse.success) {
-      console.error(parse.error);
+    const parse = eventSchema.safeParse(JSON.parse(bodyAsString));
+    if (!parse.success) {
+      tracingLogger.error("Invalid PayPal webhook payload", {
+        error: parse.error,
+      });
       throw new HttpCode({ statusCode: 400, message: "Bad Request" });
     }
packages/features/bookings/lib/handleNewBooking/validateEventLength.ts (1)

25-41: Ensure meta values are strings (avoid undefined in meta payload)

JSON.stringify(eventTypeMultipleDuration) can yield undefined. Coerce to a string to satisfy Record<string, string>.

-  const spanContext = traceContext
-    ? distributedTracing.createSpan(traceContext, "validate_event_length", {
-        reqBodyStart,
-        reqBodyEnd,
-        eventTypeMultipleDuration: JSON.stringify(eventTypeMultipleDuration),
-        eventTypeLength: eventTypeLength.toString(),
-      })
-    : distributedTracing.createTrace("validate_event_length_fallback", {
-        meta: {
-          reqBodyStart,
-          reqBodyEnd,
-          eventTypeMultipleDuration: JSON.stringify(eventTypeMultipleDuration),
-          eventTypeLength: eventTypeLength.toString(),
-        },
-      });
+  const spanContext = traceContext
+    ? distributedTracing.createSpan(traceContext, "validate_event_length", {
+        reqBodyStart,
+        reqBodyEnd,
+        eventTypeMultipleDuration: JSON.stringify(eventTypeMultipleDuration ?? []),
+        eventTypeLength: String(eventTypeLength),
+      })
+    : distributedTracing.createTrace("validate_event_length_fallback", {
+        meta: {
+          reqBodyStart,
+          reqBodyEnd,
+          eventTypeMultipleDuration: JSON.stringify(eventTypeMultipleDuration ?? []),
+          eventTypeLength: String(eventTypeLength),
+        },
+      });
packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (2)

206-213: Prefer warn for expected validation failures to reduce noise

These are common, non-exceptional conditions. Consider warn to keep error logs actionable.

-      tracingLogger.error(`Booking outside restriction schedule availability.`, piiFreeInputDataForLogging);
+      tracingLogger.warn(`Booking outside restriction schedule availability.`, piiFreeInputDataForLogging);

220-223: Avoid logging large blobs at debug without bounds

JSON.stringify({ bufferedBusyTimes, dateRanges, ... }) can be large. Consider truncating or summarizing to avoid log bloat.

packages/features/bookings/lib/handleNewBooking/validateBookingTimeIsNotOutOfBounds.ts (1)

55-56: Prefer structured logging over stringified Error

JSON.stringify(error) often yields {}. Log fields explicitly for better observability.

-      traceLogger.info(`Booking eventType ${eventType.id} failed`, JSON.stringify({ error }));
+      traceLogger.info("Booking validation failed (date in past)", {
+        eventTypeId: eventType.id,
+        message: error.message,
+        name: error.name,
+      });
packages/features/webhooks/lib/scheduleTrigger.ts (3)

293-305: Create span meta and resolve TODO

Attach minimal meta (bookingId, triggerEvent) to the span; also resolve the TODO or track it.

-  // TODO: check this
-  const spanContext = traceContext
-    ? distributedTracing.createSpan(traceContext, "webhook_scheduling")
-    : undefined;
+  // Span for scheduling; attaches key identifiers
+  const spanContext = traceContext
+    ? distributedTracing.createSpan(traceContext, "webhook_scheduling", {
+        bookingId: String(booking.id),
+        triggerEvent,
+      })
+    : undefined;

Happy to open a follow-up issue to track remaining TODOs.


333-334: Use tracer-aware logger instead of console.error and fix message

Prefer tracingLogger.error (or log.error when no trace) and correct the message to reflect scheduling, not cancelling.

-    console.error("Error cancelling scheduled jobs", error);
+    if (spanContext) {
+      distributedTracing.getTracingLogger(spanContext).error("Error scheduling webhook trigger", { error });
+    } else {
+      log.error("Error scheduling webhook trigger", safeStringify(error));
+    }

74-95: Prisma: replace include with select to limit fetched data

Per guidelines, avoid include. Refactor to select only necessary fields.

-      const bookings = await prisma.booking.findMany({
+      const bookings = await prisma.booking.findMany({
         where: {
           ...where,
           startTime: {
             gte: new Date(),
           },
           status: BookingStatus.ACCEPTED,
         },
-        include: {
-          eventType: {
-            select: {
-              bookingFields: true,
-            },
-          },
-          attendees: {
-            select: {
-              name: true,
-              email: true,
-            },
-          },
-        },
+        select: {
+          id: true,
+          title: true,
+          description: true,
+          customInputs: true,
+          responses: true,
+          startTime: true,
+          endTime: true,
+          location: true,
+          status: true,
+          eventType: {
+            select: {
+              bookingFields: true,
+            },
+          },
+          attendees: {
+            select: {
+              name: true,
+              email: true,
+            },
+          },
+        },
       });
packages/features/ee/payments/api/webhook.ts (5)

55-63: Add idempotency guard to avoid reprocessing already successful payments

Select the success flag and short-circuit if already processed.

Apply this diff:

   const payment = await prisma.payment.findFirst({
     where:
     {
       externalId: paymentIntent.id,
     },
     select: {
       id: true,
       bookingId: true,
+      success: true,
     },
   });

+  if (payment?.success) {
+    tracingLogger.info("Stripe: Payment already processed", {
+      paymentId: payment.id,
+      bookingId: payment.bookingId,
+      paymentIntentId: paymentIntent.id,
+    });
+    return;
+  }

134-141: Propagate trace to EventManager (if supported)

To keep spans connected, pass spanContext to EventManager constructor if it accepts it.

Proposed change:

-    const eventManager = new EventManager({ ...user, credentials: allCredentials }, metadata?.apps);
+    const eventManager = new EventManager(
+      { ...user, credentials: allCredentials },
+      metadata?.apps,
+      spanContext
+    );

Please confirm EventManager’s constructor supports an optional TraceContext as the third parameter.


192-203: Return X-Trace-Id header for clients

Expose traceId for correlation in responses.

Apply this diff:

   const traceContext = distributedTracing.createTrace("stripe_webhook_handler", {
     meta: webhookMeta,
   });

   const tracingLogger = distributedTracing.getTracingLogger(traceContext);
+  res.setHeader("X-Trace-Id", traceContext.traceId);

208-219: Guard stripe-signature header type

constructEvent expects a string; enforce type to avoid runtime errors if header is an array.

Apply this diff:

-    const sig = req.headers["stripe-signature"];
-    if (!sig) {
+    const sigHeader = req.headers["stripe-signature"];
+    if (!sigHeader || typeof sigHeader !== "string") {
       throw new HttpCode({ statusCode: 400, message: "Missing stripe-signature" });
     }
@@
-    const event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_WEBHOOK_SECRET);
+    const event = stripe.webhooks.constructEvent(payload, sigHeader, process.env.STRIPE_WEBHOOK_SECRET);

245-249: Use log level based on statusCode; avoid error logs for 2xx/4xx control-flow

Prevents noisy “errors” for 202/204 paths and keeps severity meaningful.

Apply this diff:

-    tracingLogger.error("Webhook Error", {
-      message: err.message,
-      statusCode: err.statusCode,
-      stack: IS_PRODUCTION ? undefined : err.stack,
-    });
+    const statusCode = err instanceof HttpCode ? err.statusCode : 500;
+    const logMethod = statusCode >= 500 ? "error" : statusCode >= 400 ? "warn" : "info";
+    tracingLogger[logMethod]("Webhook Handler Result", {
+      message: err.message,
+      statusCode,
+      stack: IS_PRODUCTION ? undefined : err.stack,
+    });

@vercel
Copy link

vercel bot commented Oct 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Oct 24, 2025 7:55pm
cal-eu Ignored Ignored Oct 24, 2025 7:55pm

@Udit-takkar Udit-takkar added the High priority Created by Linear-GitHub Sync label Oct 3, 2025
@Udit-takkar Udit-takkar marked this pull request as ready for review October 3, 2025 11:46
@Udit-takkar Udit-takkar requested a review from a team as a code owner October 3, 2025 11:46
@Udit-takkar Udit-takkar added this to the v5.8 milestone Oct 3, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/features/bookings/lib/handleSeats/handleSeats.ts (1)

88-92: Replace include with select in Prisma query.

The query uses include: { bookingSeat: true } which violates the coding guideline requiring select instead of include for Prisma queries.

As per coding guidelines

Apply this diff to fix the issue:

     select: {
       uid: true,
       id: true,
-      attendees: { include: { bookingSeat: true } },
+      attendees: { 
+        select: {
+          id: true,
+          email: true,
+          name: true,
+          timeZone: true,
+          locale: true,
+          bookingSeat: {
+            select: {
+              id: true,
+              referenceUid: true,
+              bookingId: true,
+              attendeeId: true,
+              data: true,
+            }
+          }
+        }
+      },
       userId: true,

Note: Adjust the selected fields in bookingSeat based on what's actually needed downstream in the code.

packages/features/ee/payments/api/webhook.ts (1)

133-140: Pass spanContext to EventManager for trace continuity.

The EventManager is instantiated without the spanContext parameter at line 134. Based on the changes in this PR (see line 8 import and the pattern used in handlePaymentSuccess from relevant code snippets), EventManager should receive the span context to maintain distributed tracing continuity.

Apply this diff:

   if (!requiresConfirmation) {
-    const eventManager = new EventManager({ ...user, credentials: allCredentials }, metadata?.apps);
+    const eventManager = new EventManager({ ...user, credentials: allCredentials }, metadata?.apps, spanContext);
     const scheduleResult = areCalendarEventsEnabled
       ? await eventManager.create(evt)
       : placeholderCreatedEvent;
♻️ Duplicate comments (3)
packages/app-store/_utils/payments/handlePaymentSuccess.ts (1)

19-33: Allow starting a trace when none is provided.

Requiring callers to pass a TraceContext leaves no path for fresh payment-success flows (queue jobs, tests, legacy callers) to emit traces; they’ll either skip tracing entirely or fail at runtime. Please keep the parameter optional and fall back to creating a new trace, as previously suggested.

-export async function handlePaymentSuccess(paymentId: number, bookingId: number, traceContext: TraceContext) {
+export async function handlePaymentSuccess(
+  paymentId: number,
+  bookingId: number,
+  traceContext?: TraceContext
+) {
   const paymentMeta = {
     paymentId: paymentId.toString(),
     bookingId: bookingId.toString(),
   };

-  const spanContext = distributedTracing.createSpan(traceContext, "payment_success_processing", paymentMeta);
+  const spanContext = traceContext
+    ? distributedTracing.createSpan(traceContext, "payment_success_processing", paymentMeta)
+    : distributedTracing.createTrace("payment_success_processing", { meta: paymentMeta });
   const tracingLogger = distributedTracing.getTracingLogger(spanContext);

   tracingLogger.info("Processing payment success", {
     paymentId,
     bookingId,
-    originalTraceId: traceContext.traceId,
+    traceId: spanContext.traceId,
   });
packages/features/ee/payments/api/webhook.ts (1)

63-71: Remove the redundant duplicate check.

Line 71 contains a duplicate if (!payment?.bookingId) check that is already handled in lines 63-70. This is dead code and should be removed.

Apply this diff:

   if (!payment?.bookingId) {
     tracingLogger.error("Stripe: Payment Not Found", {
       paymentIntentId: paymentIntent.id,
       paymentId: payment?.id,
       bookingId: payment?.bookingId,
     });
     throw new HttpCode({ statusCode: 204, message: "Payment not found" });
   }
-  if (!payment?.bookingId) throw new HttpCode({ statusCode: 204, message: "Payment not found" });
packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (1)

61-61: Parameter change from Logger to TraceContext is correct.

The internal parameter change from loggerWithEventDetails: Logger<unknown> to traceContext: TraceContext is correct for the distributed tracing refactor. The public signature remains unchanged due to the withReporting wrapper.

Note: A past review comment already flagged that a caller at packages/trpc/server/routers/viewer/teams/roundRobin/getRoundRobinHostsToReasign.handler.ts:141 is passing a Logger instead of TraceContext. That issue should be addressed separately.

🧹 Nitpick comments (2)
packages/features/ee/round-robin/roundRobinReassignment.ts (1)

399-402: Add error handling for event deletion.

The deleteEventsAndMeetings call lacks error handling. If deletion fails (e.g., due to network issues, credential problems, or calendar API errors), the system could proceed to create new events, leaving orphaned calendar entries for the original organizer.

Consider wrapping the deletion in a try-catch block and logging failures:

+    try {
       await originalHostEventManager.deleteEventsAndMeetings({
         event: deletionEvent,
         bookingReferences: booking.references,
       });
+    } catch (error) {
+      roundRobinReassignLogger.error(
+        `Failed to delete events for original organizer ${originalOrganizer.id}`,
+        error
+      );
+      // Consider whether to throw or continue based on business requirements
+    }
packages/features/bookings/lib/handleConfirmation.ts (1)

19-19: Remove unused logger import.

After replacing all logger calls with tracingLogger, this import is no longer used and should be removed.

Apply this diff to remove the unused import:

-import logger from "@calcom/lib/logger";
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between abb1d8f and 9fe7fe1.

📒 Files selected for processing (12)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • apps/web/test/lib/confirm.handler.test.ts (2 hunks)
  • packages/app-store/_utils/payments/handlePaymentSuccess.ts (4 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookings.ts (2 hunks)
  • packages/features/bookings/lib/BookingEmailSmsHandler.ts (1 hunks)
  • packages/features/bookings/lib/handleConfirmation.ts (12 hunks)
  • packages/features/bookings/lib/handleNewBooking.ts (48 hunks)
  • packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (8 hunks)
  • packages/features/bookings/lib/handleSeats/handleSeats.ts (6 hunks)
  • packages/features/bookings/lib/handleWebhookTrigger.ts (3 hunks)
  • packages/features/ee/payments/api/webhook.ts (7 hunks)
  • packages/features/ee/round-robin/roundRobinReassignment.ts (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/features/bookings/lib/BookingEmailSmsHandler.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/public/static/locales/en/common.json
  • packages/features/bookings/lib/handleWebhookTrigger.ts
  • packages/features/bookings/Booker/components/hooks/useBookings.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • apps/web/test/lib/confirm.handler.test.ts
  • packages/features/bookings/lib/handleConfirmation.ts
  • packages/features/bookings/lib/handleSeats/handleSeats.ts
  • packages/features/ee/round-robin/roundRobinReassignment.ts
  • packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/ee/payments/api/webhook.ts
  • packages/app-store/_utils/payments/handlePaymentSuccess.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • apps/web/test/lib/confirm.handler.test.ts
  • packages/features/bookings/lib/handleConfirmation.ts
  • packages/features/bookings/lib/handleSeats/handleSeats.ts
  • packages/features/ee/round-robin/roundRobinReassignment.ts
  • packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/ee/payments/api/webhook.ts
  • packages/app-store/_utils/payments/handlePaymentSuccess.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • apps/web/test/lib/confirm.handler.test.ts
  • packages/features/bookings/lib/handleConfirmation.ts
  • packages/features/bookings/lib/handleSeats/handleSeats.ts
  • packages/features/ee/round-robin/roundRobinReassignment.ts
  • packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts
  • packages/features/bookings/lib/handleNewBooking.ts
  • packages/features/ee/payments/api/webhook.ts
  • packages/app-store/_utils/payments/handlePaymentSuccess.ts
🧠 Learnings (2)
📚 Learning: 2025-08-21T13:55:23.470Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/service/FormWebhookService.ts:0-0
Timestamp: 2025-08-21T13:55:23.470Z
Learning: In the new webhook architecture for Cal.com, schedulePayload is considered legacy code that doesn't fit the clean architecture. The new architecture keeps webhook scheduling logic within the Service layer, specifically through a new method WebhookService.scheduleDelayedWebhooks, rather than using the old centralized schedulePayload helper.

Applied to files:

  • packages/features/bookings/lib/handleConfirmation.ts
📚 Learning: 2025-09-03T09:52:51.182Z
Learnt from: hariombalhara
PR: calcom/cal.com#23541
File: packages/features/bookings/lib/di/modules/RegularBookingServiceModule.ts:22-28
Timestamp: 2025-09-03T09:52:51.182Z
Learning: The IBookingServiceDependencies interface in packages/features/bookings/lib/handleNewBooking.ts contains 6 properties: cacheService, checkBookingAndDurationLimitsService, prismaClient, bookingRepository, featuresRepository, and checkBookingLimitsService. This interface is used by RegularBookingService and matches the depsMap structure in RegularBookingServiceModule.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking.ts
🧬 Code graph analysis (8)
apps/web/test/lib/confirm.handler.test.ts (1)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/handleConfirmation.ts (2)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/handleSeats/handleSeats.ts (4)
packages/features/bookings/lib/handleSeats/types.d.ts (1)
  • NewSeatedBookingObject (25-61)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/handleWebhookTrigger.ts (1)
  • handleWebhookTrigger (53-53)
packages/features/ee/round-robin/roundRobinReassignment.ts (2)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (1)
  • ensureAvailableUsers (260-260)
packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (2)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/handleNewBooking.ts (5)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/BookingEmailSmsHandler.ts (1)
  • BookingEmailSmsHandler (95-325)
packages/lib/http-error.ts (1)
  • HttpError (1-45)
packages/features/bookings/lib/EventManager.ts (1)
  • EventManager (136-1328)
packages/features/ee/payments/api/webhook.ts (3)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/app-store/_utils/payments/handlePaymentSuccess.ts (1)
  • handlePaymentSuccess (19-135)
packages/app-store/_utils/payments/handlePaymentSuccess.ts (4)
packages/lib/tracing/index.ts (1)
  • TraceContext (3-10)
packages/lib/tracing/factory.ts (1)
  • distributedTracing (14-14)
packages/features/bookings/lib/EventManager.ts (1)
  • EventManager (136-1328)
packages/features/bookings/lib/handleBookingRequested.ts (1)
  • handleBookingRequested (22-128)
🔇 Additional comments (31)
packages/features/bookings/lib/handleSeats/handleSeats.ts (6)

8-9: LGTM!

The tracing imports are correctly added and align with the distributed tracing infrastructure.


18-20: LGTM!

The function signature correctly extends NewSeatedBookingObject with an optional traceContext parameter, maintaining backward compatibility while enabling distributed tracing.


45-70: LGTM!

The trace context initialization is well-structured:

  • Comprehensive metadata collection in seatsMeta
  • Proper conditional logic for span vs. trace creation
  • Informative initial log with relevant booking context

123-129: LGTM!

The spanContext is correctly propagated to rescheduleSeatedBooking, maintaining the trace across the reschedule flow.


141-167: LGTM!

The workflow scheduling correctly propagates the spanContext as traceContext and uses the tracingLogger for error logging, ensuring proper trace continuity.


189-195: LGTM!

The webhook trigger correctly receives the spanContext as traceContext, ensuring the distributed trace propagates through the webhook flow.

packages/features/ee/payments/api/webhook.ts (3)

73-73: Verify handlePaymentSuccess doesn't throw 2xx status codes.

Based on the relevant code snippets, handlePaymentSuccess throws new HttpCode({ statusCode: 200 }) at the end of successful processing. This would be caught by the catch block (lines 242-254) and logged as an error, which is incorrect for successful flows.

The handlePaymentSuccess function should return normally instead of throwing a 200 status code. Consider updating packages/app-store/_utils/payments/handlePaymentSuccess.ts to return a success result rather than throwing:

// Instead of:
throw new HttpCode({ statusCode: 200, message: `Booking with id '${booking.id}' was paid and confirmed.` });

// Do:
return { success: true, bookingId: booking.id, message: `Booking with id '${booking.id}' was paid and confirmed.` };

Based on previous review comments.


178-178: LGTM!

The WebhookHandler type correctly reflects the updated signature with optional traceContext parameter, maintaining consistency across all webhook handlers.


191-258: LGTM!

The webhook handler correctly implements distributed tracing at the entry point:

  • Creates a trace context with relevant metadata
  • Propagates the trace context to downstream handlers
  • Uses the tracing logger for all log statements
  • Conditionally includes stack traces in error logs based on environment

The implementation maintains trace continuity throughout the webhook processing flow.

packages/features/ee/round-robin/roundRobinReassignment.ts (1)

151-166: LGTM! Trace context integration looks correct.

The distributed tracing integration is well-implemented:

  • Creates a properly named trace context with relevant metadata
  • Provides a safe fallback for bookingUid
  • Correctly passes the context to ensureAvailableUsers, which is wrapped with withReporting for trace propagation
packages/features/bookings/lib/handleNewBooking/ensureAvailableUsers.ts (4)

6-6: LGTM! Import reordering and new tracing imports.

The import changes correctly support the distributed tracing refactor. No issues.

Also applies to: 13-14


65-65: LGTM! TracingLogger initialization.

The tracingLogger is correctly initialized using distributedTracing.getTracingLogger(traceContext), following the standard pattern for distributed tracing.


166-166: LGTM! All logging calls updated to tracingLogger.

All logging calls within _ensureAvailableUsers have been correctly updated to use tracingLogger instead of the previous logger, enabling distributed tracing throughout the availability checking process.

Also applies to: 175-175, 205-205, 209-209, 218-218, 224-224, 233-233, 247-247, 252-252


260-260: LGTM! Public signature unchanged.

The public ensureAvailableUsers export correctly wraps the internal _ensureAvailableUsers with withReporting, maintaining backward compatibility while enabling distributed tracing internally.

packages/features/bookings/lib/handleNewBooking.ts (11)

27-29: LGTM! Import changes for distributed tracing.

The added imports for TraceContext and distributedTracing correctly support the distributed tracing integration. Import reordering has no functional impact.

Also applies to: 69-70


405-405: LGTM! Optional traceContext parameter added.

The optional traceContext parameter in BookingHandlerInput enables distributed tracing while maintaining backward compatibility with existing callers.


443-443: LGTM! Trace context creation with safe metadata.

The trace context is correctly created or updated with non-PII metadata (eventTypeId, userId, eventTypeSlug). The tracingLogger is properly initialized from the traceContext.

Note: A past review comment flagged PII concerns with a userInfo field in trace meta, but that field is not present in the current code. The current implementation correctly excludes PII from trace metadata.

Also applies to: 449-462


464-469: LGTM! Initial booking creation logging.

The initial logging statement correctly uses tracingLogger.info with appropriate non-PII context data.


537-537: LGTM! TraceId included in HttpError responses.

Including traceId in error data enables end-to-end tracing and helps with debugging by correlating client-side errors with server-side logs.

Also applies to: 547-547, 565-565, 572-572, 717-717, 1712-1712, 1957-1957, 2155-2155


518-518: LGTM! BookingEmailSmsHandler uses tracingLogger.

The BookingEmailSmsHandler is correctly initialized with tracingLogger, enabling traced logging for email/SMS operations.


687-687: LGTM! TraceContext propagated to validation functions.

The traceContext is correctly passed to validateBookingTimeIsNotOutOfBounds and validateEventLength, enabling distributed tracing through the validation layer.

Also applies to: 695-695


852-852: LGTM! TraceContext propagated to ensureAvailableUsers.

All calls to ensureAvailableUsers correctly include the traceContext parameter, enabling distributed tracing throughout user availability verification.

Also applies to: 867-867, 886-886, 915-915, 1027-1027


1723-1723: LGTM! TraceContext passed to EventManager.

The EventManager is correctly instantiated with traceContext, enabling distributed tracing for calendar event creation and management operations.


2197-2197: LGTM! TraceContext propagated to webhook, workflow, and scheduling functions.

The traceContext is correctly passed to all webhook, workflow, and scheduling functions (handleWebhookTrigger, scheduleTrigger, scheduleMandatoryReminder, WorkflowService.scheduleWorkflowsForNewBooking, scheduleNoShowTriggers), enabling end-to-end distributed tracing across the entire booking lifecycle.

Also applies to: 2294-2294, 2307-2307, 2334-2334, 2346-2346, 2407-2407, 2422-2422, 2443-2443


652-652: LGTM! Comprehensive tracingLogger usage throughout booking flow.

All logging calls throughout the booking handler have been correctly updated to use tracingLogger, enabling traced logging at all critical points including:

  • Event type and availability logging
  • User selection and fallback logic
  • Error conditions and warnings
  • Booking creation and updates
  • Integration results (EventManager, webhooks, workflows)
  • Payment and scheduling operations

This provides comprehensive observability for the entire booking lifecycle.

Also applies to: 744-744, 894-894, 922-922, 951-951, 1037-1037, 1102-1102, 1198-1198, 1213-1214, 1546-1546, 1707-1707, 1730-1730, 1761-1761, 1832-1832, 1855-1855, 1985-1985, 2063-2063, 2080-2080, 2125-2125, 2225-2225, 2256-2256, 2320-2320, 2356-2356, 2387-2387, 2425-2425, 2447-2447

apps/web/test/lib/confirm.handler.test.ts (2)

15-15: LGTM!

The import correctly adds the distributedTracing utility needed to create trace contexts for testing.


95-97: LGTM!

The test correctly adapts to the new traceContext requirement. The operation name and metadata are appropriate for test tracing.

packages/features/bookings/lib/handleConfirmation.ts (4)

4-5: LGTM!

The imports correctly add the necessary distributed tracing types and utilities.

Also applies to: 22-23


88-104: LGTM!

The trace context setup correctly creates a child span with appropriate metadata and obtains a tracing logger. The metadata comprehensively captures the booking context for observability.


121-121: LGTM!

All logger calls have been correctly replaced with tracingLogger, ensuring proper trace context propagation in error logs. The error messages include comprehensive context for debugging.

Also applies to: 158-158, 394-394, 506-512, 569-574, 607-607, 612-612


377-377: LGTM!

The spanContext is correctly propagated to downstream async operations, enabling end-to-end trace continuity across the booking confirmation workflow.

Also applies to: 389-389, 475-475

@Udit-takkar Udit-takkar marked this pull request as ready for review October 24, 2025 14:56
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

11 issues found across 47 files

Prompt for AI agents (all 11 issues)

Understand the root cause of the following 11 issues and fix them.


<file name="packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts">

<violation number="1" location="packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts:42">
Rule violated: **Avoid Logging Sensitive Information**

`seatReferenceUid` is being logged through the tracing meta prefixes, exposing a sensitive seat identifier. Please omit or fully redact this value before attaching it to the tracing context to comply with the &quot;Avoid Logging Sensitive Information&quot; guideline.</violation>
</file>

<file name="packages/features/bookings/lib/handleSeats/handleSeats.ts">

<violation number="1" location="packages/features/bookings/lib/handleSeats/handleSeats.ts:64">
Rule violated: **Avoid Logging Sensitive Information**

Please avoid logging raw bookerEmail values. Email addresses are PII and must not be written to logs per the &quot;Avoid Logging Sensitive Information&quot; guideline.</violation>
</file>

<file name="packages/trpc/server/createContext.ts">

<violation number="1" location="packages/trpc/server/createContext.ts:70">
Rule violated: **Avoid Logging Sensitive Information**

Storing the session `userId` in the distributed trace metadata causes every log generated via this trace logger to emit `userId:&lt;value&gt;` as part of the log prefix, exposing PII and violating the “Avoid Logging Sensitive Information” guideline.</violation>
</file>

<file name="apps/web/pages/api/book/event.ts">

<violation number="1" location="apps/web/pages/api/book/event.ts:71">
Rule violated: **Avoid Logging Sensitive Information**

Do not log `booking.uid`; it exposes the unique booking identifier and leaks sensitive booking data, violating the &quot;Avoid Logging Sensitive Information&quot; rule.</violation>
</file>

<file name="packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts">

<violation number="1" location="packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts:81">
Rule violated: **Avoid Logging Sensitive Information**

`tracingLogger.error` now logs the organizer&#39;s name, which is personally identifiable information and violates our prohibition on logging sensitive data.</violation>
</file>

<file name="packages/features/webhooks/lib/scheduleTrigger.ts">

<violation number="1" location="packages/features/webhooks/lib/scheduleTrigger.ts:309">
Rule violated: **Avoid Logging Sensitive Information**

Logging the raw subscriberUrl exposes potentially sensitive webhook endpoints (e.g., tokens in the URL), which violates our &quot;Avoid Logging Sensitive Information&quot; rule. Please redact or omit this value before logging.</violation>
</file>

<file name="packages/features/bookings/lib/service/RegularBookingService.ts">

<violation number="1" location="packages/features/bookings/lib/service/RegularBookingService.ts:1282">
Rule violated: **Avoid Logging Sensitive Information**

Please avoid logging guest email addresses; this tracingLogger.info call emits raw PII and violates the Avoid Logging Sensitive Information rule for bookings.</violation>
</file>

<file name="packages/features/bookings/lib/handleNewBooking/validateEventLength.ts">

<violation number="1" location="packages/features/bookings/lib/handleNewBooking/validateEventLength.ts:27">
Rule violated: **Avoid Logging Sensitive Information**

Adding reqBodyStart/reqBodyEnd to the tracing metadata stores users’ scheduling timestamps in our logs, which violates the “Avoid Logging Sensitive Information” rule. Please remove these fields or replace them with non-sensitive aggregates before emitting the span.</violation>
</file>

<file name="packages/features/webhooks/lib/handleWebhookScheduledTriggers.ts">

<violation number="1" location="packages/features/webhooks/lib/handleWebhookScheduledTriggers.ts:89">
Rule violated: **Avoid Logging Sensitive Information**

The new tracing log writes the full webhook subscriberUrl, which commonly contains embedded secret tokens. Exposing that URL in logs leaks credentials and breaks the &quot;Avoid Logging Sensitive Information&quot; rule.</violation>
</file>

<file name="packages/lib/server/defaultResponder.ts">

<violation number="1" location="packages/lib/server/defaultResponder.ts:24">
Using optional chaining only on the first replace means that when endpointRoute is undefined (as in many defaultResponder usages), this line tries to call .replace on undefined and the request crashes. Please guard the second replace as well.</violation>
</file>

<file name="packages/features/bookings/lib/EventManager.ts">

<violation number="1" location="packages/features/bookings/lib/EventManager.ts:299">
Logging the raw `event.title` exposes PII in traces. Please sanitize the title (e.g., via `getPiiFreeCalendarEvent(event).title`) before writing it to the log.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

organizerId: evt.organizer.id?.toString() || "unknown",
requiresConfirmation: String(requiresConfirmation),
hideBranding: String(hideBranding),
seatReferenceUid: seatReferenceUid || "null",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

seatReferenceUid is being logged through the tracing meta prefixes, exposing a sensitive seat identifier. Please omit or fully redact this value before attaching it to the tracing context to comply with the "Avoid Logging Sensitive Information" guideline.

Prompt for AI agents
Address the following comment on packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts at line 42:

<comment>`seatReferenceUid` is being logged through the tracing meta prefixes, exposing a sensitive seat identifier. Please omit or fully redact this value before attaching it to the tracing context to comply with the &quot;Avoid Logging Sensitive Information&quot; guideline.</comment>

<file context>
@@ -28,9 +28,34 @@ async function _scheduleMandatoryReminder({
+    organizerId: evt.organizer.id?.toString() || &quot;unknown&quot;,
+    requiresConfirmation: String(requiresConfirmation),
+    hideBranding: String(hideBranding),
+    seatReferenceUid: seatReferenceUid || &quot;null&quot;,
+    isPlatformNoEmail: String(isPlatformNoEmail),
+  };
</file context>
Suggested change
seatReferenceUid: seatReferenceUid || "null",
seatReferenceUid: seatReferenceUid ? "[redacted]" : "null",
Fix with Cubic

eventTypeSlug: eventType.slug,
rescheduleUid,
reqBookingUid,
bookerEmail,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

Please avoid logging raw bookerEmail values. Email addresses are PII and must not be written to logs per the "Avoid Logging Sensitive Information" guideline.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleSeats/handleSeats.ts at line 64:

<comment>Please avoid logging raw bookerEmail values. Email addresses are PII and must not be written to logs per the &quot;Avoid Logging Sensitive Information&quot; guideline.</comment>

<file context>
@@ -34,10 +36,36 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) =&gt; {
+    eventTypeSlug: eventType.slug,
+    rescheduleUid,
+    reqBookingUid,
+    bookerEmail,
+    hasOriginalRescheduledBooking: !!originalRescheduledBooking,
+    isReschedule: !!rescheduleUid,
</file context>
Suggested change
bookerEmail,
hasBookerEmail: Boolean(bookerEmail),
Fix with Cubic

export async function createContextInner(opts: CreateInnerContextOptions): Promise<InnerContext> {
const traceContext = distributedTracing.createTrace("trpc_request", {
meta: {
userId: opts.session?.user?.id?.toString() || "anonymous",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

Storing the session userId in the distributed trace metadata causes every log generated via this trace logger to emit userId:<value> as part of the log prefix, exposing PII and violating the “Avoid Logging Sensitive Information” guideline.

Prompt for AI agents
Address the following comment on packages/trpc/server/createContext.ts at line 70:

<comment>Storing the session `userId` in the distributed trace metadata causes every log generated via this trace logger to emit `userId:&lt;value&gt;` as part of the log prefix, exposing PII and violating the “Avoid Logging Sensitive Information” guideline.</comment>

<file context>
@@ -62,10 +65,17 @@ export type InnerContext = CreateInnerContextOptions &amp; {
 export async function createContextInner(opts: CreateInnerContextOptions): Promise&lt;InnerContext&gt; {
+  const traceContext = distributedTracing.createTrace(&quot;trpc_request&quot;, {
+    meta: {
+      userId: opts.session?.user?.id?.toString() || &quot;anonymous&quot;,
+    },
+  });
</file context>
Fix with Cubic

});

tracingLogger.info("API book event request completed successfully", {
bookingUid: booking?.uid,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

Do not log booking.uid; it exposes the unique booking identifier and leaks sensitive booking data, violating the "Avoid Logging Sensitive Information" rule.

Prompt for AI agents
Address the following comment on apps/web/pages/api/book/event.ts at line 71:

<comment>Do not log `booking.uid`; it exposes the unique booking identifier and leaks sensitive booking data, violating the &quot;Avoid Logging Sensitive Information&quot; rule.</comment>

<file context>
@@ -52,8 +63,13 @@ async function handler(req: NextApiRequest &amp; { userId?: number }) {
   });
+
+  tracingLogger.info(&quot;API book event request completed successfully&quot;, {
+    bookingUid: booking?.uid,
+  });
   // const booking = await createBookingThroughFactory();
</file context>
Suggested change
bookingUid: booking?.uid,
// booking UID intentionally not logged to avoid leaking sensitive data
Fix with Cubic

message: "Booking Rescheduling failed",
};
loggerWithEventDetails.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
tracingLogger.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

tracingLogger.error now logs the organizer's name, which is personally identifiable information and violates our prohibition on logging sensitive data.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts at line 81:

<comment>`tracingLogger.error` now logs the organizer&#39;s name, which is personally identifiable information and violates our prohibition on logging sensitive data.</comment>

<file context>
@@ -70,7 +78,7 @@ const moveSeatedBookingToNewTimeSlot = async (
       message: &quot;Booking Rescheduling failed&quot;,
     };
-    loggerWithEventDetails.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
+    tracingLogger.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
   } else {
     const metadata: AdditionalInformation = {};
</file context>
Suggested change
tracingLogger.error(`Booking ${organizerUser.name} failed`, JSON.stringify({ error, results }));
tracingLogger.error("Booking rescheduling failed", JSON.stringify({ error, results }));
Fix with Cubic


if (guestsRemoved.length > 0) {
log.info("Removed guests from the booking", guestsRemoved);
tracingLogger.info("Removed guests from the booking", guestsRemoved);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

Please avoid logging guest email addresses; this tracingLogger.info call emits raw PII and violates the Avoid Logging Sensitive Information rule for bookings.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/service/RegularBookingService.ts at line 1282:

<comment>Please avoid logging guest email addresses; this tracingLogger.info call emits raw PII and violates the Avoid Logging Sensitive Information rule for bookings.</comment>

<file context>
@@ -1246,7 +1279,7 @@ async function handler(
 
   if (guestsRemoved.length &gt; 0) {
-    log.info(&quot;Removed guests from the booking&quot;, guestsRemoved);
+    tracingLogger.info(&quot;Removed guests from the booking&quot;, guestsRemoved);
   }
 
</file context>
Suggested change
tracingLogger.info("Removed guests from the booking", guestsRemoved);
tracingLogger.info("Removed guests from the booking", { count: guestsRemoved.length });
Fix with Cubic

}: Props) => {
const spanContext = traceContext
? distributedTracing.createSpan(traceContext, "validate_event_length", {
reqBodyStart,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

Adding reqBodyStart/reqBodyEnd to the tracing metadata stores users’ scheduling timestamps in our logs, which violates the “Avoid Logging Sensitive Information” rule. Please remove these fields or replace them with non-sensitive aggregates before emitting the span.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleNewBooking/validateEventLength.ts at line 27:

<comment>Adding reqBodyStart/reqBodyEnd to the tracing metadata stores users’ scheduling timestamps in our logs, which violates the “Avoid Logging Sensitive Information” rule. Please remove these fields or replace them with non-sensitive aggregates before emitting the span.</comment>

<file context>
@@ -18,8 +20,25 @@ const _validateEventLength = ({
 }: Props) =&gt; {
+  const spanContext = traceContext
+    ? distributedTracing.createSpan(traceContext, &quot;validate_event_length&quot;, {
+        reqBodyStart,
+        reqBodyEnd,
+        eventTypeMultipleDuration: JSON.stringify(eventTypeMultipleDuration),
</file context>
Fix with Cubic

tracingLogger.info("Executing scheduled webhook", {
bookingId: parsedJobPayload.id,
triggerEvent: parsedJobPayload.triggerEvent,
subscriberUrl: job.subscriberUrl,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Rule violated: Avoid Logging Sensitive Information

The new tracing log writes the full webhook subscriberUrl, which commonly contains embedded secret tokens. Exposing that URL in logs leaks credentials and breaks the "Avoid Logging Sensitive Information" rule.

Prompt for AI agents
Address the following comment on packages/features/webhooks/lib/handleWebhookScheduledTriggers.ts at line 89:

<comment>The new tracing log writes the full webhook subscriberUrl, which commonly contains embedded secret tokens. Exposing that URL in logs leaks credentials and breaks the &quot;Avoid Logging Sensitive Information&quot; rule.</comment>

<file context>
@@ -73,8 +75,24 @@ export async function handleWebhookScheduledTriggers(prisma: PrismaClient) {
+    tracingLogger.info(&quot;Executing scheduled webhook&quot;, {
+      bookingId: parsedJobPayload.id,
+      triggerEvent: parsedJobPayload.triggerEvent,
+      subscriberUrl: job.subscriberUrl,
+      originalTraceId: parsedJobPayload._traceContext?.traceId,
+      timeSinceScheduled: parsedJobPayload?.endTime
</file context>
Suggested change
subscriberUrl: job.subscriberUrl,
subscriberUrl: "[REDACTED]",
Fix with Cubic

const tracingLogger = spanContext ? distributedTracing.getTracingLogger(spanContext) : log;

tracingLogger.info("EventManager.create started", {
eventTitle: event.title,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 24, 2025

Choose a reason for hiding this comment

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

Logging the raw event.title exposes PII in traces. Please sanitize the title (e.g., via getPiiFreeCalendarEvent(event).title) before writing it to the log.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/EventManager.ts at line 299:

<comment>Logging the raw `event.title` exposes PII in traces. Please sanitize the title (e.g., via `getPiiFreeCalendarEvent(event).title`) before writing it to the log.</comment>

<file context>
@@ -282,6 +290,16 @@ export default class EventManager {
+    const tracingLogger = spanContext ? distributedTracing.getTracingLogger(spanContext) : log;
+
+    tracingLogger.info(&quot;EventManager.create started&quot;, {
+      eventTitle: event.title,
+      attendeeCount: event.attendees.length,
+      integrationCount: this.calendarCredentials.length,
</file context>
Suggested change
eventTitle: event.title,
eventTitle: getPiiFreeCalendarEvent(event).title,
Fix with Cubic

traceContext: TraceContext;
}

type Handle<T> = (req: TracedRequest, res: NextApiResponse) => Promise<T>;
Copy link
Member

Choose a reason for hiding this comment

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

nit: We could introduced TracedResponse as well. For now, it would be just an alias of NextApiResponse

import { CreationSource } from "@calcom/prisma/enums";

async function handler(req: NextApiRequest & { userId?: number }) {
async function handler(req: NextApiRequest & { userId?: number; traceContext: TraceContext }) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
async function handler(req: NextApiRequest & { userId?: number; traceContext: TraceContext }) {
async function handler(req: TracedRequest & { userId?: number}) {

},
});

tracingLogger.info("API book event request completed successfully", {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need these info logs. This could be a sudden increase in book events call and we might not need that?

Comment on lines +20 to +23
const paymentMeta = {
paymentId: paymentId.toString(),
bookingId: bookingId.toString(),
};
Copy link
Member

@hariombalhara hariombalhara Oct 27, 2025

Choose a reason for hiding this comment

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

I see this requirement of converting every prop of meta to string.

Why don't we keep the type of meta inside DistributedTracing to be number|string and handle it there.

Comment on lines +25 to +26
const spanContext = distributedTracing.createSpan(traceContext, "payment_success_processing", paymentMeta);
const tracingLogger = distributedTracing.getTracingLogger(spanContext);
Copy link
Member

@hariombalhara hariombalhara Oct 27, 2025

Choose a reason for hiding this comment

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

nit:

Suggested change
const spanContext = distributedTracing.createSpan(traceContext, "payment_success_processing", paymentMeta);
const tracingLogger = distributedTracing.getTracingLogger(spanContext);
const {tracingLogger, traceSpan} = distributedTracing.createTracingLogger({traceContext, operation, meta: { paymentId: paymentId.toString(), bookingId} );

If we have an API like this we could reduce the noise in the code a bit.

Copy link
Member

@hariombalhara hariombalhara left a comment

Choose a reason for hiding this comment

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

As discussed we are breaking it down into small reviewable PRs

@Udit-takkar
Copy link
Contributor Author

Sub PRs are merged

@Udit-takkar Udit-takkar closed this Dec 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ✨ feature New feature or request High priority Created by Linear-GitHub Sync platform Anything related to our platform plan size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants