diff --git a/server/routers/contentstack/accountPage/query.ts b/server/routers/contentstack/accountPage/query.ts index 7948c78ad..424092343 100644 --- a/server/routers/contentstack/accountPage/query.ts +++ b/server/routers/contentstack/accountPage/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { Lang } from "@/constants/languages" import { GetAccountPage, @@ -32,9 +34,32 @@ import { Embeds } from "@/types/requests/embeds" import { Edges } from "@/types/requests/utils/edges" import { RTEDocument } from "@/types/rte/node" +const meter = metrics.getMeter("trpc.accountPage") + +// OpenTelemetry metrics +const getAccountPageRefsCounter = meter.createCounter( + "trpc.contentstack.accountPage.get" +) +const getAccountPageRefsSuccessCounter = meter.createCounter( + "trpc.contentstack.accountPage.get-success" +) +const getAccountPageRefsFailCounter = meter.createCounter( + "trpc.contentstack.accountPage.get-fail" +) +const getAccountPageCounter = meter.createCounter( + "trpc.contentstack.accountPage.get" +) +const getAccountPageSuccessCounter = meter.createCounter( + "trpc.contentstack.accountPage.get-success" +) +const getAccountPageFailCounter = meter.createCounter( + "trpc.contentstack.accountPage.get-fail" +) + export const accountPageQueryRouter = router({ get: contentstackExtendedProcedureUID.query(async ({ ctx }) => { const { lang, uid } = ctx + getAccountPageRefsCounter.add(1, { lang, uid }) console.info( "contentstack.accountPage.refs start", JSON.stringify({ query: { lang, uid } }) @@ -52,6 +77,12 @@ export const accountPageQueryRouter = router({ if (!refsResponse.data) { const notFoundError = notFound(refsResponse) + getAccountPageRefsFailCounter.add(1, { + lang, + uid, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.accountPage.refs not found error", JSON.stringify({ @@ -67,6 +98,12 @@ export const accountPageQueryRouter = router({ const validatedAccountPageRefs = validateAccountPageRefsSchema.safeParse(cleanedData) if (!validatedAccountPageRefs.success) { + getAccountPageRefsFailCounter.add(1, { + lang, + uid, + error_type: "validation_error", + error: JSON.stringify(validatedAccountPageRefs.error), + }) console.error( "contentstack.accountPage.refs validation error", JSON.stringify({ @@ -83,6 +120,8 @@ export const accountPageQueryRouter = router({ generateTags(lang, connections), generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid), ].flat() + getAccountPageRefsSuccessCounter.add(1, { lang, uid, tags }) + getAccountPageCounter.add(1, { lang, uid }) console.info( "contentstack.accountPage start", JSON.stringify({ query: { lang, uid } }) @@ -98,6 +137,12 @@ export const accountPageQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) + getAccountPageFailCounter.add(1, { + lang, + uid, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.accountPage not found error", JSON.stringify({ @@ -113,6 +158,12 @@ export const accountPageQueryRouter = router({ ) if (!validatedAccountPage.success) { + getAccountPageFailCounter.add(1, { + lang, + uid, + error_type: "validation_error", + error: JSON.stringify(validatedAccountPage.error), + }) console.error( "contentstack.accountPage validation error", JSON.stringify({ @@ -122,6 +173,7 @@ export const accountPageQueryRouter = router({ ) return null } + getAccountPageSuccessCounter.add(1, { lang, uid }) console.info( "contentstack.accountPage success", JSON.stringify({ query: { lang, uid } }) diff --git a/server/routers/contentstack/base/query.ts b/server/routers/contentstack/base/query.ts index d4952cc3f..d534279ff 100644 --- a/server/routers/contentstack/base/query.ts +++ b/server/routers/contentstack/base/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql" import { GetCurrentFooter, @@ -26,11 +28,58 @@ import { validateHeaderConfigSchema, } from "./output" +const meter = metrics.getMeter("trpc.contentstack.base") +// OpenTelemetry metrics: ContactConfig +const getContactConfigCounter = meter.createCounter( + "trpc.contentstack.contactConfig.get" +) +const getContactConfigSuccessCounter = meter.createCounter( + "trpc.contentstack.contactConfig.get-success" +) +const getContactConfigFailCounter = meter.createCounter( + "trpc.contentstack.contactConfig.get-fail" +) +// OpenTelemetry metrics: Header +const getHeaderRefCounter = meter.createCounter( + "trpc.contentstack.header.ref.get" +) +const getHeaderRefSuccessCounter = meter.createCounter( + "trpc.contentstack.header.ref.get-success" +) +const getHeaderRefFailCounter = meter.createCounter( + "trpc.contentstack.header.ref.get-fail" +) +const getHeaderCounter = meter.createCounter("trpc.contentstack.header.get") +const getHeaderSuccessCounter = meter.createCounter( + "trpc.contentstack.header.get-success" +) +const getHeaderFailCounter = meter.createCounter( + "trpc.contentstack.header.get-fail" +) +// OpenTelemetry metrics: Footer +const getFooterRefCounter = meter.createCounter( + "trpc.contentstack.footer.ref.get" +) +const getFooterRefSuccessCounter = meter.createCounter( + "trpc.contentstack.footer.ref.get-success" +) +const getFooterRefFailCounter = meter.createCounter( + "trpc.contentstack.footer.ref.get-fail" +) +const getFooterCounter = meter.createCounter("trpc.contentstack.footer.get") +const getFooterSuccessCounter = meter.createCounter( + "trpc.contentstack.footer.get-success" +) +const getFooterFailCounter = meter.createCounter( + "trpc.contentstack.footer.get-fail" +) + export const baseQueryRouter = router({ contact: contentstackBaseProcedure.query(async ({ ctx }) => { const { lang } = ctx + getContactConfigCounter.add(1, { lang }) console.info( - "contentstack.config start", + "contentstack.contactConfig start", JSON.stringify({ query: { lang } }) ) const response = await request(GetContactConfig, { @@ -39,10 +88,18 @@ export const baseQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) + + getContactConfigFailCounter.add(1, { + lang, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) + console.error( "contentstack.config not found error", JSON.stringify({ query: { lang }, error: { code: notFoundError.code } }) ) + throw notFoundError } @@ -51,8 +108,13 @@ export const baseQueryRouter = router({ ) if (!validatedContactConfigConfig.success) { + getContactConfigFailCounter.add(1, { + lang, + error_type: "validation_error", + error: JSON.stringify(validatedContactConfigConfig.error), + }) console.error( - "contentstack.config validation error", + "contentstack.contactConfig validation error", JSON.stringify({ query: { lang }, error: validatedContactConfigConfig.error, @@ -60,8 +122,9 @@ export const baseQueryRouter = router({ ) return null } + getContactConfigSuccessCounter.add(1, { lang }) console.info( - "contentstack.config success", + "contentstack.contactConfig success", JSON.stringify({ query: { lang } }) ) return validatedContactConfigConfig.data.all_contact_config.items[0] @@ -69,6 +132,7 @@ export const baseQueryRouter = router({ header: contentstackBaseProcedure .input(langInput) .query(async ({ input }) => { + getHeaderRefCounter.add(1, { lang: input.lang }) console.info( "contentstack.header.ref start", JSON.stringify({ query: { lang: input.lang } }) @@ -76,6 +140,7 @@ export const baseQueryRouter = router({ const responseRef = await request(GetCurrentHeaderRef, { locale: input.lang, }) + getHeaderCounter.add(1, { lang: input.lang }) console.info( "contentstack.header start", JSON.stringify({ @@ -99,6 +164,11 @@ export const baseQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) + getHeaderFailCounter.add(1, { + lang: input.lang, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.header not found error", JSON.stringify({ @@ -116,6 +186,11 @@ export const baseQueryRouter = router({ ) if (!validatedHeaderConfig.success) { + getHeaderFailCounter.add(1, { + lang: input.lang, + error_type: "validation_error", + error: JSON.stringify(validatedHeaderConfig.error), + }) console.error( "contentstack.header validation error", JSON.stringify({ @@ -127,6 +202,7 @@ export const baseQueryRouter = router({ ) return null } + getHeaderSuccessCounter.add(1, { lang: input.lang }) console.info( "contentstack.header success", JSON.stringify({ @@ -145,6 +221,7 @@ export const baseQueryRouter = router({ footer: contentstackBaseProcedure .input(langInput) .query(async ({ input }) => { + getFooterRefCounter.add(1, { lang: input.lang }) console.info( "contentstack.footer.ref start", JSON.stringify({ query: { lang: input.lang } }) @@ -153,6 +230,7 @@ export const baseQueryRouter = router({ locale: input.lang, }) // There's currently no error handling/validation for the responseRef, should it be added? + getFooterCounter.add(1, { lang: input.lang }) console.info( "contentstack.footer start", JSON.stringify({ @@ -178,6 +256,11 @@ export const baseQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) + getFooterFailCounter.add(1, { + lang: input.lang, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.footer not found error", JSON.stringify({ @@ -195,6 +278,11 @@ export const baseQueryRouter = router({ ) if (!validatedFooterConfig.success) { + getFooterFailCounter.add(1, { + lang: input.lang, + error_type: "validation_error", + error: JSON.stringify(validatedFooterConfig.error), + }) console.error( "contentstack.footer validation error", JSON.stringify({ @@ -204,6 +292,7 @@ export const baseQueryRouter = router({ ) return null } + getFooterSuccessCounter.add(1, { lang: input.lang }) console.info( "contentstack.footer success", JSON.stringify({ query: { lang: input.lang } }) diff --git a/server/routers/contentstack/hotelPage/query.ts b/server/routers/contentstack/hotelPage/query.ts index bf1f4ca6e..fe4e4eea1 100644 --- a/server/routers/contentstack/hotelPage/query.ts +++ b/server/routers/contentstack/hotelPage/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { GetHotelPage } from "@/lib/graphql/Query/HotelPage.graphql" import { request } from "@/lib/graphql/request" import { notFound } from "@/server/errors/trpc" @@ -5,9 +7,22 @@ import { contentstackBaseProcedure, router } from "@/server/trpc" import { HotelPage, HotelPageDataRaw, validateHotelPageSchema } from "./output" +// OpenTelemetry metrics +const meter = metrics.getMeter("trpc.contentstack.hotelPage") +const getHotelPageCounter = meter.createCounter( + "trpc.contentstack.hotelPage.get" +) +const getHotelPageSuccessCounter = meter.createCounter( + "trpc.contentstack.hotelPage.get-success" +) +const getHotelPageFailCounter = meter.createCounter( + "trpc.contentstack.hotelPage.get-fail" +) + export const hotelPageQueryRouter = router({ get: contentstackBaseProcedure.query(async ({ ctx }) => { const { lang, uid } = ctx + getHotelPageCounter.add(1, { lang, uid: `${uid}` }) console.info( "contentstack.hotelPage start", JSON.stringify({ @@ -20,6 +35,12 @@ export const hotelPageQueryRouter = router({ }) if (!response.data) { const notFoundError = notFound(response) + getHotelPageFailCounter.add(1, { + lang, + uid: `${uid}`, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.hotelPage not found error", JSON.stringify({ @@ -33,6 +54,12 @@ export const hotelPageQueryRouter = router({ const validatedHotelPage = validateHotelPageSchema.safeParse(response.data) if (!validatedHotelPage.success) { + getHotelPageFailCounter.add(1, { + lang, + uid: `${uid}`, + error_type: "validation_error", + error: JSON.stringify(validatedHotelPage.error), + }) console.error( "contentstack.hotelPage validation error", JSON.stringify({ @@ -46,6 +73,7 @@ export const hotelPageQueryRouter = router({ const hotelPage = { ...validatedHotelPage.data.hotel_page, } as HotelPage + getHotelPageSuccessCounter.add(1, { lang, uid: `${uid}` }) console.info( "contentstack.hotelPage success", JSON.stringify({ diff --git a/server/routers/contentstack/languageSwitcher/query.ts b/server/routers/contentstack/languageSwitcher/query.ts index bcab646cb..c654e8e5a 100644 --- a/server/routers/contentstack/languageSwitcher/query.ts +++ b/server/routers/contentstack/languageSwitcher/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { Lang } from "@/constants/languages" import { baseUrls } from "@/constants/routes/baseUrls" import { batchRequest } from "@/lib/graphql/batchRequest" @@ -40,6 +42,17 @@ interface LanguageSwitcherVariables { uid: string } +const meter = metrics.getMeter("trpc.contentstack.languageSwitcher") +const getLanguageSwitcherCounter = meter.createCounter( + "trpc.contentstack.languageSwitcher.get" +) +const getLanguageSwitcherSuccessCounter = meter.createCounter( + "trpc.contentstack.languageSwitcher.get-success" +) +const getLanguageSwitcherFailCounter = meter.createCounter( + "trpc.contentstack.languageSwitcher.get-fail" +) + async function getLanguageSwitcher(options: LanguageSwitcherVariables) { const variables = { uid: options.uid } const tagsDaDeEn = [ @@ -131,6 +144,11 @@ export const languageSwitcherQueryRouter = router({ if (!ctx.uid || !ctx.lang) { return { lang: ctx.lang, urls: baseUrls } } + getLanguageSwitcherCounter.add(1, { + uid: ctx.uid, + lang: ctx.lang, + contentType: ctx.contentType, + }) console.info( "contentstack.languageSwitcher start", JSON.stringify({ @@ -164,6 +182,13 @@ export const languageSwitcherQueryRouter = router({ validateLanguageSwitcherData.safeParse(urls) if (!validatedLanguageSwitcherData.success) { + getLanguageSwitcherFailCounter.add(1, { + uid: ctx.uid, + lang: ctx.lang, + contentType: ctx.contentType, + error_type: "validation_error", + error: JSON.stringify(validatedLanguageSwitcherData.error), + }) console.error( "contentstack.languageSwitcher validation error", JSON.stringify({ @@ -177,6 +202,11 @@ export const languageSwitcherQueryRouter = router({ ) return null } + getLanguageSwitcherSuccessCounter.add(1, { + uid: ctx.uid, + lang: ctx.lang, + contentType: ctx.contentType, + }) console.info( "contentstack.languageSwitcher success", JSON.stringify({ diff --git a/server/routers/contentstack/loyaltyPage/query.ts b/server/routers/contentstack/loyaltyPage/query.ts index 2f0dc3d44..b4541815a 100644 --- a/server/routers/contentstack/loyaltyPage/query.ts +++ b/server/routers/contentstack/loyaltyPage/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { Lang } from "@/constants/languages" import { GetLoyaltyPage, @@ -33,9 +35,31 @@ import { TrackingSDKPageData, } from "@/types/components/tracking" +const meter = metrics.getMeter("trpc.loyaltyPage") +// OpenTelemetry metrics: LoyaltyPage +const getLoyaltyPageRefsCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get" +) +const getLoyaltyPageRefsSuccessCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get-success" +) +const getLoyaltyPageRefsFailCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get-fail" +) +const getLoyaltyPageCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get" +) +const getLoyaltyPageSuccessCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get-success" +) +const getLoyaltyPageFailCounter = meter.createCounter( + "trpc.contentstack.loyaltyPage.get-fail" +) + export const loyaltyPageQueryRouter = router({ get: contentstackExtendedProcedureUID.query(async ({ ctx }) => { const { lang, uid } = ctx + getLoyaltyPageRefsCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage.refs start", JSON.stringify({ @@ -55,6 +79,14 @@ export const loyaltyPageQueryRouter = router({ if (!refsResponse.data) { const notFoundError = notFound(refsResponse) + getLoyaltyPageRefsFailCounter.add(1, { + lang, + uid, + error_type: "http_error", + error: JSON.stringify({ + code: notFoundError.code, + }), + }) console.error( "contentstack.loyaltyPage.refs not found error", JSON.stringify({ @@ -73,6 +105,12 @@ export const loyaltyPageQueryRouter = router({ const validatedLoyaltyPageRefs = validateLoyaltyPageRefsSchema.safeParse(cleanedData) if (!validatedLoyaltyPageRefs.success) { + getLoyaltyPageRefsFailCounter.add(1, { + lang, + uid, + error_type: "validation_error", + error: JSON.stringify(validatedLoyaltyPageRefs.error), + }) console.error( "contentstack.loyaltyPage.refs validation error", JSON.stringify({ @@ -82,6 +120,7 @@ export const loyaltyPageQueryRouter = router({ ) return null } + getLoyaltyPageRefsSuccessCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage.refs success", JSON.stringify({ @@ -94,6 +133,7 @@ export const loyaltyPageQueryRouter = router({ generateTags(lang, connections), generateTag(lang, validatedLoyaltyPageRefs.data.loyalty_page.system.uid), ].flat() + getLoyaltyPageCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage start", JSON.stringify({ @@ -111,7 +151,12 @@ export const loyaltyPageQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) - + getLoyaltyPageFailCounter.add(1, { + lang, + uid, + error_type: "http_error", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.loyaltyPage not found error", JSON.stringify({ @@ -227,6 +272,12 @@ export const loyaltyPageQueryRouter = router({ const validatedLoyaltyPage = validateLoyaltyPageSchema.safeParse(loyaltyPage) if (!validatedLoyaltyPage.success) { + getLoyaltyPageFailCounter.add(1, { + lang, + uid, + error_type: "validation_error", + error: JSON.stringify(validatedLoyaltyPage.error), + }) console.error( "contentstack.loyaltyPage validation error", JSON.stringify({ @@ -245,6 +296,7 @@ export const loyaltyPageQueryRouter = router({ channel: TrackingChannelEnum["scandic-friends"], pageType: "loyaltycontentpage", } + getLoyaltyPageSuccessCounter.add(1, { lang, uid }) console.info( "contentstack.loyaltyPage success", JSON.stringify({ query: { lang, uid } }) diff --git a/server/routers/contentstack/myPages/navigation/query.ts b/server/routers/contentstack/myPages/navigation/query.ts index 38d60aa78..0328a3719 100644 --- a/server/routers/contentstack/myPages/navigation/query.ts +++ b/server/routers/contentstack/myPages/navigation/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { GetNavigationMyPages, GetNavigationMyPagesRefs, @@ -25,6 +27,26 @@ import { getConnections } from "./utils" import { PageLinkEnum } from "@/types/requests/pageLinks" +const meter = metrics.getMeter("trpc.navigationMyPages") +const getNavigationMyPagesRefsCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.refs.get" +) +const getNavigationMyPagesRefsSuccessCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.refs.get-success" +) +const getNavigationMyPagesRefsFailCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.refs.get-fail" +) +const getNavigationMyPagesCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.get" +) +const getNavigationMyPagesSuccessCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.get-success" +) +const getNavigationMyPagesFailCounter = meter.createCounter( + "trpc.contentstack.navigationMyPages.get-fail" +) + export function mapMenuItems(menuItems: MenuItems) { return menuItems.map((menuItem) => { return { @@ -61,6 +83,7 @@ export function mapMenuItems(menuItems: MenuItems) { export const navigationQueryRouter = router({ get: contentstackBaseProcedure.query(async function ({ ctx }) { const { lang } = ctx + getNavigationMyPagesRefsCounter.add(1, { lang }) console.info( "contentstack.myPages.navigation.refs start", JSON.stringify({ query: { lang } }) @@ -75,6 +98,11 @@ export const navigationQueryRouter = router({ if (!refsResponse.data) { const notFoundError = notFound(refsResponse) + getNavigationMyPagesRefsFailCounter.add(1, { + lang, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error( "contentstack.myPages.navigation.refs not found error", JSON.stringify({ @@ -90,6 +118,11 @@ export const navigationQueryRouter = router({ const validatedMyPagesNavigationRefs = navigationRefsPayloadSchema.safeParse(refsResponse.data) if (!validatedMyPagesNavigationRefs.success) { + getNavigationMyPagesRefsFailCounter.add(1, { + lang, + error_type: "validation_error", + error: JSON.stringify(validatedMyPagesNavigationRefs.error), + }) console.error( "contentstack.myPages.navigation.refs validation error", JSON.stringify({ @@ -101,6 +134,7 @@ export const navigationQueryRouter = router({ ) return null } + getNavigationMyPagesRefsSuccessCounter.add(1, { lang }) console.info( "contentstack.myPages.navigation.refs success", JSON.stringify({ query: { lang } }) @@ -115,6 +149,7 @@ export const navigationQueryRouter = router({ .system.uid ), ].flat() + getNavigationMyPagesCounter.add(1) console.info( "contentstack.myPages.navigation start", JSON.stringify({ query: { lang } }) @@ -127,6 +162,11 @@ export const navigationQueryRouter = router({ if (!response.data) { const notFoundError = notFound(response) + getNavigationMyPagesFailCounter.add(1, { + lang, + error_type: "not_found", + error: JSON.stringify({ code: notFoundError.code }), + }) console.error("contentstack.myPages.navigation not found error", { query: { lang, @@ -140,6 +180,11 @@ export const navigationQueryRouter = router({ response.data ) if (!validatedMyPagesNavigation.success) { + getNavigationMyPagesFailCounter.add(1, { + lang, + error_type: "validation_error", + error: JSON.stringify(validatedMyPagesNavigation.error), + }) console.error( "contentstack.myPages.navigation.payload validation error", JSON.stringify({ @@ -160,6 +205,11 @@ export const navigationQueryRouter = router({ const validatedNav = getNavigationSchema.safeParse(nav) if (!validatedNav.success) { + getNavigationMyPagesFailCounter.add(1, { + lang, + error_type: "validation_error", + error: JSON.stringify(validatedNav.error), + }) console.error( "contentstack.myPages.navigation validation error", JSON.stringify({ @@ -171,6 +221,7 @@ export const navigationQueryRouter = router({ console.error(validatedNav.error) return null } + getNavigationMyPagesSuccessCounter.add(1, { lang }) console.info( "contentstack.myPages.navigation success", JSON.stringify({ query: { lang } }) diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index a18c9bc71..e01f95b74 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -20,9 +20,9 @@ import tempFilterData from "./tempFilterData.json" import tempRatesData from "./tempRatesData.json" const meter = metrics.getMeter("trpc.hotels") -let getHotelCounter = meter.createCounter("trpc.hotel.get") -let getHotelSuccessCounter = meter.createCounter("trpc.hotel.get-success") -let getHotelFailCounter = meter.createCounter("trpc.hotel.get-fail") +const getHotelCounter = meter.createCounter("trpc.hotel.get") +const getHotelSuccessCounter = meter.createCounter("trpc.hotel.get-success") +const getHotelFailCounter = meter.createCounter("trpc.hotel.get-fail") export const hotelQueryRouter = router({ getHotel: serviceProcedure @@ -40,6 +40,7 @@ export const hotelQueryRouter = router({ params.include = include.join(",") } + getHotelCounter.add(1, { hotelId, language, include }) console.info( "api.hotels.hotel start", JSON.stringify({ @@ -59,6 +60,17 @@ export const hotelQueryRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() + getHotelFailCounter.add(1, { + hotelId, + language, + include, + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.hotels.hotel error", JSON.stringify({ @@ -76,6 +88,14 @@ export const hotelQueryRouter = router({ const validatedHotelData = getHotelDataSchema.safeParse(apiJson) if (!validatedHotelData.success) { + getHotelFailCounter.add(1, { + hotelId, + language, + include, + error_type: "validation_error", + error: JSON.stringify(validatedHotelData.error), + }) + console.error( "api.hotels.hotel validation error", JSON.stringify({ @@ -94,6 +114,18 @@ export const hotelQueryRouter = router({ .map((roomCategory) => { const validatedRoom = roomSchema.safeParse(roomCategory) if (!validatedRoom.success) { + getHotelFailCounter.add(1, { + hotelId, + language, + include, + error_type: "validation_error", + error: JSON.stringify( + validatedRoom.error.issues.map(({ code, message }) => ({ + code, + message, + })) + ), + }) console.error( "api.hotels.hotel validation error", JSON.stringify({ @@ -103,6 +135,7 @@ export const hotelQueryRouter = router({ ) throw badRequestError() } + return validatedRoom.data }) : [] @@ -129,6 +162,7 @@ export const hotelQueryRouter = router({ // const apiLang = toApiLang(language) // params.set("hotelId", hotelId.toString()) // params.set("language", apiLang) + console.info("api.hotels.rates start", JSON.stringify({})) const validatedHotelData = getRatesSchema.safeParse(tempRatesData) diff --git a/server/routers/user/mutation.ts b/server/routers/user/mutation.ts index e78e95a13..21b266464 100644 --- a/server/routers/user/mutation.ts +++ b/server/routers/user/mutation.ts @@ -1,5 +1,3 @@ -import { stat } from "fs" - import * as api from "@/lib/api" import { initiateSaveCardSchema } from "@/server/routers/user/output" import { protectedProcedure, router } from "@/server/trpc" diff --git a/server/routers/user/query.ts b/server/routers/user/query.ts index ef130e72b..1040d81b1 100644 --- a/server/routers/user/query.ts +++ b/server/routers/user/query.ts @@ -1,3 +1,5 @@ +import { metrics } from "@opentelemetry/api" + import { Lang } from "@/constants/languages" import { env } from "@/env/server" import * as api from "@/lib/api" @@ -32,12 +34,62 @@ import type { TrackingSDKUserData, } from "@/types/components/tracking" +// OpenTelemetry metrics: User +const meter = metrics.getMeter("trpc.user") +const getVerifiedUserCounter = meter.createCounter("trpc.user.get") +const getVerifiedUserSuccessCounter = meter.createCounter( + "trpc.user.get-success" +) +const getVerifiedUserFailCounter = meter.createCounter("trpc.user.get-fail") +const getProfileCounter = meter.createCounter("trpc.user.profile") +const getProfileSuccessCounter = meter.createCounter( + "trpc.user.profile-success" +) +const getProfileFailCounter = meter.createCounter("trpc.user.profile-fail") + +// OpenTelemetry metrics: Stays +const getPreviousStaysCounter = meter.createCounter("trpc.user.stays.previous") +const getPreviousStaysSuccessCounter = meter.createCounter( + "trpc.user.stays.previous-success" +) +const getPreviousStaysFailCounter = meter.createCounter( + "trpc.user.stays.previous-fail" +) +const getUpcomingStaysCounter = meter.createCounter("trpc.user.stays.upcoming") +const getUpcomingStaysSuccessCounter = meter.createCounter( + "trpc.user.stays.upcoming-success" +) +const getUpcomingStaysFailCounter = meter.createCounter( + "trpc.user.stays.upcoming-fail" +) + +// OpenTelemetry metrics: Transactions +const getFriendTransactionsCounter = meter.createCounter( + "trpc.user.transactions.friendTransactions" +) +const getFriendTransactionsSuccessCounter = meter.createCounter( + "trpc.user.transactions.friendTransactions-success" +) +const getFriendTransactionsFailCounter = meter.createCounter( + "trpc.user.transactions.friendTransactions-fail" +) + +// OpenTelemetry metrics: Credit Cards +const getCreditCardsCounter = meter.createCounter("trpc.user.creditCards") +const getCreditCardsSuccessCounter = meter.createCounter( + "trpc.user.creditCards-success" +) +const getCreditCardsFailCounter = meter.createCounter( + "trpc.user.creditCards-fail" +) + async function getVerifiedUser({ session }: { session: Session }) { const now = Date.now() if (session.token.expires_at && session.token.expires_at < now) { return { error: true, cause: "token_expired" } as const } + getVerifiedUserCounter.add(1) console.info("api.user.profile start", JSON.stringify({})) const apiResponse = await api.get(api.endpoints.v1.profile, { cache: "no-store", @@ -48,6 +100,14 @@ async function getVerifiedUser({ session }: { session: Session }) { if (!apiResponse.ok) { const text = await apiResponse.text() + getVerifiedUserFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.user.profile error", JSON.stringify({ @@ -74,12 +134,17 @@ async function getVerifiedUser({ session }: { session: Session }) { const apiJson = await apiResponse.json() if (!apiJson.data?.attributes) { + getVerifiedUserFailCounter.add(1, { error_type: "data_error" }) console.error("api.user.profile data error", JSON.stringify({})) // not passing the data to avoid logging sensitive data return null } const verifiedData = getUserSchema.safeParse(apiJson.data.attributes) if (!verifiedData.success) { + getVerifiedUserFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(verifiedData.error), + }) console.error( "api.user.profile validation error", JSON.stringify({ @@ -88,6 +153,7 @@ async function getVerifiedUser({ session }: { session: Session }) { ) return null } + getVerifiedUserSuccessCounter.add(1) console.info("api.user.profile success", JSON.stringify({})) return verifiedData } @@ -118,6 +184,7 @@ async function updateStaysBookingUrl( lang: Lang ) { // Tenporary API call needed till we have user name in ctx session data + getProfileCounter.add(1) console.info("api.user.profile start", JSON.stringify({})) const apiResponse = await api.get(api.endpoints.v1.profile, { cache: "no-store", @@ -155,6 +222,7 @@ async function updateStaysBookingUrl( } if (apiResponse.ok) { + getProfileSuccessCounter.add(1) console.info("api.user.profile success", JSON.stringify({})) const apiJson = await apiResponse.json() if (apiJson.data?.attributes) { @@ -181,6 +249,7 @@ async function updateStaysBookingUrl( }) } } + getProfileFailCounter.add(1, { error: JSON.stringify(apiResponse) }) console.info("api.user.profile error", JSON.stringify({ error: apiResponse })) return data @@ -300,7 +369,7 @@ export const userQueryRouter = router({ const params = new URLSearchParams() params.set("limit", "1") - + getPreviousStaysCounter.add(1, { params: params.toString() }) console.info( "api.booking.stays.past start", JSON.stringify({ query: { params } }) @@ -316,6 +385,13 @@ export const userQueryRouter = router({ ) if (!previousStaysResponse.ok) { + getPreviousStaysFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: previousStaysResponse.status, + statusText: previousStaysResponse.statusText, + }), + }) console.error( "api.booking.stays.past error", JSON.stringify({ @@ -332,12 +408,17 @@ export const userQueryRouter = router({ const verifiedPreviousStaysData = getStaysSchema.safeParse(previousStaysApiJson) if (!verifiedPreviousStaysData.success) { + getPreviousStaysFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(verifiedPreviousStaysData.error), + }) console.error( "api.booking.stays.past validation error, ", JSON.stringify({ error: verifiedPreviousStaysData.error }) ) return notLoggedInUserTrackingData } + getPreviousStaysSuccessCounter.add(1) console.info("api.booking.stays.past success", JSON.stringify({})) const membership = getMembership(verifiedUserData.data.memberships) @@ -373,6 +454,7 @@ export const userQueryRouter = router({ if (cursor) { params.offset = cursor } + getPreviousStaysCounter.add(1, { params: params.toString() }) console.info( "api.booking.stays.past start", JSON.stringify({ query: { params: params.toString() } }) @@ -390,6 +472,15 @@ export const userQueryRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() + getPreviousStaysFailCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.booking.stays.past error ", JSON.stringify({ @@ -408,6 +499,11 @@ export const userQueryRouter = router({ const verifiedData = getStaysSchema.safeParse(apiJson) if (!verifiedData.success) { + getPreviousStaysFailCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + error_type: "validation_error", + error: JSON.stringify(verifiedData.error), + }) console.error( "api.booking.stays.past validation error ", JSON.stringify({ @@ -418,6 +514,9 @@ export const userQueryRouter = router({ return null } + getPreviousStaysSuccessCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + }) console.info( "api.booking.stays.past success", JSON.stringify({ query: { params: params.toString() } }) @@ -449,6 +548,9 @@ export const userQueryRouter = router({ if (cursor) { params.offset = cursor } + getUpcomingStaysCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + }) console.info( "api.booking.stays.future start", JSON.stringify({ query: { params: params.toString() } }) @@ -465,10 +567,20 @@ export const userQueryRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() + getUpcomingStaysFailCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.booking.stays.future error ", JSON.stringify({ query: { params: params.toString() }, + error_type: "http_error", error: { status: apiResponse.status, statusText: apiResponse.statusText, @@ -482,6 +594,11 @@ export const userQueryRouter = router({ const apiJson = await apiResponse.json() const verifiedData = getStaysSchema.safeParse(apiJson) if (!verifiedData.success) { + getUpcomingStaysFailCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + error_type: "validation_error", + error: JSON.stringify(verifiedData.error), + }) console.error( "api.booking.stays.future validation error ", JSON.stringify({ @@ -491,6 +608,9 @@ export const userQueryRouter = router({ ) return null } + getUpcomingStaysSuccessCounter.add(1, { + query: JSON.stringify({ params: params.toString() }), + }) console.info("api.booking.stays.future success", { query: { params: params.toString() }, }) @@ -517,6 +637,7 @@ export const userQueryRouter = router({ .input(friendTransactionsInput) .query(async ({ ctx, input }) => { const { limit, page } = input + getFriendTransactionsCounter.add(1) console.info( "api.transaction.friendTransactions start", JSON.stringify({}) @@ -541,6 +662,14 @@ export const userQueryRouter = router({ // throw internalServerError() // } const text = await apiResponse.text() + getFriendTransactionsFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.transaction.friendTransactions error ", JSON.stringify({ @@ -557,6 +686,10 @@ export const userQueryRouter = router({ const apiJson = await apiResponse.json() const verifiedData = getFriendTransactionsSchema.safeParse(apiJson) if (!verifiedData.success) { + getFriendTransactionsFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(verifiedData.error), + }) console.error( "api.transaction.friendTransactions validation error ", JSON.stringify({ error: verifiedData.error }) @@ -564,6 +697,7 @@ export const userQueryRouter = router({ return null } + getFriendTransactionsSuccessCounter.add(1) console.info( "api.transaction.friendTransactions success", JSON.stringify({}) @@ -624,6 +758,7 @@ export const userQueryRouter = router({ }), creditCards: protectedProcedure.query(async function ({ ctx }) { + getCreditCardsCounter.add(1) console.info("api.profile.creditCards start", JSON.stringify({})) const apiResponse = await api.get(api.endpoints.v1.creditCards, { cache: "no-store", @@ -634,6 +769,14 @@ export const userQueryRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() + getCreditCardsFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) console.error( "api.profile.creditCards error ", JSON.stringify({ @@ -650,17 +793,23 @@ export const userQueryRouter = router({ const apiJson = await apiResponse.json() const verifiedData = creditCardsSchema.safeParse(apiJson) if (!verifiedData.success) { + getCreditCardsFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(verifiedData.error), + }) console.error( "api.profile.creditCards validation error ", JSON.stringify({ error: verifiedData.error }) ) return null } + getCreditCardsSuccessCounter.add(1) console.info("api.profile.creditCards success", JSON.stringify({})) return verifiedData.data.data }), membershipCards: protectedProcedure.query(async function ({ ctx }) { + getProfileCounter.add(1) console.info("api.profile start", JSON.stringify({})) const apiResponse = await api.get(api.endpoints.v1.profile, { cache: "no-store", @@ -681,7 +830,15 @@ export const userQueryRouter = router({ // throw internalServerError() // } const text = await apiResponse.text() - console.log( + getProfileFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) + console.error( "api.profile error", JSON.stringify({ error: { @@ -700,12 +857,17 @@ export const userQueryRouter = router({ ) if (!verifiedData.success) { + getProfileFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(verifiedData), + }) console.error( "api.profile validation error", JSON.stringify({ error: verifiedData }) ) return null } + getProfileSuccessCounter.add(1) console.info("api.profile success", JSON.stringify({})) const cards = getMembershipCards(verifiedData.data)