From 4e1d05a7e736c0c13e0a77e380f5be1870fcb2c3 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:13:22 +0530 Subject: [PATCH] feat: dist tracing 4 (#25574) * feat: distributed tracing 2 * feat: distributed tracing 2 * refactor: feedback * refactor: feedback * fix: type error * fix: trpc error * feat: distributed tracing - 3 * chore: translation * refactor: improvements * fix: feedback * chore: remove * feat: dist tracing 4 * fix: type errors * fix: type errors * fix: remove string type * fix: type errors --- apps/web/test/lib/confirm.handler.test.ts | 2 ++ .../utils/bookingScenario/bookingScenario.ts | 4 ++- .../_utils/payments/handlePaymentSuccess.ts | 9 +++++- packages/app-store/alby/api/webhook.ts | 6 +++- .../app-store/btcpayserver/api/webhook.ts | 6 +++- packages/app-store/hitpay/api/webhook.ts | 6 +++- packages/app-store/paypal/api/webhook.ts | 6 +++- .../bookings/lib/handleConfirmation.ts | 22 ++++++++++---- .../bookings/lib/handleSeats/handleSeats.ts | 3 +- .../bookings/lib/handleSeats/types.d.ts | 2 ++ .../bookings/lib/handleWebhookTrigger.ts | 14 +++++++-- .../lib/service/RegularBookingService.ts | 5 ++++ packages/features/ee/payments/api/webhook.ts | 24 +++++++++++---- .../reminders/scheduleMandatoryReminder.ts | 29 +++++++++++++++---- .../viewer/bookings/confirm.handler.ts | 15 +++++++++- 15 files changed, 127 insertions(+), 26 deletions(-) diff --git a/apps/web/test/lib/confirm.handler.test.ts b/apps/web/test/lib/confirm.handler.test.ts index 0ef053d381..eca68e13eb 100644 --- a/apps/web/test/lib/confirm.handler.test.ts +++ b/apps/web/test/lib/confirm.handler.test.ts @@ -9,6 +9,7 @@ import { import { describe, it, beforeEach, vi, expect } from "vitest"; import * as handleConfirmationModule from "@calcom/features/bookings/lib/handleConfirmation"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { BookingStatus } from "@calcom/prisma/enums"; import { confirmHandler } from "@calcom/trpc/server/routers/viewer/bookings/confirm.handler"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; @@ -92,6 +93,7 @@ describe("confirmHandler", () => { timeZone: organizer.timeZone, username: organizer.username, } as NonNullable, + traceContext: distributedTracing.createTrace("test_confirm_handler"), }; const res = await confirmHandler({ diff --git a/apps/web/test/utils/bookingScenario/bookingScenario.ts b/apps/web/test/utils/bookingScenario/bookingScenario.ts index ad5428a659..f7deeb3b24 100644 --- a/apps/web/test/utils/bookingScenario/bookingScenario.ts +++ b/apps/web/test/utils/bookingScenario/bookingScenario.ts @@ -10,6 +10,7 @@ import type { z } from "zod"; import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; import { handleStripePaymentSuccess } from "@calcom/features/ee/payments/api/webhook"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { ProfileRepository } from "@calcom/features/profile/repositories/ProfileRepository"; import { weekdayToWeekIndex, type WeekDays } from "@calcom/lib/dayjs"; import type { HttpError } from "@calcom/lib/http-error"; @@ -2287,7 +2288,8 @@ export function getMockedStripePaymentEvent({ paymentIntentId }: { paymentIntent export async function mockPaymentSuccessWebhookFromStripe({ externalId }: { externalId: string }) { let webhookResponse = null; try { - await handleStripePaymentSuccess(getMockedStripePaymentEvent({ paymentIntentId: externalId })); + const traceContext = distributedTracing.createTrace("test_stripe_webhook"); + await handleStripePaymentSuccess(getMockedStripePaymentEvent({ paymentIntentId: externalId }), traceContext); } catch (e) { log.silly("mockPaymentSuccessWebhookFromStripe:catch", JSON.stringify(e)); webhookResponse = e as HttpError; diff --git a/packages/app-store/_utils/payments/handlePaymentSuccess.ts b/packages/app-store/_utils/payments/handlePaymentSuccess.ts index 4a5c3000e3..84d7848db3 100644 --- a/packages/app-store/_utils/payments/handlePaymentSuccess.ts +++ b/packages/app-store/_utils/payments/handlePaymentSuccess.ts @@ -10,13 +10,19 @@ import { getPlatformParams } from "@calcom/features/platform-oauth-client/get-pl import { PlatformOAuthClientRepository } from "@calcom/features/platform-oauth-client/platform-oauth-client.repository"; import { HttpError as HttpCode } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; +import type { TraceContext } from "@calcom/lib/tracing"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import { BookingStatus } from "@calcom/prisma/enums"; import type { EventTypeMetadata } from "@calcom/prisma/zod-utils"; const log = logger.getSubLogger({ prefix: ["[handlePaymentSuccess]"] }); -export async function handlePaymentSuccess(paymentId: number, bookingId: number) { +export async function handlePaymentSuccess(paymentId: number, bookingId: number, traceContext: TraceContext) { + const updatedTraceContext = distributedTracing.updateTrace(traceContext, { + bookingId, + paymentId, + }); log.debug(`handling payment success for bookingId ${bookingId}`); const { booking, user: userWithCredentials, evt, eventType } = await getBooking(bookingId); @@ -87,6 +93,7 @@ export async function handlePaymentSuccess(paymentId: number, bookingId: number) booking, paid: true, platformClientParams: platformOAuthClient ? getPlatformParams(platformOAuthClient) : undefined, + traceContext: updatedTraceContext, }); } else { await handleBookingRequested({ diff --git a/packages/app-store/alby/api/webhook.ts b/packages/app-store/alby/api/webhook.ts index a16f9af219..0cbe50fcc6 100644 --- a/packages/app-store/alby/api/webhook.ts +++ b/packages/app-store/alby/api/webhook.ts @@ -3,6 +3,7 @@ import getRawBody from "raw-body"; import { z } from "zod"; import { handlePaymentSuccess } from "@calcom/app-store/_utils/payments/handlePaymentSuccess"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { albyCredentialKeysSchema } from "@calcom/app-store/alby/lib"; import parseInvoice from "@calcom/app-store/alby/lib/parseInvoice"; import { IS_PRODUCTION } from "@calcom/lib/constants"; @@ -88,7 +89,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) throw new HttpCode({ statusCode: 400, message: "invoice amount does not match payment amount" }); } - return await handlePaymentSuccess(payment.id, payment.bookingId); + const traceContext = distributedTracing.createTrace("alby_webhook", { + meta: { paymentId: payment.id, bookingId: payment.bookingId }, + }); + return await handlePaymentSuccess(payment.id, payment.bookingId, traceContext); } catch (_err) { const err = getServerErrorFromUnknown(_err); console.error(`Webhook Error: ${err.message}`); diff --git a/packages/app-store/btcpayserver/api/webhook.ts b/packages/app-store/btcpayserver/api/webhook.ts index c95a43b536..fd3a435049 100644 --- a/packages/app-store/btcpayserver/api/webhook.ts +++ b/packages/app-store/btcpayserver/api/webhook.ts @@ -4,6 +4,7 @@ import getRawBody from "raw-body"; import { z } from "zod"; import { handlePaymentSuccess } from "@calcom/app-store/_utils/payments/handlePaymentSuccess"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { IS_PRODUCTION } from "@calcom/lib/constants"; import { HttpError as HttpCode } from "@calcom/lib/http-error"; import { getServerErrorFromUnknown } from "@calcom/lib/server/getServerErrorFromUnknown"; @@ -87,7 +88,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ); if (!isValid) throw new HttpCode({ statusCode: 400, message: "signature mismatch" }); - await handlePaymentSuccess(payment.id, payment.bookingId); + const traceContext = distributedTracing.createTrace("btcpayserver_webhook", { + meta: { paymentId: payment.id, bookingId: payment.bookingId }, + }); + await handlePaymentSuccess(payment.id, payment.bookingId, traceContext); return res.status(200).json({ success: true }); } catch (_err) { const err = getServerErrorFromUnknown(_err); diff --git a/packages/app-store/hitpay/api/webhook.ts b/packages/app-store/hitpay/api/webhook.ts index c472801304..d8a191e30a 100644 --- a/packages/app-store/hitpay/api/webhook.ts +++ b/packages/app-store/hitpay/api/webhook.ts @@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import type z from "zod"; import { handlePaymentSuccess } from "@calcom/app-store/_utils/payments/handlePaymentSuccess"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { IS_PRODUCTION } from "@calcom/lib/constants"; import { HttpError as HttpCode } from "@calcom/lib/http-error"; import { getServerErrorFromUnknown } from "@calcom/lib/server/getServerErrorFromUnknown"; @@ -109,7 +110,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (excluded.status !== "completed") { throw new HttpCode({ statusCode: 204, message: `Payment is ${excluded.status}` }); } - return await handlePaymentSuccess(payment.id, payment.bookingId); + const traceContext = distributedTracing.createTrace("hitpay_webhook", { + meta: { paymentId: payment.id, bookingId: payment.bookingId }, + }); + return await handlePaymentSuccess(payment.id, payment.bookingId, traceContext); } catch (_err) { const err = getServerErrorFromUnknown(_err); console.error(`Webhook Error: ${err.message}`); diff --git a/packages/app-store/paypal/api/webhook.ts b/packages/app-store/paypal/api/webhook.ts index f049b87812..ec029a03da 100644 --- a/packages/app-store/paypal/api/webhook.ts +++ b/packages/app-store/paypal/api/webhook.ts @@ -3,6 +3,7 @@ import getRawBody from "raw-body"; import { z } from "zod"; import { handlePaymentSuccess } from "@calcom/app-store/_utils/payments/handlePaymentSuccess"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { paypalCredentialKeysSchema } from "@calcom/app-store/paypal/lib"; import Paypal from "@calcom/app-store/paypal/lib/Paypal"; import { IS_PRODUCTION } from "@calcom/lib/constants"; @@ -62,7 +63,10 @@ export async function handlePaypalPaymentSuccess( }, }); - return await handlePaymentSuccess(payment.id, payment.bookingId); + const traceContext = distributedTracing.createTrace("paypal_webhook", { + meta: { paymentId: payment.id, bookingId: payment.bookingId }, + }); + return await handlePaymentSuccess(payment.id, payment.bookingId, traceContext); } export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/packages/features/bookings/lib/handleConfirmation.ts b/packages/features/bookings/lib/handleConfirmation.ts index c037943f92..19765e550d 100644 --- a/packages/features/bookings/lib/handleConfirmation.ts +++ b/packages/features/bookings/lib/handleConfirmation.ts @@ -20,6 +20,8 @@ import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; +import type { TraceContext } from "@calcom/lib/tracing"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import type { PrismaClient } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import type { SchedulingType } from "@calcom/prisma/enums"; @@ -74,6 +76,7 @@ export async function handleConfirmation(args: { paid?: boolean; emailsEnabled?: boolean; platformClientParams?: PlatformClientParams; + traceContext: TraceContext; }) { const { user, @@ -85,6 +88,7 @@ export async function handleConfirmation(args: { paid, emailsEnabled = true, platformClientParams, + traceContext, } = args; const eventType = booking.eventType; const eventTypeMetadata = EventTypeMetaDataSchema.parse(eventType?.metadata || {}); @@ -96,13 +100,17 @@ export async function handleConfirmation(args: { const metadata: AdditionalInformation = {}; const workflows = await getAllWorkflowsFromEventType(eventType, booking.userId); + const spanContext = distributedTracing.createSpan(traceContext, "handle_confirmation"); + + const tracingLogger = distributedTracing.getTracingLogger(spanContext); + if (results.length > 0 && results.every((res) => !res.success)) { const error = { errorCode: "BookingCreatingMeetingFailed", message: "Booking failed", }; - log.error(`Booking ${user.username} failed`, safeStringify({ error, results })); + tracingLogger.error(`Booking ${user.username} failed`, safeStringify({ error, results })); } else { if (results.length) { // TODO: Handle created event metadata more elegantly @@ -139,7 +147,7 @@ export async function handleConfirmation(args: { ); } } catch (error) { - log.error(error); + tracingLogger.error(error); } } let updatedBookings: { @@ -358,6 +366,7 @@ export async function handleConfirmation(args: { hideBranding: !!updatedBookings[index].eventType?.owner?.hideBranding, seatReferenceUid: evt.attendeeSeatId, isPlatformNoEmail: !emailsEnabled && Boolean(platformClientParams?.platformClientId), + traceContext: spanContext, }); } @@ -487,7 +496,7 @@ export async function handleConfirmation(args: { sub, payload ).catch((e) => { - log.error( + tracingLogger.error( `Error executing webhook for event: ${WebhookTriggerEvents.BOOKING_CREATED}, URL: ${sub.subscriberUrl}, bookingId: ${evt.bookingId}, bookingUid: ${evt.uid}, platformClientId: ${platformClientParams?.platformClientId}`, safeStringify(e) ); @@ -547,7 +556,7 @@ export async function handleConfirmation(args: { sub, payload ).catch((e) => { - log.error( + tracingLogger.error( `Error executing webhook for event: ${WebhookTriggerEvents.BOOKING_PAID}, URL: ${sub.subscriberUrl}, bookingId: ${evt.bookingId}, bookingUid: ${evt.uid}`, safeStringify(e) ); @@ -586,7 +595,10 @@ export async function handleConfirmation(args: { creditCheckFn: creditService.hasAvailableCredits.bind(creditService), }); } catch (error) { - log.error("Error while scheduling workflow reminders for booking paid", safeStringify(error)); + tracingLogger.error( + "Error while scheduling workflow reminders for booking paid", + safeStringify(error) + ); } } } catch (error) { diff --git a/packages/features/bookings/lib/handleSeats/handleSeats.ts b/packages/features/bookings/lib/handleSeats/handleSeats.ts index 9473bf93fe..ecc37f4815 100644 --- a/packages/features/bookings/lib/handleSeats/handleSeats.ts +++ b/packages/features/bookings/lib/handleSeats/handleSeats.ts @@ -34,6 +34,7 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => { rescheduledBy, rescheduleReason, isDryRun = false, + traceContext, } = newSeatedBookingObject; // TODO: We could allow doing more things to support good dry run for seats if (isDryRun) return; @@ -160,7 +161,7 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => { rescheduledBy, }; - await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData, isDryRun }); + await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData, isDryRun, traceContext }); } return resultBooking; diff --git a/packages/features/bookings/lib/handleSeats/types.d.ts b/packages/features/bookings/lib/handleSeats/types.d.ts index 4449df78f4..64dca252ad 100644 --- a/packages/features/bookings/lib/handleSeats/types.d.ts +++ b/packages/features/bookings/lib/handleSeats/types.d.ts @@ -1,6 +1,7 @@ import type z from "zod"; import type { Workflow } from "@calcom/features/ee/workflows/lib/types"; +import type { TraceContext } from "@calcom/lib/tracing"; import type { Prisma } from "@calcom/prisma/client"; import type { AppsStatus, CalendarEvent } from "@calcom/types/Calendar"; @@ -58,6 +59,7 @@ export type NewSeatedBookingObject = { rescheduledBy?: string; workflows: Workflow[]; isDryRun?: boolean; + traceContext: TraceContext; }; export type RescheduleSeatedBookingObject = NewSeatedBookingObject & { rescheduleUid: string }; diff --git a/packages/features/bookings/lib/handleWebhookTrigger.ts b/packages/features/bookings/lib/handleWebhookTrigger.ts index 57cd39b509..d266a4171f 100644 --- a/packages/features/bookings/lib/handleWebhookTrigger.ts +++ b/packages/features/bookings/lib/handleWebhookTrigger.ts @@ -2,25 +2,33 @@ import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; import type { GetSubscriberOptions } from "@calcom/features/webhooks/lib/getWebhooks"; import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload"; import { isEventPayload, type WebhookPayloadType } from "@calcom/features/webhooks/lib/sendPayload"; -import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { withReporting } from "@calcom/lib/sentryWrapper"; +import type { TraceContext } from "@calcom/lib/tracing"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; async function _handleWebhookTrigger(args: { subscriberOptions: GetSubscriberOptions; eventTrigger: string; webhookData: WebhookPayloadType; isDryRun?: boolean; + traceContext: TraceContext; }) { + const spanContext = distributedTracing.createSpan(args.traceContext, "webhook_trigger", { + eventTrigger: args.eventTrigger || "unknown", + }); + + const tracingLogger = distributedTracing.getTracingLogger(spanContext); try { if (args.isDryRun) return; + const subscribers = await getWebhooks(args.subscriberOptions); const promises = subscribers.map((sub) => sendPayload(sub.secret, args.eventTrigger, new Date().toISOString(), sub, args.webhookData).catch( (e) => { if (isEventPayload(args.webhookData)) { - logger.error( + tracingLogger.error( `Error executing webhook for event: ${args.eventTrigger}, URL: ${sub.subscriberUrl}, booking id: ${args.webhookData.bookingId}, booking uid: ${args.webhookData.uid}`, safeStringify(e) ); @@ -30,7 +38,7 @@ async function _handleWebhookTrigger(args: { ); await Promise.all(promises); } catch (error) { - logger.error("Error while sending webhook", error); + tracingLogger.error("Error while sending webhook", error); } } diff --git a/packages/features/bookings/lib/service/RegularBookingService.ts b/packages/features/bookings/lib/service/RegularBookingService.ts index 647509f8a4..5bc13cc2bb 100644 --- a/packages/features/bookings/lib/service/RegularBookingService.ts +++ b/packages/features/bookings/lib/service/RegularBookingService.ts @@ -1720,6 +1720,7 @@ async function handler( workflows, rescheduledBy: reqBody.rescheduledBy, isDryRun, + traceContext, }); if (newBooking) { @@ -2480,6 +2481,7 @@ async function handler( paymentId: payment?.id, }, isDryRun, + traceContext, }); try { @@ -2617,6 +2619,7 @@ async function handler( eventTrigger, webhookData, isDryRun, + traceContext, }); } else { // if eventType requires confirmation we will trigger the BOOKING REQUESTED Webhook @@ -2628,6 +2631,7 @@ async function handler( eventTrigger, webhookData, isDryRun, + traceContext, }); } @@ -2671,6 +2675,7 @@ async function handler( seatReferenceUid: evt.attendeeSeatId, isPlatformNoEmail: noEmail && Boolean(platformClientId), isDryRun, + traceContext, }); } diff --git a/packages/features/ee/payments/api/webhook.ts b/packages/features/ee/payments/api/webhook.ts index f3832de3b5..ce4430d914 100644 --- a/packages/features/ee/payments/api/webhook.ts +++ b/packages/features/ee/payments/api/webhook.ts @@ -18,6 +18,8 @@ import { HttpError as HttpCode } from "@calcom/lib/http-error"; import logger from "@calcom/lib/logger"; import { safeStringify } from "@calcom/lib/safeStringify"; import { getServerErrorFromUnknown } from "@calcom/lib/server/getServerErrorFromUnknown"; +import type { TraceContext } from "@calcom/lib/tracing"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { prisma } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import { BookingStatus } from "@calcom/prisma/enums"; @@ -30,7 +32,7 @@ export const config = { }, }; -export async function handleStripePaymentSuccess(event: Stripe.Event) { +export async function handleStripePaymentSuccess(event: Stripe.Event, traceContext: TraceContext) { const paymentIntent = event.data.object as Stripe.PaymentIntent; const payment = await prisma.payment.findFirst({ where: { @@ -48,10 +50,10 @@ export async function handleStripePaymentSuccess(event: Stripe.Event) { } if (!payment?.bookingId) throw new HttpCode({ statusCode: 204, message: "Payment not found" }); - await handlePaymentSuccess(payment.id, payment.bookingId); + await handlePaymentSuccess(payment.id, payment.bookingId, traceContext); } -const handleSetupSuccess = async (event: Stripe.Event) => { +const handleSetupSuccess = async (event: Stripe.Event, traceContext: TraceContext) => { const setupIntent = event.data.object as Stripe.SetupIntent; const payment = await prisma.payment.findFirst({ where: { @@ -63,6 +65,10 @@ const handleSetupSuccess = async (event: Stripe.Event) => { const { booking, user, evt, eventType } = await getBooking(payment.bookingId); + const updatedTraceContext = distributedTracing.updateTrace(traceContext, { + bookingId: booking.id, + }); + const bookingData: Prisma.BookingUpdateInput = { paid: true, }; @@ -126,6 +132,7 @@ const handleSetupSuccess = async (event: Stripe.Event) => { booking, paid: true, platformClientParams: platformOAuthClient ? getPlatformParams(platformOAuthClient) : undefined, + traceContext: updatedTraceContext, }); } else if (areEmailsEnabled) { await sendOrganizerRequestEmail({ ...evt }, eventType.metadata); @@ -133,7 +140,7 @@ const handleSetupSuccess = async (event: Stripe.Event) => { } }; -type WebhookHandler = (event: Stripe.Event) => Promise; +type WebhookHandler = (event: Stripe.Event, traceContext: TraceContext) => Promise; const webhookHandlers: Record = { "payment_intent.succeeded": handleStripePaymentSuccess, @@ -163,6 +170,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_WEBHOOK_SECRET); + const traceContext = distributedTracing.createTrace(`stripe_webhook`, { + meta: { + eventType: event.type, + eventId: event.id, + }, + }); + // bypassing this validation for e2e tests // in order to successfully confirm the payment if (!event.account && !process.env.NEXT_PUBLIC_IS_E2E) { @@ -171,7 +185,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const handler = webhookHandlers[event.type]; if (handler) { - await handler(event); + await handler(event, traceContext); } else { /** Not really an error, just letting Stripe know that the webhook was received but unhandled */ throw new HttpCode({ diff --git a/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts b/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts index 75ec635ce0..7ec19ec72b 100644 --- a/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts +++ b/packages/features/ee/workflows/lib/reminders/scheduleMandatoryReminder.ts @@ -2,14 +2,13 @@ import type { getEventTypeResponse } from "@calcom/features/bookings/lib/handleN import { scheduleEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager"; import type { Workflow } from "@calcom/features/ee/workflows/lib/types"; import type { getDefaultEvent } from "@calcom/features/eventtypes/lib/defaultEvents"; -import logger from "@calcom/lib/logger"; import { withReporting } from "@calcom/lib/sentryWrapper"; +import type { TraceContext } from "@calcom/lib/tracing"; +import { distributedTracing } from "@calcom/lib/tracing/factory"; import { WorkflowTriggerEvents, TimeUnit, WorkflowActions, WorkflowTemplates } from "@calcom/prisma/enums"; import type { ExtendedCalendarEvent } from "./reminderScheduler"; -const log = logger.getSubLogger({ prefix: ["[scheduleMandatoryReminder]"] }); - export type NewBookingEventType = Awaited> | getEventTypeResponse; async function _scheduleMandatoryReminder({ @@ -20,6 +19,7 @@ async function _scheduleMandatoryReminder({ seatReferenceUid, isPlatformNoEmail = false, isDryRun = false, + traceContext, }: { evt: ExtendedCalendarEvent; workflows: Workflow[]; @@ -28,7 +28,26 @@ async function _scheduleMandatoryReminder({ seatReferenceUid: string | undefined; isPlatformNoEmail?: boolean; isDryRun?: boolean; + traceContext: TraceContext; }) { + const reminderMeta = { + eventTitle: evt.title, + attendeeCount: evt.attendees.length, + organizerId: evt.organizer.id, + requiresConfirmation, + hideBranding, + seatReferenceUid, + isPlatformNoEmail, + }; + + const spanContext = distributedTracing.createSpan( + traceContext, + "schedule_mandatory_reminder", + reminderMeta + ); + + const tracingLogger = distributedTracing.getTracingLogger(spanContext); + if (isDryRun) return; if (isPlatformNoEmail) return; try { @@ -67,11 +86,11 @@ async function _scheduleMandatoryReminder({ verifiedAt: new Date(), }); } catch (error) { - log.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); + tracingLogger.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); } } } catch (error) { - log.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); + tracingLogger.error("Error while scheduling mandatory reminders", JSON.stringify({ error })); } } diff --git a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts index c3d5916d1a..426de305c9 100644 --- a/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/confirm.handler.ts @@ -20,6 +20,7 @@ import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent"; import { getTranslation } from "@calcom/lib/server/i18n"; import { PrismaOrgMembershipRepository } from "@calcom/lib/server/repository/PrismaOrgMembershipRepository"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; +import type { TraceContext } from "@calcom/lib/tracing"; import { prisma } from "@calcom/prisma"; import { Prisma } from "@calcom/prisma/client"; import { @@ -41,6 +42,7 @@ import type { TConfirmInputSchema } from "./confirm.schema"; type ConfirmOptions = { ctx: { user: Pick, "id" | "uuid" | "email" | "username" | "role" | "destinationCalendar">; + traceContext: TraceContext; }; input: TConfirmInputSchema; }; @@ -277,6 +279,15 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { }); } } + const traceContext = { + ...ctx.traceContext, + bookingUid: booking.uid || "unknown", + confirmed: String(confirmed), + eventTypeId: booking.eventType?.id?.toString() || "null", + userId: user.id.toString(), + teamId: booking.eventType?.teamId?.toString() || "null", + }; + if (recurringEventId && recurringEvent) { const groupedRecurringBookings = await prisma.booking.groupBy({ where: { @@ -307,6 +318,7 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { (booking.eventType?.locations as LocationObject[]) || [] ); evt.conferenceCredentialId = conferenceCredentialId.conferenceCredentialId; + await handleConfirmation({ user: { ...user, credentials: allCredentials }, evt, @@ -316,6 +328,7 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { booking, emailsEnabled, platformClientParams, + traceContext, }); } else { evt.rejectionReason = rejectionReason; @@ -392,7 +405,7 @@ export const confirmHandler = async ({ ctx, input }: ConfirmOptions) => { status: BookingStatus.REJECTED, smsReminderNumber: booking.smsReminderNumber || undefined, }; - await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData }); + await handleWebhookTrigger({ subscriberOptions, eventTrigger, webhookData, traceContext }); const workflows = await getAllWorkflowsFromEventType(booking.eventType, user.id); try {