diff --git a/apps/scandic-web/actions/editProfile.ts b/apps/scandic-web/actions/editProfile.ts index 1b077ee58..848ca2d7c 100644 --- a/apps/scandic-web/actions/editProfile.ts +++ b/apps/scandic-web/actions/editProfile.ts @@ -2,6 +2,7 @@ import { z } from "zod" +import { logger } from "@scandic-hotels/common/logger" import { phoneValidator } from "@scandic-hotels/common/utils/zod/phoneValidator" import * as api from "@scandic-hotels/trpc/api" import { ApiLang } from "@scandic-hotels/trpc/constants/apiLang" @@ -47,7 +48,7 @@ export const editProfile = protectedServerActionProcedure const intl = await getIntl() const payload = editProfilePayload.safeParse(input) if (!payload.success) { - console.error( + logger.error( "editProfile payload validation error", JSON.stringify({ query: input, @@ -70,7 +71,7 @@ export const editProfile = protectedServerActionProcedure const profile = await getProfile() if (!profile || "error" in profile) { - console.error( + logger.error( "editProfile profile fetch error", JSON.stringify({ query: input, @@ -144,7 +145,7 @@ export const editProfile = protectedServerActionProcedure status: Status.success, } } else { - console.log( + logger.debug( `[edit profile: ${profile.membershipNumber}] body keys: ${JSON.stringify(Object.keys(body))}` ) } @@ -159,7 +160,7 @@ export const editProfile = protectedServerActionProcedure if (!apiResponse.ok) { const text = await apiResponse.text() - console.error( + logger.error( "editProfile api patch error", JSON.stringify({ query: input, @@ -184,7 +185,7 @@ export const editProfile = protectedServerActionProcedure const json = await apiResponse.json() if (json.errors?.length) { json.errors.forEach((error: any) => { - console.warn( + logger.warn( "editProfile api patch errors (not aborting)", JSON.stringify({ query: input, @@ -196,7 +197,7 @@ export const editProfile = protectedServerActionProcedure const validatedData = editProfileSchema.safeParse(json.data.attributes) if (!validatedData.success) { - console.error( + logger.error( "editProfile validation error", JSON.stringify({ query: input, diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts b/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts index c877c0335..c957c910f 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts @@ -2,6 +2,7 @@ import { type NextRequest, NextResponse } from "next/server" import { AuthError } from "next-auth" import { Lang } from "@scandic-hotels/common/constants/language" +import { logger } from "@scandic-hotels/common/logger" import { env } from "@/env/server" import { internalServerError } from "@/server/errors/next" @@ -20,7 +21,7 @@ export async function GET( const returnUrl = request.headers.get("x-returnurl") const isSeamless = request.headers.get("x-logout-source") === "seamless" - console.log( + logger.debug( `[logout] source: ${request.headers.get("x-logout-source") || "normal"}` ) @@ -32,7 +33,7 @@ export async function GET( if (returnUrl) { redirectTo = returnUrl } else { - console.log( + logger.debug( `[login] missing returnUrl, using fallback: ${redirectToFallback}` ) redirectTo = redirectToFallback @@ -42,9 +43,9 @@ export async function GET( // Make relative URL to absolute URL if (redirectTo.startsWith("/")) { - console.log(`[logout] make redirectTo absolute, from ${redirectTo}`) + logger.debug(`[logout] make redirectTo absolute, from ${redirectTo}`) redirectTo = new URL(redirectTo, publicURL).href - console.log(`[logout] make redirectTo absolute, to ${redirectTo}`) + logger.debug(`[logout] make redirectTo absolute, to ${redirectTo}`) } try { @@ -72,21 +73,21 @@ export async function GET( break } const redirectUrl = new URL(redirectUrlValue) - console.log( + logger.debug( `[logout] creating redirect to seamless logout: ${redirectUrl}` ) redirectTo = redirectUrl.toString() } catch (e) { - console.error( - "Unable to create URL for seamless logout, proceeding without it." + logger.error( + "Unable to create URL for seamless logout, proceeding without it.", + e ) - console.error(e) } } try { redirectTo = `${env.CURITY_ISSUER_USER}/authn/authenticate/logout?redirect_uri=${encodeURIComponent(redirectTo)}` - console.log(`[logout] final redirectUrl: ${redirectTo}`) + logger.debug(`[logout] final redirectUrl: ${redirectTo}`) /** * Passing `redirect: false` to `signOut` will return a result object @@ -99,16 +100,16 @@ export async function GET( }) if (redirectUrlObj) { - console.log(`[logout] redirecting to: ${redirectUrlObj.redirect}`) + logger.debug(`[logout] redirecting to: ${redirectUrlObj.redirect}`) return NextResponse.redirect(redirectUrlObj.redirect) } else { - console.error(`[logout] missing redirectUrlObj reponse from signOut()`) + logger.error(`[logout] missing redirectUrlObj reponse from signOut()`) } } catch (error) { if (error instanceof AuthError) { - console.log({ signOutAuthError: error }) + logger.error("signOutAuthError", { signOutAuthError: error }) } else { - console.log({ signOutError: error }) + logger.error("signOutError", { signOutError: error }) } } diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/error.tsx b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/error.tsx index 61f2134c5..b012cf574 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/error.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/error.tsx @@ -4,6 +4,8 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" + export default function Error({ error, }: { @@ -14,7 +16,7 @@ export default function Error({ useEffect(() => { if (!error) return - console.error({ breadcrumbsError: error }) + logger.error("Breadcrumbs Error", { breadcrumbsError: error }) Sentry.captureException(error) }, [error]) diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/error.tsx b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/error.tsx index 3e2981d47..f10d320a0 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/error.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/error.tsx @@ -4,6 +4,8 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" + export default function Error({ error, }: { @@ -14,7 +16,7 @@ export default function Error({ useEffect(() => { if (!error) return - console.error(error) + logger.error("My Pages", error) Sentry.captureException(error) }, [error]) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_overview_page/[uid]/error.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_overview_page/[uid]/error.tsx index e1d49695c..3025a8599 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_overview_page/[uid]/error.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_overview_page/[uid]/error.tsx @@ -4,6 +4,8 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" + import { DestinationOverviewPageError } from "@/components/ContentType/DestinationPage/DestinationOverviewPage/error" export default function Error({ @@ -16,7 +18,7 @@ export default function Error({ useEffect(() => { if (!error) return - console.error(error) + logger.error("Destination overview page", error) Sentry.captureException(error) }, [error]) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/dtmc/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/dtmc/route.ts index de09e6690..8de89273b 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/dtmc/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/dtmc/route.ts @@ -1,6 +1,8 @@ import { NextResponse } from "next/server" import { AuthError } from "next-auth" +import { logger } from "@scandic-hotels/common/logger" + import { dtmcApiCallback } from "@/constants/routes/dtmc" import { env } from "@/env/server" import { internalServerError, serviceUnavailable } from "@/server/errors/next" @@ -21,22 +23,22 @@ export async function GET() { ) if (redirectUrl) { - console.log(`[dtmc] redirecting to: ${redirectUrl}`) + logger.debug(`[dtmc] redirecting to: ${redirectUrl}`) return NextResponse.redirect(redirectUrl) } else { - console.error(`[dtmc] missing redirectUrl response from signIn()`) + logger.error(`[dtmc] missing redirectUrl response from signIn()`) return internalServerError( "[dtmc] Missing redirect URL from authentication service" ) } } catch (error) { if (error instanceof AuthError) { - console.error({ signInAuthError: error }) + logger.error("signInAuthError", { signInAuthError: error }) return serviceUnavailable( "[dtmc] Microsoft authentication service unavailable" ) } else { - console.error({ signInError: error }) + logger.error("signInError", { signInError: error }) return internalServerError( "[dtmc] Unexpected error during authentication" ) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx index f45b857a2..3bb7ec960 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx @@ -1,6 +1,7 @@ import { notFound } from "next/navigation" import { myStay } from "@scandic-hotels/common/constants/routes/myStay" +import { logger } from "@scandic-hotels/common/logger" import { BookingErrorCodeEnum } from "@scandic-hotels/trpc/enums/bookingErrorCode" import { PaymentCallbackStatusEnum } from "@/constants/booking" @@ -25,7 +26,7 @@ export default async function GuaranteePaymentCallbackPage( ) { const searchParams = await props.searchParams const params = await props.params - console.log(`[gla-payment-callback] callback started`) + logger.debug(`[gla-payment-callback] callback started`) const lang = params.lang const status = searchParams.status const confirmationNumber = searchParams.confirmationNumber @@ -49,7 +50,7 @@ export default async function GuaranteePaymentCallbackPage( /> ) } - console.log(`[gla-payment-callback] redirecting to: ${myStayUrl}`) + logger.debug(`[gla-payment-callback] redirecting to: ${myStayUrl}`) return } @@ -76,7 +77,7 @@ export default async function GuaranteePaymentCallbackPage( : BookingErrorCodeEnum.TransactionFailed ) } catch { - console.error( + logger.error( `[gla-payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` ) if (status === PaymentCallbackStatusEnum.Cancel) { @@ -86,7 +87,10 @@ export default async function GuaranteePaymentCallbackPage( errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}` } } - console.log(errorMessage) + + if (errorMessage) { + logger.error(errorMessage) + } if (isAncillaryFlow) { searchObject.set("ancillary", "ancillary") diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx index 39d0b0d27..a9f1764c8 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -1,5 +1,6 @@ import { notFound } from "next/navigation" +import { logger } from "@scandic-hotels/common/logger" import { getServiceToken } from "@scandic-hotels/common/tokenManager" import { BookingErrorCodeEnum } from "@scandic-hotels/trpc/enums/bookingErrorCode" import { getBooking } from "@scandic-hotels/trpc/routers/booking/utils" @@ -31,13 +32,13 @@ export default async function PaymentCallbackPage( ) { const searchParams = await props.searchParams const params = await props.params - console.log(`[payment-callback] callback started`) + logger.debug(`[payment-callback] callback started`) const lang = params.lang const status = searchParams.status const confirmationNumber = searchParams.confirmationNumber if (!status || !confirmationNumber) { - console.error( + logger.error( `[payment-callback] missing status or confirmationNumber in search params` ) notFound() @@ -71,7 +72,7 @@ export default async function PaymentCallbackPage( } if (!token) { - console.error( + logger.error( `[payment-callback] no token found for user, cannot fetch booking` ) notFound() @@ -89,7 +90,7 @@ export default async function PaymentCallbackPage( const expire = Math.floor(Date.now() / 1000) + 60 const sig = encrypt(expire.toString()) const confirmationUrl = `${bookingConfirmation(lang)}?RefId=${encodeURIComponent(refId)}` - console.log( + logger.debug( `[payment-callback] rendering success callback with confirmation number: ${confirmationNumber}` ) @@ -126,7 +127,7 @@ export default async function PaymentCallbackPage( : BookingErrorCodeEnum.TransactionFailed ) } catch { - console.error( + logger.error( `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` ) searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed) @@ -135,7 +136,7 @@ export default async function PaymentCallbackPage( } if (status === PaymentCallbackStatusEnum.Error) { - console.error( + logger.error( `[payment-callback] error status received for ${confirmationNumber}, status: ${status}` ) searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts index 0e1fca3d5..d678effb7 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts @@ -2,6 +2,7 @@ import { type NextRequest, NextResponse } from "next/server" import { AuthError } from "next-auth" import { Lang } from "@scandic-hotels/common/constants/language" +import { logger } from "@scandic-hotels/common/logger" import { env } from "@/env/server" import { internalServerError } from "@/server/errors/next" @@ -25,7 +26,7 @@ export async function GET( const isSeamlessMagicLink = request.headers.get("x-login-source") === "seamless-magiclink" - console.log( + logger.debug( `[login] source: ${request.headers.get("x-login-source") || "normal"}` ) @@ -34,8 +35,8 @@ export async function GET( request.nextUrl.searchParams.get("redirectTo") const redirectToFallback = "/" - console.log(`[login] redirectTo cookie value: ${redirectToCookieValue}`) - console.log( + logger.debug(`[login] redirectTo cookie value: ${redirectToCookieValue}`) + logger.debug( `[login] redirectTo search param value: ${redirectToSearchParamValue}` ) @@ -43,7 +44,7 @@ export async function GET( if (returnUrl) { redirectTo = returnUrl } else { - console.log( + logger.debug( `[login] missing returnUrl, using fallback: ${redirectToFallback}` ) redirectTo = redirectToFallback @@ -54,9 +55,9 @@ export async function GET( // Make relative URL to absolute URL if (redirectTo.startsWith("/")) { - console.log(`[login] make redirectTo absolute, from ${redirectTo}`) + logger.debug(`[login] make redirectTo absolute, from ${redirectTo}`) redirectTo = new URL(redirectTo, publicURL).href - console.log(`[login] make redirectTo absolute, to ${redirectTo}`) + logger.debug(`[login] make redirectTo absolute, to ${redirectTo}`) } // Clean up cookie from authRequired middleware @@ -90,9 +91,11 @@ export async function GET( break } const redirectUrl = new URL(redirectUrlValue) - console.log(`[login] creating redirect to seamless login: ${redirectUrl}`) + logger.debug( + `[login] creating redirect to seamless login: ${redirectUrl}` + ) redirectUrl.searchParams.set("returnurl", redirectTo) - console.log( + logger.debug( `[login] returnurl for seamless login: ${redirectUrl.searchParams.get("returnurl")}` ) redirectTo = redirectUrl.toString() @@ -105,7 +108,7 @@ export async function GET( "; Max-Age=300; Path=/; HttpOnly; SameSite=Lax" ) } catch (e) { - console.error( + logger.error( "[login] unable to create URL for seamless login, proceeding without it.", e ) @@ -113,7 +116,7 @@ export async function GET( } try { - console.log(`[login] final redirectUrl: ${redirectTo}`) + logger.debug(`[login] final redirectUrl: ${redirectTo}`) /** Record is next-auth typings */ const params: Record = { @@ -174,16 +177,16 @@ export async function GET( const redirectOpts = { headers: redirectHeaders, } - console.log(`[login] redirecting to: ${redirectUrl}`, redirectOpts) + logger.debug(`[login] redirecting to: ${redirectUrl}`, redirectOpts) return NextResponse.redirect(redirectUrl, redirectOpts) } else { - console.error(`[login] missing redirectUrl reponse from signIn()`) + logger.error(`[login] missing redirectUrl reponse from signIn()`) } } catch (error) { if (error instanceof AuthError) { - console.error({ signInAuthError: error }) + logger.error("signInAuthError", { signInAuthError: error }) } else { - console.error({ signInError: error }) + logger.error("signInError", { signInError: error }) } } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts index dbc162dd2..1fc85b77c 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts @@ -1,6 +1,8 @@ import { type NextRequest, NextResponse } from "next/server" import { AuthError } from "next-auth" +import { logger } from "@scandic-hotels/common/logger" + import { badRequest, internalServerError } from "@/server/errors/next" import { getPublicURL } from "@/server/utils" @@ -16,7 +18,7 @@ export async function GET( const loginKey = request.nextUrl.searchParams.get("loginKey") if (!loginKey) { - console.log( + logger.debug( `[verifymagiclink] missing required loginKey, aborting bad request` ) return badRequest() @@ -24,14 +26,14 @@ export async function GET( let redirectTo: string - console.log(`[verifymagiclink] verifying callback`) + logger.debug(`[verifymagiclink] verifying callback`) const redirectToCookieValue = request.cookies.get( "magicLinkRedirectTo" )?.value // Set redirect url from the magicLinkRedirect Cookie which is set when intiating login const redirectToFallback = "/" - console.log( + logger.debug( `[verifymagiclink] magicLinkRedirectTo cookie value: ${redirectToCookieValue}` ) @@ -39,11 +41,11 @@ export async function GET( // Make relative URL to absolute URL if (redirectTo.startsWith("/")) { - console.log( + logger.debug( `[verifymagiclink] make redirectTo absolute, from ${redirectTo}` ) redirectTo = new URL(redirectTo, publicURL).href - console.log(`[verifymagiclink] make redirectTo absolute, to ${redirectTo}`) + logger.debug(`[verifymagiclink] make redirectTo absolute, to ${redirectTo}`) } // Update Seamless login url as Magic link login has a different authenticator in Curity @@ -59,7 +61,7 @@ export async function GET( ) try { - console.log(`[verifymagiclink] final redirectUrl: ${redirectTo}`) + logger.debug(`[verifymagiclink] final redirectUrl: ${redirectTo}`) const params = await context.params /** @@ -92,18 +94,18 @@ export async function GET( ) if (redirectUrl) { - console.log(`[verifymagiclink] redirecting to: ${redirectUrl}`) + logger.debug(`[verifymagiclink] redirecting to: ${redirectUrl}`) return NextResponse.redirect(redirectUrl) } else { - console.error( + logger.error( `[verifymagiclink] missing redirectUrl reponse from signIn()` ) } } catch (error) { if (error instanceof AuthError) { - console.error({ signInAuthError: error }) + logger.error("signInAuthError", { signInAuthError: error }) } else { - console.error({ signInError: error }) + logger.error("signInError", { signInError: error }) } } diff --git a/apps/scandic-web/app/[lang]/(live)/error.tsx b/apps/scandic-web/app/[lang]/(live)/error.tsx index 9a25c0283..57d6d5418 100644 --- a/apps/scandic-web/app/[lang]/(live)/error.tsx +++ b/apps/scandic-web/app/[lang]/(live)/error.tsx @@ -5,6 +5,7 @@ import { useParams, useRouter, useSearchParams } from "next/navigation" import { startTransition, useEffect, useRef } from "react" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { SESSION_EXPIRED } from "@scandic-hotels/trpc/errors" import { login } from "@/constants/routes/handleAuth" @@ -31,14 +32,13 @@ export default function Error({ useEffect(() => { if (!error) return - console.error(error) - if (error.message === SESSION_EXPIRED) { const loginUrl = login[params.lang] window.location.assign(loginUrl) return } + logger.error("(live)/error", error) Sentry.captureException(error) }, [error, params.lang]) diff --git a/apps/scandic-web/app/[lang]/(live-current)/@header/error.tsx b/apps/scandic-web/app/[lang]/(live-current)/@header/error.tsx index 35c0831b1..c680c37bd 100644 --- a/apps/scandic-web/app/[lang]/(live-current)/@header/error.tsx +++ b/apps/scandic-web/app/[lang]/(live-current)/@header/error.tsx @@ -3,6 +3,8 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" +import { logger } from "@scandic-hotels/common/logger" + export default function Error({ error, }: { @@ -11,7 +13,7 @@ export default function Error({ useEffect(() => { if (!error) return - console.error(error) + logger.error("header", error) Sentry.captureException(error) }, [error]) diff --git a/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx b/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx index e203827a1..7ce43e125 100644 --- a/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx +++ b/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx @@ -1,5 +1,6 @@ import { notFound } from "next/navigation" +import { logger } from "@scandic-hotels/common/logger" import { GetCurrentBlockPage } from "@scandic-hotels/trpc/graphql/Query/Current/CurrentBlockPage.graphql" import { GetCurrentBlockPageTrackingData } from "@scandic-hotels/trpc/graphql/Query/Current/CurrentBlockPageTrackingData.graphql" import { request } from "@scandic-hotels/trpc/graphql/request" @@ -34,9 +35,12 @@ export default async function CurrentContentPage( ) if (!response.data?.all_current_blocks_page?.total) { - console.log("#### DATA ####") - console.log(response.data) - console.log("SearchParams URI: ", searchParams.uri) + logger.debug( + "#### DATA ####", + response.data, + "SearchParams URI: ", + searchParams.uri + ) throw new Error("Not found") } diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts index c2e084104..1ebf472ca 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts @@ -2,6 +2,7 @@ import { cookies } from "next/headers" import { redirect } from "next/navigation" import { z } from "zod" +import { logger } from "@scandic-hotels/common/logger" import { safeTry } from "@scandic-hotels/common/utils/safeTry" import { SAS_TOKEN_STORAGE_KEY } from "@scandic-hotels/trpc/constants/partnerSAS" @@ -35,7 +36,7 @@ export async function GET( }) if (!result.success) { - console.error("[SAS] Invalid search params", result.error) + logger.error("[SAS] Invalid search params", result.error) redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_query`) } const { code, state } = result.data @@ -62,7 +63,7 @@ export async function GET( if (!tokenResponse.ok) { const error = await tokenResponse.text() - console.error("[SAS] Failed to get token", error) + logger.error("[SAS] Failed to get token", error) redirect(`/${lang}/sas-x-scandic/error?errorCode=token_error`) } @@ -90,7 +91,7 @@ export async function GET( const caller = await serverClient() const [data, error] = await safeTry(caller.partner.sas.requestOtp()) if (!data || error) { - console.error("[SAS] Failed to request OTP", error) + logger.error("[SAS] Failed to request OTP", error) redirect(`/${lang}/sas-x-scandic/error`) } @@ -107,7 +108,7 @@ export async function GET( throw new Error(`Unhandled request OTP status ${data.status}`) } - console.log("[SAS] Request OTP response", data) + logger.debug("[SAS] Request OTP response", data) const otpUrl = new URL( `/${lang}/sas-x-scandic/otp`, diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx index bf1c9a7f2..adb761e3a 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx @@ -4,6 +4,7 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { Typography } from "@scandic-hotels/design-system/Typography" import { GenericError } from "./components/GenericError" @@ -19,7 +20,7 @@ export default function Error({ useEffect(() => { if (!error) return - console.error(error) + logger.error("sas-x-scandic", error) Sentry.captureException(error) }, [error]) diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx index b3eb37cf2..515210f00 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx @@ -3,6 +3,7 @@ import { redirect } from "next/navigation" import { z } from "zod" import { myPages } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { safeTry } from "@scandic-hotels/common/utils/safeTry" import { SAS_TOKEN_STORAGE_KEY, @@ -173,7 +174,7 @@ async function handleLinkAccount({ const caller = await serverClient() const [res, error] = await safeTry(caller.partner.sas.linkAccount()) if (!res || error) { - console.error("[SAS] link account error", error) + logger.error("[SAS] link account error", error) return { url: `/${lang}/sas-x-scandic/error`, } @@ -216,7 +217,7 @@ async function handleUnlinkAccount({ const caller = await serverClient() const [res, error] = await safeTry(caller.partner.sas.unlinkAccount()) if (!res || error) { - console.error("[SAS] unlink account error", error) + logger.error("[SAS] unlink account error", error) return { url: `/${lang}/sas-x-scandic/error`, } @@ -266,7 +267,7 @@ async function handleTransferPoints({ ) if (!res || error || res.transferState === "error") { - console.error("[SAS] transfer points error", error) + logger.error("[SAS] transfer points error", error) return { url: `/${lang}/sas-x-scandic/error`, type: "replace", @@ -274,14 +275,14 @@ async function handleTransferPoints({ } if (res.transferState === "notLinked") { - console.warn("[SAS] transfer points not linked") + logger.warn("[SAS] transfer points not linked") return { url: `/${lang}/sas-x-scandic/link`, type: "replace", } } - console.log("[SAS] transfer points response", res) + logger.debug("[SAS] transfer points response", res) return { url: `/${lang}/sas-x-scandic/transfer/success?p=${points}`, diff --git a/apps/scandic-web/app/[lang]/webview/(views)/[contentType]/[uid]/page.tsx b/apps/scandic-web/app/[lang]/webview/(views)/[contentType]/[uid]/page.tsx index 76b5871ef..1161b9b8d 100644 --- a/apps/scandic-web/app/[lang]/webview/(views)/[contentType]/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/webview/(views)/[contentType]/[uid]/page.tsx @@ -1,5 +1,7 @@ import { notFound } from "next/navigation" +import { logger } from "@scandic-hotels/common/logger" + import AccountPage from "@/components/Webviews/AccountPage" import LoyaltyPage from "@/components/Webviews/LoyaltyPage" @@ -22,7 +24,7 @@ export default async function ContentTypePage( return default: const type: never = params.contentType - console.error(`Unsupported content type given: ${type}`) + logger.error(`Unsupported content type given: ${type}`) notFound() } } diff --git a/apps/scandic-web/app/[lang]/webview/(views)/layout.tsx b/apps/scandic-web/app/[lang]/webview/(views)/layout.tsx index fab9288b8..32d2229f5 100644 --- a/apps/scandic-web/app/[lang]/webview/(views)/layout.tsx +++ b/apps/scandic-web/app/[lang]/webview/(views)/layout.tsx @@ -1,6 +1,9 @@ +import * as Sentry from "@sentry/nextjs" import { headers } from "next/headers" import { redirect } from "next/navigation" +import { logger } from "@scandic-hotels/common/logger" + import { getProfile } from "@/lib/trpc/memoizedRequests" import { getIntl } from "@/i18n" @@ -17,7 +20,7 @@ export default async function Layout( const user = await getProfile() if (!user) { - console.log(`[webview:page] unable to load user`) + logger.debug(`[webview:page] unable to load user`) return (

{intl.formatMessage({ @@ -35,7 +38,9 @@ export default async function Layout( const headersList = await headers() const returnURL = `/${params.lang}/webview${headersList.get("x-pathname")!}` const redirectURL = `/${params.lang}/webview/refresh?returnUrl=${encodeURIComponent(returnURL)}` - console.log(`[webview:page] user error, redirecting to: ${redirectURL}`) + logger.debug( + `[webview:page] user error, redirecting to: ${redirectURL}` + ) redirect(redirectURL) case "notfound": return ( @@ -55,7 +60,8 @@ export default async function Layout( ) default: const u: never = user - console.log("[webview:page] unhandled user loading error", u) + logger.error("[webview:page] unhandled user loading error", u) + Sentry.captureMessage("[webview:page] unhandled user loading error", u) } } diff --git a/apps/scandic-web/app/api/debug/route.ts b/apps/scandic-web/app/api/debug/route.ts index 1cb663d96..2feb9b339 100644 --- a/apps/scandic-web/app/api/debug/route.ts +++ b/apps/scandic-web/app/api/debug/route.ts @@ -1,6 +1,8 @@ import { notFound } from "next/navigation" import { NextResponse } from "next/server" +import { logger } from "@scandic-hotels/common/logger" + import { env } from "@/env/server" import { auth } from "@/auth" @@ -11,6 +13,6 @@ export const GET = async () => { } const user = await auth() - console.log("[DEBUG] access-token", user?.token) + logger.debug("[DEBUG] access-token", user?.token) return NextResponse.json(user) } diff --git a/apps/scandic-web/app/api/hoteldata/route.ts b/apps/scandic-web/app/api/hoteldata/route.ts index caeab048e..9173ec111 100644 --- a/apps/scandic-web/app/api/hoteldata/route.ts +++ b/apps/scandic-web/app/api/hoteldata/route.ts @@ -1,5 +1,6 @@ import { type NextRequest, NextResponse } from "next/server" +import { logger } from "@scandic-hotels/common/logger" import { languageSchema } from "@scandic-hotels/common/utils/languages" import { env } from "@/env/server" @@ -9,7 +10,7 @@ export const dynamic = "force-dynamic" export async function GET(request: NextRequest) { if (!env.ENABLE_WARMUP_HOTEL) { - console.log("[WARMUP] Warmup hotel data is disabled") + logger.info("[WARMUP] Warmup hotel data is disabled") return NextResponse.json( { message: "Warmup hotel data is disabled" }, { status: 200 } @@ -32,7 +33,7 @@ export async function GET(request: NextRequest) { }) return NextResponse.json(hotels) } catch (error) { - console.error("[WARMUP] error", error) + logger.error("[WARMUP] error", error) return NextResponse.json( { error: "Failed to fetch all hotels", diff --git a/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts b/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts index 2d9ba028a..20ba88a00 100644 --- a/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts +++ b/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts @@ -1,5 +1,6 @@ import { Lang } from "@scandic-hotels/common/constants/language" import { profile } from "@scandic-hotels/common/constants/routes/myPages" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { serverClient } from "@/lib/trpc/server" import { getPublicURL } from "@/server/utils" @@ -10,10 +11,12 @@ export async function GET( request: NextRequest, props: { params: Promise<{ lang: string }> } ) { + const addCardLogger = createLogger("add-card") + const params = await props.params const publicURL = getPublicURL(request) - console.log(`[add-card] callback started`) + addCardLogger.debug(`[add-card] callback started`) const lang = params.lang as Lang const returnUrl = new URL(`${publicURL}/${profile[lang ?? Lang.en]}`) @@ -32,28 +35,28 @@ export async function GET( }) if (saveCardSuccess) { - console.log(`[add-card] planet success: card saved success`) + addCardLogger.debug(`[add-card] planet success: card saved success`) returnUrl.searchParams.set("success", "true") } else { - console.log(`[add-card] planet success: card saved fail`) + addCardLogger.debug(`[add-card] planet success: card saved fail`) returnUrl.searchParams.set("failure", "true") } } else { - console.log(`[add-card] planet success: missing datatransTrxId`) + addCardLogger.debug(`[add-card] planet success: missing datatransTrxId`) returnUrl.searchParams.set("error", "true") } } else if (failure) { - console.log(`[add-card] planet fail`) + addCardLogger.debug(`[add-card] planet fail`) returnUrl.searchParams.set("failure", "true") } else if (cancel) { - console.log(`[add-card] planet cancel`) + addCardLogger.debug(`[add-card] planet cancel`) returnUrl.searchParams.set("cancel", "true") } } catch (e) { - console.error(`[add-card] error saving credit card`, e) + addCardLogger.error(`[add-card] error saving credit card`, e) returnUrl.searchParams.set("error", "true") } - console.log(`[add-card] redirecting to: ${returnUrl}`) + addCardLogger.debug(`[add-card] redirecting to: ${returnUrl}`) return Response.redirect(returnUrl) } diff --git a/apps/scandic-web/app/api/web/auth/dtmc/route.ts b/apps/scandic-web/app/api/web/auth/dtmc/route.ts index 221eca05b..67d988082 100644 --- a/apps/scandic-web/app/api/web/auth/dtmc/route.ts +++ b/apps/scandic-web/app/api/web/auth/dtmc/route.ts @@ -1,6 +1,7 @@ import { type NextRequest, NextResponse } from "next/server" import { overview } from "@scandic-hotels/common/constants/routes/myPages" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import * as api from "@scandic-hotels/trpc/api" import { isValidSession } from "@scandic-hotels/trpc/utils/session" @@ -13,6 +14,7 @@ import { auth } from "@/auth" import { auth as dtmcAuth } from "@/auth.dtmc" import { getLang } from "@/i18n/serverContext" +const dtmcLogger = createLogger("dtmc") interface LinkEmployeeSuccessResult { success: true } @@ -32,7 +34,7 @@ async function linkEmployeeToUser( employeeId: string, accessToken: string ): Promise { - console.log(`[dtmc] Linking employee ID ${employeeId}`) + dtmcLogger.debug(`Linking employee ID ${employeeId}`) let response: Response try { response = await api.post( @@ -45,7 +47,7 @@ async function linkEmployeeToUser( } ) } catch (networkError) { - console.error("[dtmc] Network error during API request:", networkError) + dtmcLogger.error("Network error during API request:", networkError) return { success: false, statusCode: 0, @@ -53,17 +55,17 @@ async function linkEmployeeToUser( } if (!response.ok) { - console.error(`[dtmc] API returned error status ${response.status}`) + dtmcLogger.error(`API returned error status ${response.status}`) try { const errorResponse = await response.json() - console.error(`[dtmc] API error response:`, errorResponse) + dtmcLogger.error(`API error response:`, errorResponse) } catch (parseError) { - console.warn(`[dtmc] Could not parse API error response:`, parseError) + dtmcLogger.warn(`Could not parse API error response:`, parseError) try { const errorText = await response.text() - console.error(`[dtmc] Raw error response:`, errorText) + dtmcLogger.error(`Raw error response:`, errorText) } catch { - console.error(`[dtmc] Could not read error response body`) + dtmcLogger.error(`Could not read error response body`) } } @@ -87,19 +89,19 @@ async function linkEmployeeToUser( } } - console.log(`[dtmc] API call successful - Status: ${response.status}`) - console.log( - `[dtmc] Response headers:`, + dtmcLogger.debug(`API call successful - Status: ${response.status}`) + dtmcLogger.debug( + `Response headers:`, Object.fromEntries(response.headers.entries()) ) try { const responseBody = await response.json() - console.log(`[dtmc] Response body:`, responseBody) + dtmcLogger.debug(`Response body:`, responseBody) } catch (parseError) { - console.warn(`[dtmc] Could not parse success response body:`, parseError) + dtmcLogger.warn(`Could not parse success response body:`, parseError) } - console.log(`[dtmc] Successfully linked employee ID ${employeeId}`) + dtmcLogger.debug(`Successfully linked employee ID ${employeeId}`) return { success: true } } @@ -114,20 +116,18 @@ export async function GET(request: NextRequest) { const dtmcSession = await dtmcAuth() const session = await auth() const baseUrl = getPublicURL(request) - console.log("[dtmc] DTMC Callback handler - using baseUrl:", baseUrl) + dtmcLogger.debug("DTMC Callback handler - using baseUrl:", baseUrl) if (!isValidSession(session)) { - console.error( - "[dtmc] DTMC Callback handler - No valid user session found" - ) + dtmcLogger.error("DTMC Callback handler - No valid user session found") const errorUrl = new URL(linkEmploymentError[lang], baseUrl) errorUrl.searchParams.set("error", "no_session") return NextResponse.redirect(errorUrl) } if (!isValidSession(dtmcSession)) { - console.error( - "[dtmc] DTMC Callback handler - No valid entra id session found" + dtmcLogger.error( + "DTMC Callback handler - No valid entra id session found" ) const errorUrl = new URL(linkEmploymentError[lang], baseUrl) errorUrl.searchParams.set("error", "no_entra_id_session") @@ -136,40 +136,40 @@ export async function GET(request: NextRequest) { const employeeId = dtmcSession.employeeId - console.log( - "[dtmc] DTMC Callback handler - Extracted employeeId:", + dtmcLogger.debug( + "DTMC Callback handler - Extracted employeeId:", employeeId ) if (!employeeId) { - console.error("[dtmc] DTMC Callback handler - No employeeId in session") + dtmcLogger.error("DTMC Callback handler - No employeeId in session") const errorUrl = new URL(linkEmploymentError[lang], baseUrl) errorUrl.searchParams.set("error", "missing_employee_id") return NextResponse.redirect(errorUrl) } - console.log( - "[dtmc] DTMC Callback handler - Calling linkEmployeeToUser with ID:", + dtmcLogger.debug( + "DTMC Callback handler - Calling linkEmployeeToUser with ID:", employeeId ) const accessToken = session.token.access_token if (!accessToken) { - console.error("[dtmc] DTMC Callback handler - No access token in session") + dtmcLogger.error("DTMC Callback handler - No access token in session") const errorUrl = new URL(linkEmploymentError[lang], baseUrl) errorUrl.searchParams.set("error", "missing_access_token") return NextResponse.redirect(errorUrl) } const result = await linkEmployeeToUser(employeeId, accessToken) - console.log( - "[dtmc] DTMC Callback handler - linkEmployeeToUser result:", + dtmcLogger.debug( + "DTMC Callback handler - linkEmployeeToUser result:", result ) if (!result.success) { - console.error( - "[dtmc] DTMC Callback handler - Failed to verify employment:", + dtmcLogger.error( + "DTMC Callback handler - Failed to verify employment:", `Status: ${result.statusCode}, Error: ${result.queryParam}` ) @@ -182,21 +182,21 @@ export async function GET(request: NextRequest) { return NextResponse.redirect(errorUrl) } - console.log( - "[dtmc] DTMC Callback handler - Success! Employee linked with ID:", + dtmcLogger.debug( + "DTMC Callback handler - Success! Employee linked with ID:", employeeId ) - console.log("[dtmc] overview[lang]:", overview[lang]) + dtmcLogger.debug("overview[lang]:", overview[lang]) const successUrl = new URL(overview[lang], baseUrl) successUrl.searchParams.set(DTMC_SUCCESS_BANNER_KEY, "true") - console.log( - "[dtmc] DTMC Callback handler - Redirecting to success URL:", + dtmcLogger.debug( + "DTMC Callback handler - Redirecting to success URL:", successUrl.toString() ) return NextResponse.redirect(successUrl) } catch (error) { - console.error("[dtmc] DTMC Callback handler - Error in handler:", error) + dtmcLogger.error("DTMC Callback handler - Error in handler:", error) return internalServerError() } } diff --git a/apps/scandic-web/app/api/web/revalidate/hotel/route.ts b/apps/scandic-web/app/api/web/revalidate/hotel/route.ts index a175a7adb..ad4dc8873 100644 --- a/apps/scandic-web/app/api/web/revalidate/hotel/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/hotel/route.ts @@ -4,6 +4,7 @@ import { z } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { generateHotelUrlTag } from "@scandic-hotels/trpc/utils/generateTag" import { env } from "@/env/server" @@ -24,22 +25,25 @@ const validateJsonBody = z.object({ }), }) +const revalidateHotelLogger = createLogger("revalidate-hotel") + export async function POST(request: NextRequest) { try { const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { - console.error(`Invalid Secret`) - console.error({ secret }) + revalidateHotelLogger.error(`Invalid Secret`, { secret }) return badRequest({ revalidated: false, now: Date.now() }) } const data = await request.json() const validatedData = validateJsonBody.safeParse(data) if (!validatedData.success) { - console.error("Bad validation for `validatedData` in hotel revalidation") - console.error(validatedData.error) + revalidateHotelLogger.error( + "Bad validation for `validatedData` in hotel revalidation", + validatedData.error + ) return internalServerError({ revalidated: false, now: Date.now() }) } @@ -56,21 +60,20 @@ export async function POST(request: NextRequest) { if (content_type.uid === "hotel_page") { tag = generateHotelUrlTag(locale, entry.hotel_page_id) } else { - console.error( + revalidateHotelLogger.error( `Invalid content_type, received ${content_type.uid}, expected "hotel_page"` ) return notFound({ revalidated: false, now: Date.now() }) } - console.info(`Revalidating hotel url tag: ${tag}`) + revalidateHotelLogger.info(`Revalidating hotel url tag: ${tag}`) revalidateTag(tag) const cacheClient = await getCacheClient() await cacheClient.deleteKey(tag, { fuzzy: true }) return Response.json({ revalidated: true, now: Date.now() }) } catch (error) { - console.error("Failed to revalidate tag(s) for hotel") - console.error(error) + revalidateHotelLogger.error("Failed to revalidate tag(s) for hotel", error) return internalServerError({ revalidated: false, now: Date.now() }) } } diff --git a/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts b/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts index f5a40a9cc..53262d2e1 100644 --- a/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts @@ -4,6 +4,7 @@ import { z } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { generateLoyaltyConfigTag } from "@scandic-hotels/trpc/utils/generateTag" import { env } from "@/env/server" @@ -16,6 +17,8 @@ enum LoyaltyConfigContentTypes { reward = "reward", } +const loyaltyRevalidateLogger = createLogger("loyalty-revalidate") + const validateJsonBody = z.object({ data: z.object({ content_type: z.object({ @@ -35,18 +38,18 @@ export async function POST(request: NextRequest) { const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { - console.error(`Invalid Secret`) - console.error({ secret }) + loyaltyRevalidateLogger.error(`Invalid Secret`, { secret }) return badRequest({ revalidated: false, now: Date.now() }) } const data = await request.json() const validatedData = validateJsonBody.safeParse(data) if (!validatedData.success) { - console.error( - "Bad validation for `validatedData` in loyaltyConfig revalidation" + loyaltyRevalidateLogger.error( + "Bad validation for `validatedData` in loyaltyConfig revalidation", + validatedData.error ) - console.error(validatedData.error) + return internalServerError({ revalidated: false, now: Date.now() }) } @@ -76,11 +79,11 @@ export async function POST(request: NextRequest) { entry.reward_id ) } else { - console.error("Invalid content_type") + loyaltyRevalidateLogger.error("Invalid content_type") return notFound({ revalidated: false, now: Date.now() }) } - console.info(`Revalidating loyalty config tag: ${tag}`) + loyaltyRevalidateLogger.info(`Revalidating loyalty config tag: ${tag}`) revalidateTag(tag) const cacheClient = await getCacheClient() @@ -88,8 +91,10 @@ export async function POST(request: NextRequest) { return Response.json({ revalidated: true, now: Date.now() }) } catch (error) { - console.error("Failed to revalidate tag(s) for loyalty config") - console.error(error) + loyaltyRevalidateLogger.error( + "Failed to revalidate tag(s) for loyalty config", + error + ) return internalServerError({ revalidated: false, now: Date.now() }) } } diff --git a/apps/scandic-web/app/api/web/revalidate/manually/route.ts b/apps/scandic-web/app/api/web/revalidate/manually/route.ts index b2417c355..80045f839 100644 --- a/apps/scandic-web/app/api/web/revalidate/manually/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/manually/route.ts @@ -2,6 +2,7 @@ import { revalidateTag } from "next/cache" import { headers } from "next/headers" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { generateTag } from "@scandic-hotels/trpc/utils/generateTag" import { env } from "@/env/server" @@ -9,6 +10,7 @@ import { badRequest, internalServerError } from "@/server/errors/next" import type { Lang } from "@scandic-hotels/common/constants/language" +const revalidateManuallyLogger = createLogger("revalidate-manually") // This file is primarily to be used locally to test // purging your cache for new (and old) requests export async function POST() { @@ -17,8 +19,7 @@ export async function POST() { const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { - console.error(`Invalid Secret`) - console.error({ secret }) + revalidateManuallyLogger.error(`Invalid Secret`, { secret }) return badRequest({ now: Date.now(), revalidated: false, @@ -30,8 +31,8 @@ export async function POST() { const lang = headersList.get("x-lang") if (!lang || !identifier) { - console.info(`Missing lang and/or identifier`) - console.info(`lang: ${lang}, identifier: ${identifier}`) + revalidateManuallyLogger.info(`Missing lang and/or identifier`) + revalidateManuallyLogger.info(`lang: ${lang}, identifier: ${identifier}`) return badRequest({ now: Date.now(), revalidated: false, @@ -42,18 +43,17 @@ export async function POST() { const tag = generateTag(lang as Lang, identifier, affix) - console.info( + revalidateManuallyLogger.info( `Revalidated tag for [lang: ${lang}, identifier: ${identifier}${affix ? `, affix: ${affix}` : ""}]` ) - console.info(`Tag: ${tag}`) + revalidateManuallyLogger.info(`Tag: ${tag}`) revalidateTag(tag) cacheClient.deleteKey(tag, { fuzzy: true }) return Response.json({ revalidated: true, now: Date.now() }) } catch (error) { - console.error("Failed to revalidate tag(s)") - console.error(error) + revalidateManuallyLogger.error("Failed to revalidate tag(s)", error) return internalServerError({ revalidated: false, now: Date.now() }) } } diff --git a/apps/scandic-web/app/api/web/revalidate/route.ts b/apps/scandic-web/app/api/web/revalidate/route.ts index d036dfbea..6f44f81a2 100644 --- a/apps/scandic-web/app/api/web/revalidate/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/route.ts @@ -4,6 +4,7 @@ import { z } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { affix as breadcrumbsAffix } from "@scandic-hotels/trpc/routers/contentstack/breadcrumbs/utils" import { destinationCityPageDestinationSettingsSchema } from "@scandic-hotels/trpc/routers/contentstack/destinationCityPage/output" import { languageSwitcherAffix } from "@scandic-hotels/trpc/routers/contentstack/languageSwitcher/utils" @@ -47,14 +48,14 @@ const validateJsonBody = z.object({ }), }) +const revalidateLogger = createLogger("revalidate") export async function POST(request: NextRequest) { try { const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { - console.error(`Invalid Secret`) - console.error({ secret }) + revalidateLogger.error(`Invalid Secret`, { secret }) return badRequest({ now: Date.now(), revalidated: false, @@ -64,8 +65,10 @@ export async function POST(request: NextRequest) { const data = await request.json() const validatedData = validateJsonBody.safeParse(data) if (!validatedData.success) { - console.error("Bad validation for `validatedData`") - console.error(validatedData.error) + revalidateLogger.error( + "Bad validation for `validatedData`", + validatedData.error + ) return internalServerError({ revalidated: false, now: Date.now() }) } @@ -95,37 +98,41 @@ export async function POST(request: NextRequest) { const cacheClient = await getCacheClient() const contentTypeUidTag = generateTag(entryLocale, content_type.uid) - console.info(`Revalidating tag by content_type_uid: ${contentTypeUidTag}`) + revalidateLogger.info( + `Revalidating tag by content_type_uid: ${contentTypeUidTag}` + ) revalidateTag(contentTypeUidTag) await cacheClient.deleteKey(contentTypeUidTag, { fuzzy: true }) - console.info(`Revalidating refsTag: ${refsTag}`) + revalidateLogger.info(`Revalidating refsTag: ${refsTag}`) revalidateTag(refsTag) await cacheClient.deleteKey(refsTag, { fuzzy: true }) - console.info(`Revalidating refTag: ${refTag}`) + revalidateLogger.info(`Revalidating refTag: ${refTag}`) revalidateTag(refTag) await cacheClient.deleteKey(refTag, { fuzzy: true }) - console.info(`Revalidating tag: ${tag}`) + revalidateLogger.info(`Revalidating tag: ${tag}`) revalidateTag(tag) await cacheClient.deleteKey(tag, { fuzzy: true }) - console.info(`Revalidating language switcher tag: ${languageSwitcherTag}`) + revalidateLogger.info( + `Revalidating language switcher tag: ${languageSwitcherTag}` + ) revalidateTag(languageSwitcherTag) await cacheClient.deleteKey(languageSwitcherTag, { fuzzy: true }) - console.info(`Revalidating metadataTag: ${metadataTag}`) + revalidateLogger.info(`Revalidating metadataTag: ${metadataTag}`) revalidateTag(metadataTag) await cacheClient.deleteKey(metadataTag, { fuzzy: true }) - console.info(`Revalidating contentEntryTag: ${contentEntryTag}`) + revalidateLogger.info(`Revalidating contentEntryTag: ${contentEntryTag}`) revalidateTag(contentEntryTag) await cacheClient.deleteKey(contentEntryTag, { fuzzy: true }) if (entry.url) { const resolveEntryTag = resolveEntryCacheKey(entryLocale, entry.url) - console.info(`Revalidating url: ${resolveEntryTag}`) + revalidateLogger.info(`Revalidating url: ${resolveEntryTag}`) await cacheClient.deleteKey(resolveEntryTag, { fuzzy: true }) } @@ -142,11 +149,13 @@ export async function POST(request: NextRequest) { breadcrumbsAffix ) - console.info(`Revalidating breadcrumbsRefsTag: ${breadcrumbsRefsTag}`) + revalidateLogger.info( + `Revalidating breadcrumbsRefsTag: ${breadcrumbsRefsTag}` + ) revalidateTag(breadcrumbsRefsTag) await cacheClient.deleteKey(breadcrumbsRefsTag, { fuzzy: true }) - console.info(`Revalidating breadcrumbsTag: ${breadcrumbsTag}`) + revalidateLogger.info(`Revalidating breadcrumbsTag: ${breadcrumbsTag}`) revalidateTag(breadcrumbsTag) await cacheClient.deleteKey(breadcrumbsTag, { fuzzy: true }) } @@ -158,7 +167,7 @@ export async function POST(request: NextRequest) { pageSettingsAffix ) - console.info(`Revalidating pageSettingsTag: ${pageSettingsTag}`) + revalidateLogger.info(`Revalidating pageSettingsTag: ${pageSettingsTag}`) revalidateTag(pageSettingsTag) await cacheClient.deleteKey(pageSettingsTag, { fuzzy: true }) } @@ -177,8 +186,7 @@ export async function POST(request: NextRequest) { return Response.json({ revalidated: true, now: Date.now() }) } catch (error) { - console.error("Failed to revalidate tag(s)") - console.error(error) + revalidateLogger.error("Failed to revalidate tag(s)", error) return internalServerError({ revalidated: false, now: Date.now() }) } } diff --git a/apps/scandic-web/app/api/web/warmup/route.ts b/apps/scandic-web/app/api/web/warmup/route.ts index acb0bf79c..ea6bfe219 100644 --- a/apps/scandic-web/app/api/web/warmup/route.ts +++ b/apps/scandic-web/app/api/web/warmup/route.ts @@ -1,14 +1,15 @@ import { type NextRequest, NextResponse } from "next/server" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { env } from "@/env/server" import { warmup } from "@/services/warmup" import { isWarmupKey } from "@/services/warmup/warmupKeys" -import { createLogger } from "@/utils/logger" export const dynamic = "force-dynamic" -const logger = createLogger("Warmup") +const logger = createLogger("warmup") export async function GET(req: NextRequest) { const url = new URL(req.url) diff --git a/apps/scandic-web/app/global-error.tsx b/apps/scandic-web/app/global-error.tsx index 701dc33d7..181c9ee5d 100644 --- a/apps/scandic-web/app/global-error.tsx +++ b/apps/scandic-web/app/global-error.tsx @@ -3,6 +3,8 @@ import * as Sentry from "@sentry/nextjs" import { useEffect } from "react" +import { logger } from "@scandic-hotels/common/logger" + import Image from "@/components/Image" /* eslint-disable formatjs/no-literal-string-in-jsx */ @@ -11,7 +13,7 @@ export default function GlobalError({ }: { error: Error & { digest?: string } }) { - console.log({ global_error: error }) + logger.error("Global Error", { global_error: error }) useEffect(() => { Sentry.captureException(error) diff --git a/apps/scandic-web/app/sitemap/[sitemapId]/route.ts b/apps/scandic-web/app/sitemap/[sitemapId]/route.ts index 0da6e4125..91a44a702 100644 --- a/apps/scandic-web/app/sitemap/[sitemapId]/route.ts +++ b/apps/scandic-web/app/sitemap/[sitemapId]/route.ts @@ -1,11 +1,14 @@ import { notFound } from "next/navigation" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { getSitemapDataById } from "@/utils/sitemap" import type { NextRequest } from "next/server" export const dynamic = "force-dynamic" +const sitemapLogger = createLogger("sitemap") export async function GET( _request: NextRequest, context: { params: Promise<{ sitemapId: string }> } @@ -13,7 +16,7 @@ export async function GET( const params = await context.params const sitemapId = params.sitemapId - console.log("[SITEMAP] Fetching sitemap by ID", sitemapId) + sitemapLogger.debug("Fetching sitemap by ID", sitemapId) if (!sitemapId) { return notFound() diff --git a/apps/scandic-web/app/sitemap/route.ts b/apps/scandic-web/app/sitemap/route.ts index 54a1f7148..700080bf9 100644 --- a/apps/scandic-web/app/sitemap/route.ts +++ b/apps/scandic-web/app/sitemap/route.ts @@ -1,11 +1,14 @@ +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { env } from "@/env/server" import { getLastUpdated, getSitemapIds } from "@/utils/sitemap" export const dynamic = "force-dynamic" +const sitemapLogger = createLogger("sitemap") export async function GET() { - console.log(`[SITEMAP] Fetching sitemap`) + sitemapLogger.debug(`Fetching sitemap`) const lastUpdated = await getLastUpdated() @@ -15,7 +18,7 @@ export async function GET() { return new Response("No sitemaps found", { status: 404 }) } - console.log(`[SITEMAP] Sitemaps retrieved: ${sitemaps.length}`) + sitemapLogger.debug(`Sitemaps retrieved: ${sitemaps.length}`) const urls = sitemaps.map( (id) => ` diff --git a/apps/scandic-web/auth.dtmc.ts b/apps/scandic-web/auth.dtmc.ts index d8e4e9b8b..06e014d13 100644 --- a/apps/scandic-web/auth.dtmc.ts +++ b/apps/scandic-web/auth.dtmc.ts @@ -1,6 +1,8 @@ import NextAuth, { type NextAuthConfig } from "next-auth" import MicrosoftEntraID from "next-auth/providers/microsoft-entra-id" +import { logger } from "@scandic-hotels/common/logger" + import { env } from "@/env/server" const config = { @@ -40,9 +42,9 @@ const config = { return session }, async redirect({ baseUrl, url }) { - console.log(`[auth.dtmc] deciding redirect URL`, { baseUrl, url }) + logger.debug(`[auth.dtmc] deciding redirect URL`, { baseUrl, url }) if (url.startsWith("/")) { - console.log( + logger.debug( `[auth.dtmc] relative URL accepted, returning: ${baseUrl}${url}` ) // Allows relative callback URLs @@ -54,22 +56,24 @@ const config = { if ( /\.scandichotels\.(dk|de|com|fi|no|se)$/.test(parsedUrl.hostname) ) { - console.log(`[auth.dtmc] subdomain URL accepted, returning: ${url}`) + logger.debug( + `[auth.dtmc] subdomain URL accepted, returning: ${url}` + ) // Allows any subdomains on all top level domains above return url } else if (parsedUrl.origin === baseUrl) { // Allows callback URLs on the same origin - console.log(`[auth.dtmc] origin URL accepted, returning: ${url}`) + logger.debug(`[auth.dtmc] origin URL accepted, returning: ${url}`) return url } } catch (e) { - console.error( + logger.error( `[auth.dtmc] error parsing incoming URL for redirection`, e ) } } - console.log(`[auth.dtmc] URL denied, returning base URL: ${baseUrl}`) + logger.debug(`[auth.dtmc] URL denied, returning base URL: ${baseUrl}`) return baseUrl }, async authorized() { diff --git a/apps/scandic-web/auth.ts b/apps/scandic-web/auth.ts index fe673d163..80bf02d98 100644 --- a/apps/scandic-web/auth.ts +++ b/apps/scandic-web/auth.ts @@ -1,5 +1,6 @@ import NextAuth, { type NextAuthConfig, type User } from "next-auth" +import { logger } from "@scandic-hotels/common/logger" import { LoginTypeEnum } from "@scandic-hotels/trpc/types/loginType" import { PRE_REFRESH_TIME_IN_SECONDS } from "@/constants/auth" @@ -24,7 +25,7 @@ async function refreshTokens(token: JWT) { throw "Refresh token missing." } - console.log("token-debug Access token expired, trying to refresh it.", { + logger.debug("token-debug Access token expired, trying to refresh it.", { expires_at: token.expires_at, sub: token.sub, token: token.access_token, @@ -46,7 +47,7 @@ async function refreshTokens(token: JWT) { const new_tokens = await response.json() if (!response.ok) { - console.log("token-debug Token response was not ok", { + logger.debug("token-debug Token response was not ok", { status: response.status, statusText: response.statusText, sub: token.sub, @@ -54,7 +55,7 @@ async function refreshTokens(token: JWT) { throw new_tokens } - console.log("token-debug Successfully got new token(s)", { + logger.debug("token-debug Successfully got new token(s)", { expires_at: new_tokens.expires_at, got_new_refresh_token: new_tokens.refresh_token !== token.refresh_token, got_new_access_token: new_tokens.access_token !== token.access_token, @@ -72,7 +73,7 @@ async function refreshTokens(token: JWT) { refresh_token: new_tokens.refresh_token, } } catch (error) { - console.log("token-debug Error thrown when trying to refresh", { + logger.error("token-debug Error thrown when trying to refresh", { error, sub: token.sub, }) @@ -141,9 +142,11 @@ const baseConfig = { return session }, async redirect({ baseUrl, url }) { - console.log(`[auth] deciding redirect URL`, { baseUrl, url }) + logger.debug(`[auth] deciding redirect URL`, { baseUrl, url }) if (url.startsWith("/")) { - console.log(`[auth] relative URL accepted, returning: ${baseUrl}${url}`) + logger.debug( + `[auth] relative URL accepted, returning: ${baseUrl}${url}` + ) // Allows relative callback URLs return `${baseUrl}${url}` } else { @@ -153,19 +156,19 @@ const baseConfig = { if ( /\.scandichotels\.(dk|de|com|fi|no|se)$/.test(parsedUrl.hostname) ) { - console.log(`[auth] subdomain URL accepted, returning: ${url}`) + logger.debug(`[auth] subdomain URL accepted, returning: ${url}`) // Allows any subdomains on all top level domains above return url } else if (parsedUrl.origin === baseUrl) { // Allows callback URLs on the same origin - console.log(`[auth] origin URL accepted, returning: ${url}`) + logger.debug(`[auth] origin URL accepted, returning: ${url}`) return url } } catch (e) { - console.error(`[auth] error parsing incoming URL for redirection`, e) + logger.error(`[auth] error parsing incoming URL for redirection`, e) } } - console.log(`[auth] URL denied, returning base URL: ${baseUrl}`) + logger.debug(`[auth] URL denied, returning base URL: ${baseUrl}`) return baseUrl }, async authorized() { diff --git a/apps/scandic-web/components/Blocks/DynamicContent/JobylonFeed/JobList/reducer.ts b/apps/scandic-web/components/Blocks/DynamicContent/JobylonFeed/JobList/reducer.ts index 3790e5972..e0614737d 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/JobylonFeed/JobList/reducer.ts +++ b/apps/scandic-web/components/Blocks/DynamicContent/JobylonFeed/JobList/reducer.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import { getFilteredJobs, getFiltersFromJobs } from "./utils" import { @@ -55,7 +57,7 @@ export function reducer(state: State, action: Action) { } default: const unhandledActionType: never = type - console.info(`Unhandled type: ${unhandledActionType}`) + logger.info(`Unhandled JobylonFeed type: ${unhandledActionType}`) return state } } diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/index.tsx index 5722bcabb..ebf7eb0ac 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/index.tsx @@ -10,6 +10,7 @@ import { } from "react-aria-components" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { trpc } from "@scandic-hotels/trpc/client" @@ -177,7 +178,7 @@ function getRedeemFlow(reward: Reward, membershipNumber: string) { case "Tier": return default: - console.warn("Unsupported reward type for redeem:", rewardType) + logger.warn("Unsupported reward type for redeem:", rewardType) return null } } diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/useRedeemFlow.ts b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/useRedeemFlow.ts index caaccd9b0..bde47ff13 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/useRedeemFlow.ts +++ b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/Redeem/useRedeemFlow.ts @@ -2,6 +2,7 @@ import { createContext, useCallback, useContext, useEffect } from "react" +import { logger } from "@scandic-hotels/common/logger" import { trpc } from "@scandic-hotels/trpc/client" import { getFirstRedeemableCoupon } from "@/utils/rewards" @@ -41,7 +42,7 @@ export default function useRedeemFlow() { setRedeemStep("redeemed") }, onError(error) { - console.error("Failed to redeem", error) + logger.error("Failed to redeem", error) }, } ) diff --git a/apps/scandic-web/components/ContentType/HotelMapPage/Sidebar/index.tsx b/apps/scandic-web/components/ContentType/HotelMapPage/Sidebar/index.tsx index ebab791b3..57565a637 100644 --- a/apps/scandic-web/components/ContentType/HotelMapPage/Sidebar/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelMapPage/Sidebar/index.tsx @@ -6,6 +6,7 @@ import { useState } from "react" import { Button as ButtonRAC } from "react-aria-components" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { Typography } from "@scandic-hotels/design-system/Typography" import { PointOfInterestGroupEnum } from "@scandic-hotels/trpc/enums/pointOfInterest" @@ -120,7 +121,7 @@ export default function Sidebar({ }) default: const option: never = group - console.warn(`Unsupported group given: ${option}`) + logger.warn(`Unsupported group given: ${option}`) return intl.formatMessage({ defaultMessage: "N/A", diff --git a/apps/scandic-web/components/ContentType/HotelPage/DialogshiftWidget/Client.tsx b/apps/scandic-web/components/ContentType/HotelPage/DialogshiftWidget/Client.tsx index f0907281a..57b88751d 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/DialogshiftWidget/Client.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/DialogshiftWidget/Client.tsx @@ -4,6 +4,8 @@ import "dialogshift-webchat-sdk/bundles/dialogshift-webchat-sdk.min.css" import { useEffect, useRef } from "react" +import { logger } from "@scandic-hotels/common/logger" + import type { Lang } from "@scandic-hotels/common/constants/language" interface DialogshiftWidgetClientProps { @@ -26,7 +28,7 @@ export default function DialogshiftWidgetClient({ locale: language, }) } catch (error) { - console.error("Failed to load Dialogshift chat:", error) + logger.error("Failed to load Dialogshift chat:", error) } } diff --git a/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx index 51facb18e..4405f7bf3 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import { getIntl } from "@/i18n" import { isFacilityCard, setFacilityCardGrids } from "@/utils/facilityCards" @@ -55,7 +57,7 @@ export default async function Facilities({ defaultMessage: "Read more", }) default: - console.warn(`Unsupported option given: ${text}`) + logger.warn(`Unsupported option given: ${text}`) return intl.formatMessage({ defaultMessage: "Read more", }) diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/Facility/utils.ts b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/Facility/utils.ts index 791420197..945985bb8 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/Facility/utils.ts +++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/Facility/utils.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import { getIntl } from "@/i18n" import { @@ -112,7 +114,7 @@ export async function translateWellnessDetails({ .sort() default: - console.warn(`Unsupported type given: ${type}`) + logger.warn(`Unsupported type given: ${type}`) } } diff --git a/apps/scandic-web/components/ContentType/HotelPage/utils.ts b/apps/scandic-web/components/ContentType/HotelPage/utils.ts index 018a7f4b0..72f830f99 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/utils.ts +++ b/apps/scandic-web/components/ContentType/HotelPage/utils.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import type { Lang } from "@scandic-hotels/common/constants/language" import type { Hotel, HotelData } from "@scandic-hotels/trpc/types/hotel" import type { HotelPage } from "@scandic-hotels/trpc/types/hotelPage" @@ -83,7 +85,7 @@ export function translateWellnessType(type: string, intl: IntlShape) { defaultMessage: "Sauna", }) default: - console.warn(`Unsupported group given: ${type}`) + logger.warn(`Unsupported wellnessType: ${type}`) return intl.formatMessage({ defaultMessage: "Wellness", }) diff --git a/apps/scandic-web/components/CookieBot/index.tsx b/apps/scandic-web/components/CookieBot/index.tsx index c3a728d3c..aa907b1d2 100644 --- a/apps/scandic-web/components/CookieBot/index.tsx +++ b/apps/scandic-web/components/CookieBot/index.tsx @@ -3,6 +3,8 @@ import { usePathname } from "next/navigation" import { useCallback, useEffect } from "react" +import { logger } from "@scandic-hotels/common/logger" + import { webviews } from "@/constants/routes/webviews" export default function CookieBotConsent() { @@ -20,7 +22,7 @@ export default function CookieBotConsent() { window.adobe.optIn.deny(window.adobe.OptInCategories.ANALYTICS, true) } window.adobe.optIn.complete() - console.warn("window.load event explicitly dispatched.") + logger.warn("window.load event explicitly dispatched.") window.dispatchEvent(new Event("load")) } }, [isWebview]) diff --git a/apps/scandic-web/components/Current/Blocks/index.tsx b/apps/scandic-web/components/Current/Blocks/index.tsx index dfb21f55b..24411e68c 100644 --- a/apps/scandic-web/components/Current/Blocks/index.tsx +++ b/apps/scandic-web/components/Current/Blocks/index.tsx @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import List from "./List" import Puffs from "./Puffs" import Text from "./Text" @@ -24,7 +26,7 @@ export default function Blocks({ blocks }: BlocksProps) { case BlocksTypenameEnum.CurrentBlocksPageBlocksText: return default: - console.log(`Unknown type: (${type})`) + logger.error(`Unknown type: (${type})`) return null } })} diff --git a/apps/scandic-web/components/Current/Tracking.tsx b/apps/scandic-web/components/Current/Tracking.tsx index c6099c68c..415ded0c4 100644 --- a/apps/scandic-web/components/Current/Tracking.tsx +++ b/apps/scandic-web/components/Current/Tracking.tsx @@ -3,6 +3,8 @@ import { usePathname, useSearchParams } from "next/navigation" import { useEffect } from "react" +import { logger } from "@scandic-hotels/common/logger" + import type { SiteSectionObject, TrackingData, @@ -82,7 +84,7 @@ export default function Tracking({ pageData }: TrackingProps) { window.adobe.optIn.deny(window.adobe.OptInCategories.ANALYTICS, true) } window.adobe.optIn.complete() - console.warn("window.load event explicitly dispatched.") + logger.warn("window.load event explicitly dispatched.") window.dispatchEvent(new Event("load")) } } diff --git a/apps/scandic-web/components/ErrorBoundary/ErrorBoundary.tsx b/apps/scandic-web/components/ErrorBoundary/ErrorBoundary.tsx index c98f90d83..5319f3281 100644 --- a/apps/scandic-web/components/ErrorBoundary/ErrorBoundary.tsx +++ b/apps/scandic-web/components/ErrorBoundary/ErrorBoundary.tsx @@ -1,6 +1,8 @@ import * as Sentry from "@sentry/nextjs" import React from "react" +import { logger } from "@scandic-hotels/common/logger" + type ErrorBoundaryProps = { children: React.ReactNode fallback?: React.ReactNode @@ -21,7 +23,7 @@ class ErrorBoundary extends React.Component< } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - console.error("ErrorBoundary caught an error:", error, errorInfo) + logger.error("ErrorBoundary caught an error:", error, errorInfo) Sentry.captureException(error, { extra: { errorInfo } }) } diff --git a/apps/scandic-web/components/Forms/BookingWidget/FormContent/Search/index.tsx b/apps/scandic-web/components/Forms/BookingWidget/FormContent/Search/index.tsx index 2138ee5cd..4895c7eea 100644 --- a/apps/scandic-web/components/Forms/BookingWidget/FormContent/Search/index.tsx +++ b/apps/scandic-web/components/Forms/BookingWidget/FormContent/Search/index.tsx @@ -6,6 +6,7 @@ import { type ChangeEvent, type FormEvent, useId } from "react" import { useFormContext, useWatch } from "react-hook-form" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { Button } from "@scandic-hotels/design-system/Button" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { Typography } from "@scandic-hotels/design-system/Typography" @@ -78,7 +79,7 @@ export function Search({ setValue("city", undefined) break default: - console.error("Unhandled type:", selectedItem.type) + logger.error("Unhandled type:", selectedItem.type) break } diff --git a/apps/scandic-web/components/Forms/Edit/Profile/index.tsx b/apps/scandic-web/components/Forms/Edit/Profile/index.tsx index 37afeab3c..678df9afe 100644 --- a/apps/scandic-web/components/Forms/Edit/Profile/index.tsx +++ b/apps/scandic-web/components/Forms/Edit/Profile/index.tsx @@ -6,6 +6,7 @@ import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { profile } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { trpc } from "@scandic-hotels/trpc/client" import { langToApiLang } from "@scandic-hotels/trpc/constants/apiLang" @@ -84,7 +85,7 @@ export default function Form({ user }: EditFormProps) { case Status.error: if (response.issues?.length) { response.issues.forEach((issue) => { - console.error(issue) + logger.error("Profile edit error:", issue) }) } toast.error(response.message) diff --git a/apps/scandic-web/components/Forms/Signup/index.tsx b/apps/scandic-web/components/Forms/Signup/index.tsx index e02ec787d..6ebf229a7 100644 --- a/apps/scandic-web/components/Forms/Signup/index.tsx +++ b/apps/scandic-web/components/Forms/Signup/index.tsx @@ -6,6 +6,7 @@ import { useRouter } from "next/navigation" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" import { Button } from "@scandic-hotels/design-system/Button" import Checkbox from "@scandic-hotels/design-system/Form/Checkbox" import { Typography } from "@scandic-hotels/design-system/Typography" @@ -69,7 +70,7 @@ export default function SignupForm({ title }: SignUpFormProps) { defaultMessage: "Something went wrong!", }) ) - console.error("Component Signup error:", error) + logger.error("Component Signup error:", error) }, }) diff --git a/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx b/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx index a36aebfde..b6c01a77a 100644 --- a/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx +++ b/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx @@ -3,6 +3,7 @@ import { createEvent } from "ics" import { useIntl } from "react-intl" import { dt } from "@scandic-hotels/common/dt" +import { logger } from "@scandic-hotels/common/logger" import { toast } from "@/components/TempDesignSystem/Toasts" import useLang from "@/hooks/useLang" @@ -25,7 +26,7 @@ export default function AddToCalendar({ createEvent(event, (error, value) => { if (error) { - console.error("ICS Error:", error) + logger.error("ICS Error:", error) toast.error( intl.formatMessage({ defaultMessage: "Failed to add to calendar", @@ -45,7 +46,7 @@ export default function AddToCalendar({ URL.revokeObjectURL(url) }) } catch (error) { - console.error("Download error:", error) + logger.error("Download error:", error) toast.error( intl.formatMessage({ defaultMessage: "Failed to add to calendar", diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers.ts b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers.ts index dc7bd85ed..93dbfdf76 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers.ts +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers.ts @@ -1,5 +1,7 @@ import "client-only" +import { logger } from "@scandic-hotels/common/logger" + export const glaStorageName = "gla-storage" type GlaSessionData = { @@ -15,7 +17,7 @@ export function readGlaFromSessionStorage(): GlaSessionData | null { if (!glaSessionData) return null return JSON.parse(glaSessionData) } catch (error) { - console.error("Error reading from session storage:", error) + logger.error("Error reading from session storage:", error) return null } } @@ -37,7 +39,7 @@ export function writeGlaToSessionStorage( }) ) } catch (error) { - console.error("Error writing to session storage:", error) + logger.error("Error writing to session storage:", error) } } diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx index ec371125a..0dc70064d 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx @@ -10,6 +10,7 @@ import { useIntl } from "react-intl" import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod" import { selectRate } from "@scandic-hotels/common/constants/routes/hotelReservation" +import { logger } from "@scandic-hotels/common/logger" import Body from "@scandic-hotels/design-system/Body" import { Button } from "@scandic-hotels/design-system/Button" import Checkbox from "@scandic-hotels/design-system/Form/Checkbox" @@ -180,7 +181,7 @@ export default function PaymentClient({ } }, onError: (error) => { - console.error("Error", error) + logger.error("Booking error", error) handlePaymentError(error.message) }, }) @@ -195,7 +196,7 @@ export default function PaymentClient({ setPriceChangeData(null) }, onError: (error) => { - console.error("Error", error) + logger.error("Price change error", error) setPriceChangeData(null) handlePaymentError(error.message) }, diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/helpers.ts b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/helpers.ts index 75a4aa716..1a3ba5868 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/helpers.ts +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/helpers.ts @@ -1,4 +1,5 @@ import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod" +import { logger } from "@scandic-hotels/common/logger" import type { RoomState } from "@/types/stores/enter-details" @@ -63,7 +64,7 @@ export function readPaymentInfoFromSessionStorage(): if (!paymentInfoSessionData) return undefined return JSON.parse(paymentInfoSessionData) } catch (error) { - console.error("Error reading from session storage:", error) + logger.error("Error reading from session storage:", error) return undefined } } @@ -81,7 +82,7 @@ export function writePaymentInfoToSessionStorage( }) ) } catch (error) { - console.error("Error writing to session storage:", error) + logger.error("Error writing to session storage:", error) } } diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/mapToPrice.ts b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/mapToPrice.ts index 5cf17ccb5..b4f50cf70 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/mapToPrice.ts +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/mapToPrice.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import { sumPackages } from "@/components/HotelReservation/utils" import type { RoomState } from "@/types/stores/enter-details" @@ -133,7 +135,7 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) { } } - console.error(room.roomRate) + logger.error("Unknown roomRate", room.roomRate) throw new Error(`Unknown roomRate`) }) } diff --git a/apps/scandic-web/components/HotelReservation/FindMyBooking/index.tsx b/apps/scandic-web/components/HotelReservation/FindMyBooking/index.tsx index e34bc1d76..843a195ae 100644 --- a/apps/scandic-web/components/HotelReservation/FindMyBooking/index.tsx +++ b/apps/scandic-web/components/HotelReservation/FindMyBooking/index.tsx @@ -6,6 +6,7 @@ import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { myStay } from "@scandic-hotels/common/constants/routes/myStay" +import { logger } from "@scandic-hotels/common/logger" import Body from "@scandic-hotels/design-system/Body" import Caption from "@scandic-hotels/design-system/Caption" import { trpc } from "@scandic-hotels/trpc/client" @@ -48,7 +49,7 @@ export default function FindMyBooking() { router.push(`${myStay[lang]}?RefId=${encodeURIComponent(result.refId)}`) }, onError: (error) => { - console.error("Failed to create ref id", error) + logger.error("Failed to create ref id", error) toast.error( intl.formatMessage({ defaultMessage: "Failed to submit form, please try again later.", diff --git a/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts b/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts index 7dabf4a78..8a0c70fed 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import type { Ancillary, SelectedAncillary, @@ -59,7 +61,7 @@ export const getAncillarySessionData = (): const storedData = sessionStorage.getItem(ancillarySessionKey) return storedData ? JSON.parse(storedData) : undefined } catch (error) { - console.error("Error reading from session storage:", error) + logger.error("Error reading from session storage:", error) return undefined } } @@ -96,7 +98,7 @@ export function setAncillarySessionData({ }) ) } catch (error) { - console.error("Error writing to session storage:", error) + logger.error("Error writing to session storage:", error) } } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx index cf4d8baa1..aa2557714 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx @@ -4,6 +4,7 @@ import { useIntl } from "react-intl" import { CurrencyEnum } from "@scandic-hotels/common/constants/currency" import { dt } from "@scandic-hotels/common/dt" +import { logger } from "@scandic-hotels/common/logger" import Body from "@scandic-hotels/design-system/Body" import Caption from "@scandic-hotels/design-system/Caption" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" @@ -122,7 +123,7 @@ export default function SelectedRoomPanel() { } if (!selectedProduct) { - console.error("Selected product is unknown") + logger.error("Selected product is unknown") return null } diff --git a/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx b/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx index 66dc1783f..6dcaa75ae 100644 --- a/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx +++ b/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx @@ -5,6 +5,7 @@ import { useEffect, useRef } from "react" import { useIntl } from "react-intl" import { partnerSas } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { trpc } from "@scandic-hotels/trpc/client" import { TIER_TO_FRIEND_MAP } from "@/constants/membershipLevels" @@ -42,7 +43,7 @@ export function SASLevelUpgradeCheck() { } }, onError() { - console.log("[sas] something went wrong") + logger.error("[sas] something went wrong") }, }) diff --git a/apps/scandic-web/components/MyPages/Surprises/Client.tsx b/apps/scandic-web/components/MyPages/Surprises/Client.tsx index 60112b11d..8ff221276 100644 --- a/apps/scandic-web/components/MyPages/Surprises/Client.tsx +++ b/apps/scandic-web/components/MyPages/Surprises/Client.tsx @@ -7,6 +7,7 @@ import { Dialog, Modal, ModalOverlay } from "react-aria-components" import { useIntl } from "react-intl" import { benefits } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { Typography } from "@scandic-hotels/design-system/Typography" import { trpc } from "@scandic-hotels/trpc/client" @@ -91,7 +92,7 @@ export default function SurprisesNotification({ ) }, onError: (error) => { - console.error("Failed to unwrap surprise", error) + logger.error("Failed to unwrap surprise", error) toast.error( <> {intl.formatMessage( diff --git a/apps/scandic-web/components/ProtectedLayout.tsx b/apps/scandic-web/components/ProtectedLayout.tsx index 576e2fd17..63546d45d 100644 --- a/apps/scandic-web/components/ProtectedLayout.tsx +++ b/apps/scandic-web/components/ProtectedLayout.tsx @@ -2,6 +2,7 @@ import { headers } from "next/headers" import { redirect } from "next/navigation" import { overview } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { isValidSession } from "@scandic-hotels/trpc/utils/session" import { getProfile } from "@/lib/trpc/memoizedRequests" @@ -26,7 +27,9 @@ export async function ProtectedLayout({ children }: React.PropsWithChildren) { const redirectURL = `/${lang}/login?redirectTo=${redirectTo}` if (!isValidSession(session)) { - console.log(`[layout:protected] no session, redirecting to: ${redirectURL}`) + logger.debug( + `[layout:protected] no session, redirecting to: ${redirectURL}` + ) redirect(redirectURL) } @@ -34,27 +37,23 @@ export async function ProtectedLayout({ children }: React.PropsWithChildren) { if (user && "error" in user) { // redirect(redirectURL) - console.error("[layout:protected] error in user", user) - console.error( - "[layout:protected] full user: ", - JSON.stringify(user, null, 4) - ) + logger.error("[layout:protected] error in user", user) switch (user.cause) { case "unauthorized": // fall through case "forbidden": // fall through case "token_expired": - console.error( + logger.error( `[layout:protected] user error, redirecting to: ${redirectURL}` ) redirect(redirectURL) case "notfound": - console.error(`[layout:protected] notfound user loading error`) + logger.error(`[layout:protected] notfound user loading error`) break case "unknown": - console.error(`[layout:protected] unknown user loading error`) + logger.error(`[layout:protected] unknown user loading error`) break default: - console.error(`[layout:protected] unhandled user loading error`) + logger.error(`[layout:protected] unhandled user loading error`) break } return ( @@ -67,7 +66,7 @@ export async function ProtectedLayout({ children }: React.PropsWithChildren) { } if (!user) { - console.error( + logger.error( "[layout:protected] no user found, redirecting to: ", redirectURL ) diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Date/index.tsx b/apps/scandic-web/components/TempDesignSystem/Form/Date/index.tsx index 9363cf673..a681b3dcf 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/Date/index.tsx +++ b/apps/scandic-web/components/TempDesignSystem/Form/Date/index.tsx @@ -6,6 +6,7 @@ import { useIntl } from "react-intl" import { useMediaQuery } from "usehooks-ts" import { dt } from "@scandic-hotels/common/dt" +import { logger } from "@scandic-hotels/common/logger" import { Select } from "@scandic-hotels/design-system/Select" import useLang from "@/hooks/useLang" @@ -104,7 +105,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) { ? parseDate(currentDateValue) : null } catch (error) { - console.warn("Known error for parse date in DateSelect: ", error) + logger.warn("Known error for parse date in DateSelect: ", error) } useEffect(() => { diff --git a/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts b/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts index 6babc73a3..574156741 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts +++ b/apps/scandic-web/components/TempDesignSystem/Form/Input/errors.ts @@ -1,3 +1,4 @@ +import { logger } from "@scandic-hotels/common/logger" import { phoneErrors } from "@scandic-hotels/common/utils/zod/phoneValidator" import { signupErrors } from "@scandic-hotels/trpc/routers/user/schemas" @@ -182,7 +183,7 @@ export function getErrorMessage(intl: IntlShape, errorCode?: string) { "Reward nights can't be combined with codes or vouchers.", }) default: - console.warn("Error code not supported:", errorCode) + logger.warn("Error code not supported:", errorCode) return errorCode } } diff --git a/apps/scandic-web/components/TempDesignSystem/MeetingRoomCard/utils.ts b/apps/scandic-web/components/TempDesignSystem/MeetingRoomCard/utils.ts index 470d526cb..ab6e88747 100644 --- a/apps/scandic-web/components/TempDesignSystem/MeetingRoomCard/utils.ts +++ b/apps/scandic-web/components/TempDesignSystem/MeetingRoomCard/utils.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import type { IntlShape } from "react-intl/src/types" import { RoomLighting, SeatingType } from "@/types/enums/meetingRooms" @@ -33,7 +35,7 @@ export function translateRoomLighting(option: string, intl: IntlShape) { defaultMessage: "Windows natural daylight and excellent view", }) default: - console.warn(`Unsupported conference room ligthing option: ${option}`) + logger.warn(`Unsupported conference room ligthing option: ${option}`) return intl.formatMessage({ defaultMessage: "N/A", }) @@ -75,7 +77,7 @@ export function translateSeatingType(type: string, intl: IntlShape) { defaultMessage: "U-shape", }) default: - console.warn(`Unsupported conference room type : ${type}`) + logger.warn(`Unsupported conference room type : ${type}`) return intl.formatMessage({ defaultMessage: "N/A", }) diff --git a/apps/scandic-web/components/TrackingSDK/hooks.ts b/apps/scandic-web/components/TrackingSDK/hooks.ts index d04ec0a35..521e6fa8a 100644 --- a/apps/scandic-web/components/TrackingSDK/hooks.ts +++ b/apps/scandic-web/components/TrackingSDK/hooks.ts @@ -15,6 +15,7 @@ import { type UseFromSubscribe, } from "react-hook-form" +import { logger } from "@scandic-hotels/common/logger" import { trpc } from "@scandic-hotels/trpc/client" import useRouterTransitionStore from "@/stores/router-transition" @@ -215,13 +216,13 @@ const trackPerformance = async ({ try { pageLoadTime = await promiseWithTimeout(getPageLoadTimeEntry(), 3000) } catch (error) { - console.error("Error obtaining pageLoadTime:", error) + logger.error("Error obtaining pageLoadTime:", error) } try { lcpTime = await promiseWithTimeout(getLCPTimeEntry(), 3000) } catch (error) { - console.error("Error obtaining lcpTime:", error) + logger.error("Error obtaining lcpTime:", error) } const trackingData = { diff --git a/apps/scandic-web/hooks/useSearchHistory.ts b/apps/scandic-web/hooks/useSearchHistory.ts index 7ac4a8cd4..9c9e43742 100644 --- a/apps/scandic-web/hooks/useSearchHistory.ts +++ b/apps/scandic-web/hooks/useSearchHistory.ts @@ -1,5 +1,6 @@ import { useCallback, useEffect, useState } from "react" +import { logger } from "@scandic-hotels/common/logger" import { type AutoCompleteLocation, autoCompleteLocationSchema, @@ -25,7 +26,7 @@ export function useSearchHistory() { return existingHistory } catch (error) { - console.error("Failed to parse search history:", error) + logger.error("Failed to parse search history:", error) localStorage.removeItem(KEY) return [] diff --git a/apps/scandic-web/i18n/Provider.tsx b/apps/scandic-web/i18n/Provider.tsx index 89cb43481..136dec6c0 100644 --- a/apps/scandic-web/i18n/Provider.tsx +++ b/apps/scandic-web/i18n/Provider.tsx @@ -2,6 +2,8 @@ import { IntlProvider } from "react-intl" +import { logger } from "@scandic-hotels/common/logger" + import type { ClientIntlProviderProps } from "@/types/i18n" const logged: Record = {} @@ -29,7 +31,7 @@ export default function ClientIntlProvider({ if (!logged[msg]) { logged[msg] = true - console.warn(err) + logger.warn("IntlProvider", err) } }} > diff --git a/apps/scandic-web/i18n/tooling/formatter.ts b/apps/scandic-web/i18n/tooling/formatter.ts index ee4c0073e..0ca85bd60 100644 --- a/apps/scandic-web/i18n/tooling/formatter.ts +++ b/apps/scandic-web/i18n/tooling/formatter.ts @@ -1,5 +1,7 @@ // https://docs.lokalise.com/en/articles/3229161-structured-json +import { logger } from "@scandic-hotels/common/logger" + import type { LokaliseMessageDescriptor } from "@/types/intl" type TranslationEntry = { @@ -28,7 +30,7 @@ export function format( if (description) { if (typeof description === "string") { - console.warn( + logger.warn( `Unsupported type for description, expected 'object', got ${typeof context}. Skipping!`, msg ) @@ -39,7 +41,7 @@ export function format( if (typeof context === "string") { entry.context = context } else { - console.warn( + logger.warn( `Unsupported type for context, expected 'string', got ${typeof context}`, msg ) @@ -50,7 +52,7 @@ export function format( if (limit && typeof limit === "number") { entry.limit = limit } else { - console.warn( + logger.warn( `Unsupported type for limit, expected 'number', got ${typeof limit}`, msg ) @@ -64,7 +66,7 @@ export function format( entry.tags = tagArray } } else { - console.warn( + logger.warn( `Unsupported type for tags, expected Array, got ${typeof tags}`, msg ) @@ -75,7 +77,7 @@ export function format( results[id] = entry } else { - console.warn( + logger.warn( `Skipping message, unsupported type for defaultMessage, expected string, got ${typeof defaultMessage}`, { id, diff --git a/apps/scandic-web/i18n/tooling/lokalise.ts b/apps/scandic-web/i18n/tooling/lokalise.ts index 454a193ef..c8b3c8f6e 100644 --- a/apps/scandic-web/i18n/tooling/lokalise.ts +++ b/apps/scandic-web/i18n/tooling/lokalise.ts @@ -4,16 +4,12 @@ import { performance, PerformanceObserver } from "node:perf_hooks" import { LokaliseApi } from "@lokalise/node-api" import AdmZip from "adm-zip" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + const projectId = "4194150766ff28c418f010.39532200" const lokaliseApi = new LokaliseApi({ apiKey: process.env.LOKALISE_API_KEY }) -function log(msg: string, ...args: any[]) { - console.log(`[lokalise] ${msg}`, ...args) -} - -function error(msg: string, ...args: any[]) { - console.error(`[lokalise] ${msg}`, ...args) -} +const lokaliseLogger = createLogger("lokalise") let resolvePerf: (value?: unknown) => void const performanceMetrics = new Promise((resolve) => { @@ -31,7 +27,9 @@ const perf = new PerformanceObserver((items) => { resolvePerf() } } else { - log(`[metrics] ${entry.name} completed in ${entry.duration} ms`) + lokaliseLogger.info( + `[metrics] ${entry.name} completed in ${entry.duration} ms` + ) } } performance.clearMeasures() @@ -43,7 +41,7 @@ async function waitUntilUploadDone(processId: string) { try { performance.mark("waitUntilUploadDoneStart") - log("Checking upload status...") + lokaliseLogger.debug("Checking upload status...") performance.mark("getProcessStart") const process = await lokaliseApi.queuedProcesses().get(processId, { @@ -56,7 +54,7 @@ async function waitUntilUploadDone(processId: string) { "getProcessEnd" ) - log(`Status: ${process.status}`) + lokaliseLogger.debug(`Status: ${process.status}`) if (process.status === "finished") { clearInterval(interval) @@ -72,8 +70,8 @@ async function waitUntilUploadDone(processId: string) { } } catch (e) { clearInterval(interval) - error("An error occurred:", e) - performance.mark("waitUntilUploadDoneEnd", { detail: error }) + lokaliseLogger.error("An error occurred:", e) + performance.mark("waitUntilUploadDoneEnd", { detail: e }) performance.measure( "Wait on upload", "waitUntilUploadDoneStart", @@ -89,7 +87,7 @@ export async function upload(filepath: string) { perf.observe({ type: "measure" }) try { - log(`Uploading ${filepath}...`) + lokaliseLogger.debug(`Uploading ${filepath}...`) performance.mark("uploadStart") @@ -130,9 +128,9 @@ export async function upload(filepath: string) { "lokaliseUploadEnd" ) - log("Upload successful") + lokaliseLogger.debug("Upload successful") } catch (e) { - error("Upload failed", e) + lokaliseLogger.error("Upload failed", e) } finally { performance.mark("uploadEnd") @@ -148,7 +146,7 @@ export async function download(extractPath: string, all: boolean = false) { perf.observe({ type: "measure" }) try { - log( + lokaliseLogger.debug( all ? "Downloading all translations..." : "Downloading filtered translations..." @@ -199,12 +197,12 @@ export async function download(extractPath: string, all: boolean = false) { "unpackTranslationsEnd" ) - log("Download successful") + lokaliseLogger.debug("Download successful") } else { throw bundleResponse } } catch (e) { - error("Download failed", e) + lokaliseLogger.error("Download failed", e) } finally { performance.mark("downloadEnd") @@ -251,11 +249,13 @@ export async function deleteBulk(keyNames: string[]) { .keys() .bulk_delete(keysToDelete, { project_id: projectId }) - log(`Bulk delete successful, removed ${keysToDelete.length} keys`) + lokaliseLogger.debug( + `Bulk delete successful, removed ${keysToDelete.length} keys` + ) return response } catch (e) { - error("Bulk delete failed", e) + lokaliseLogger.error("Bulk delete failed", e) } finally { performance.mark("bulkDeleteEnd") diff --git a/apps/scandic-web/lib/trpc/Provider.tsx b/apps/scandic-web/lib/trpc/Provider.tsx index 8812e7598..0bfbe2641 100644 --- a/apps/scandic-web/lib/trpc/Provider.tsx +++ b/apps/scandic-web/lib/trpc/Provider.tsx @@ -2,6 +2,7 @@ import { TRPCClientError } from "@trpc/client" +import { logger } from "@scandic-hotels/common/logger" import { SessionExpiredError } from "@scandic-hotels/trpc/errors" import { TrpcProvider as InternalTrpcProvider } from "@scandic-hotels/trpc/Provider" @@ -23,7 +24,7 @@ export default function TrpcProvider({ onError={(error) => { if (error instanceof TRPCClientError) { const appError: TRPCClientError = error - console.log({ appError }) + logger.error("trpc error", { appError }) if (appError.data?.code === "UNAUTHORIZED") { if (appError.data?.cause instanceof SessionExpiredError) { const loginUrl = login[lang] diff --git a/apps/scandic-web/lib/trpc/server.ts b/apps/scandic-web/lib/trpc/server.ts index defc93404..c038d5191 100644 --- a/apps/scandic-web/lib/trpc/server.ts +++ b/apps/scandic-web/lib/trpc/server.ts @@ -3,6 +3,7 @@ import { cookies, headers } from "next/headers" import { redirect } from "next/navigation" import { Lang } from "@scandic-hotels/common/constants/language" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createContext } from "@scandic-hotels/trpc/context" import { appServerClient, @@ -50,6 +51,7 @@ export async function createAppContext() { configureServerClient(createAppContext) +const serverClientLogger = createLogger("serverClient") export async function serverClient() { const ctx = await createAppContext() @@ -71,17 +73,18 @@ export async function serverClient() { if (webviews.includes(fullPathname)) { const redirectUrl = `/${lang}/webview/refresh?returnurl=${encodeURIComponent(fullPathname)}` - console.error( + serverClientLogger.error( "Unautorized in webview, redirecting to: ", redirectUrl ) - console.log(`[serverClient] onError redirecting to: ${redirectUrl}`) redirect(redirectUrl) } const redirectUrl = `${login[lang]}?redirectTo=${encodeURIComponent(`/${lang}/${pathname}`)}` - console.log(`[serverClient] onError redirecting to: ${redirectUrl}`) + serverClientLogger.error( + `[serverClient] onError redirecting to: ${redirectUrl}` + ) redirect(redirectUrl) } } diff --git a/apps/scandic-web/middleware.ts b/apps/scandic-web/middleware.ts index 15b0aa191..f7d915bc6 100644 --- a/apps/scandic-web/middleware.ts +++ b/apps/scandic-web/middleware.ts @@ -2,6 +2,7 @@ import * as Sentry from "@sentry/nextjs" import { type NextMiddleware, NextResponse } from "next/server" import { Lang } from "@scandic-hotels/common/constants/language" +import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" import * as authRequired from "@/middlewares/authRequired" @@ -92,7 +93,7 @@ export const middleware: NextMiddleware = async (request, event) => { } catch (e) { if (e instanceof NextResponse && e.status) { const cause = await e.json() - console.error(`NextResponse Error in middleware`, cause) + logger.error(`NextResponse Error in middleware`, cause) Sentry.captureException(cause) return NextResponse.rewrite( @@ -107,7 +108,7 @@ export const middleware: NextMiddleware = async (request, event) => { ) } - console.error(`Error in middleware`, e) + logger.error(`Error in middleware`, e) Sentry.captureException(e) return NextResponse.rewrite( diff --git a/apps/scandic-web/middlewares/authRequired.ts b/apps/scandic-web/middlewares/authRequired.ts index f2da4a5ea..1607c371d 100644 --- a/apps/scandic-web/middlewares/authRequired.ts +++ b/apps/scandic-web/middlewares/authRequired.ts @@ -1,5 +1,6 @@ import { type NextMiddleware, NextResponse } from "next/server" +import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" import { authRequired, mfaRequired } from "@/constants/routes/authRequired" @@ -89,7 +90,7 @@ export const middleware = auth(async (request) => { const redirectOpts = { headers, } - console.log(`[authRequired] redirecting to: ${redirectUrl}`, redirectOpts) + logger.debug(`[authRequired] redirecting to: ${redirectUrl}`, redirectOpts) return NextResponse.redirect(redirectUrl, redirectOpts) }) as unknown as NextMiddleware // See comment above diff --git a/apps/scandic-web/middlewares/myPages.ts b/apps/scandic-web/middlewares/myPages.ts index cfed89140..9a3b63c3d 100644 --- a/apps/scandic-web/middlewares/myPages.ts +++ b/apps/scandic-web/middlewares/myPages.ts @@ -6,6 +6,7 @@ import { profile, profileEdit, } from "@scandic-hotels/common/constants/routes/myPages" +import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" import { resolve as resolveEntry } from "@scandic-hotels/trpc/utils/entry" @@ -25,7 +26,7 @@ export const middleware: NextMiddleware = async (request) => { const nextUrlPublic = getPublicNextURL(request) const overviewUrl = overview[lang] const redirectUrl = new URL(overviewUrl, nextUrlPublic) - console.log(`[myPages] redirecting to: ${redirectUrl}`) + logger.debug(`[myPages] redirecting to: ${redirectUrl}`) return NextResponse.redirect(redirectUrl, { status: 308, }) diff --git a/apps/scandic-web/middlewares/redirect.ts b/apps/scandic-web/middlewares/redirect.ts index a3d3b756e..34b213d03 100644 --- a/apps/scandic-web/middlewares/redirect.ts +++ b/apps/scandic-web/middlewares/redirect.ts @@ -1,6 +1,7 @@ import { type NextMiddleware, NextResponse } from "next/server" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" import { notFound } from "@/server/errors/next" @@ -65,7 +66,7 @@ export const middleware: NextMiddleware = async (request) => { headers.set("x-continue", "1") return NextResponse.next({ headers }) } catch (e) { - console.error("Redirect error: ", e) + logger.error("Redirect error: ", e) throw notFound() } } diff --git a/apps/scandic-web/middlewares/webView.ts b/apps/scandic-web/middlewares/webView.ts index e14ec5d4d..1b47f2a06 100644 --- a/apps/scandic-web/middlewares/webView.ts +++ b/apps/scandic-web/middlewares/webView.ts @@ -1,5 +1,6 @@ import { type NextMiddleware, NextResponse } from "next/server" +import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" import { resolve as resolveEntry } from "@scandic-hotels/trpc/utils/entry" @@ -92,7 +93,7 @@ export const middleware: NextMiddleware = async (request) => { // Authorization header is required for webviews // It should be base64 encoded if (!authorizationToken) { - console.error("Authorization header is missing") + logger.error("Authorization header is missing") return badRequest("Authorization header is missing") } @@ -100,7 +101,7 @@ export const middleware: NextMiddleware = async (request) => { // It should be base64 encoded const initializationVector = request.headers.get("X-AES-IV")! if (!initializationVector) { - console.error("initializationVector header is missing") + logger.error("initializationVector header is missing") return badRequest("initializationVector header is missing") } @@ -121,8 +122,7 @@ export const middleware: NextMiddleware = async (request) => { }) } catch (e) { if (e instanceof Error) { - console.error("Error in webView middleware") - console.error(`${e.name}: ${e.message}`) + logger.error(`Error in webView middleware - ${e.name}: ${e.message}`) } return badRequest() diff --git a/apps/scandic-web/netlify/utils/hoteldata.ts b/apps/scandic-web/netlify/utils/hoteldata.ts index 206e24ed3..8b04f6f44 100644 --- a/apps/scandic-web/netlify/utils/hoteldata.ts +++ b/apps/scandic-web/netlify/utils/hoteldata.ts @@ -1,8 +1,12 @@ +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import type { Lang } from "@scandic-hotels/common/constants/language" export async function warmupHotelDataOnLang(lang: Lang) { + const warmupHotelDataOnLangLogger = createLogger("warmupHotelDataOnLang") const PUBLIC_URL = Netlify.env.get("PUBLIC_URL") - console.info( + + warmupHotelDataOnLangLogger.info( `[WARMUP] Started warmup cache hoteldata for language ${lang} at: ${new Date().toISOString()}!` ) @@ -22,9 +26,11 @@ export async function warmupHotelDataOnLang(lang: Lang) { } const hotels = await hotelsResponse.json() - console.info(`[WARMUP] Retrieved ${hotels.length} hotels.`) + warmupHotelDataOnLangLogger.info( + `[WARMUP] Retrieved ${hotels.length} hotels.` + ) } catch (error) { - console.error( + warmupHotelDataOnLangLogger.error( `[WARMUP] Error warming cache with hoteldata on language ${lang} with error: ${error}` ) } diff --git a/apps/scandic-web/server/utils.ts b/apps/scandic-web/server/utils.ts index aac338427..c1ceac4e3 100644 --- a/apps/scandic-web/server/utils.ts +++ b/apps/scandic-web/server/utils.ts @@ -1,7 +1,8 @@ import { NextRequest } from "next/server" -import { env } from "@/env/server" +import { logger } from "@scandic-hotels/common/logger" +import { env } from "@/env/server" /** * Use this function when you want to create URLs that are public facing, for * example for redirects or redirectTo query parameters. @@ -67,7 +68,7 @@ export function getInternalNextURL(request: NextRequest) { const originHeader = request.headers.get("x-sh-origin") if (originHeader) { - console.log(`[internalNextUrl] using x-sh-origin header`, { + logger.debug(`[internalNextUrl] using x-sh-origin header`, { origin, originHeader, newOrigin: href.replace(origin, originHeader), @@ -78,7 +79,7 @@ export function getInternalNextURL(request: NextRequest) { const hostHeader = request.headers.get("host") if (hostHeader) { const inputHostOrigin = `${request.nextUrl.protocol}//${hostHeader}` - console.log(`[internalNextUrl] using host header`, { + logger.debug(`[internalNextUrl] using host header`, { origin, hostHeader, hostOrigin: inputHostOrigin, @@ -88,6 +89,6 @@ export function getInternalNextURL(request: NextRequest) { return new NextRequest(href.replace(origin, hostOrigin), request).nextUrl } - console.log(`[internalNextUrl] falling back to incoming request`) + logger.debug(`[internalNextUrl] falling back to incoming request`) return request.nextUrl } diff --git a/apps/scandic-web/services/warmup/warmupHotelIdsByCountry.ts b/apps/scandic-web/services/warmup/warmupHotelIdsByCountry.ts index bb2e810be..51138028a 100644 --- a/apps/scandic-web/services/warmup/warmupHotelIdsByCountry.ts +++ b/apps/scandic-web/services/warmup/warmupHotelIdsByCountry.ts @@ -1,4 +1,5 @@ import { Lang } from "@scandic-hotels/common/constants/language" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { getServiceToken } from "@scandic-hotels/common/tokenManager" import { safeTry } from "@scandic-hotels/common/utils/safeTry" import { @@ -10,6 +11,7 @@ import type { WarmupFunction, WarmupResult } from "." export const warmupHotelIdsByCountry = (): WarmupFunction => async (): Promise => { + const warmupLogger = createLogger("warmupHotelIdsByCountry") try { let serviceToken = await getServiceToken() @@ -39,7 +41,7 @@ export const warmupHotelIdsByCountry = ) if (error) { - console.error( + warmupLogger.error( `[Warmup]: Error fetching hotel IDs for ${countryName}:`, error ) diff --git a/apps/scandic-web/stores/enter-details/helpers.ts b/apps/scandic-web/stores/enter-details/helpers.ts index a276739ec..d7f50ccc1 100644 --- a/apps/scandic-web/stores/enter-details/helpers.ts +++ b/apps/scandic-web/stores/enter-details/helpers.ts @@ -2,6 +2,7 @@ import isEqual from "fast-deep-equal" import { parsePhoneNumberFromString } from "libphonenumber-js" import { CurrencyEnum } from "@scandic-hotels/common/constants/currency" +import { logger } from "@scandic-hotels/common/logger" import { RateTypeEnum } from "@scandic-hotels/trpc/enums/rateType" import { @@ -279,7 +280,7 @@ export function readFromSessionStorage(): PersistedState | undefined { return parsedData } catch (error) { - console.error("Error reading from session storage:", error) + logger.error("Error reading from session storage:", error) return undefined } } @@ -292,7 +293,7 @@ export function writeToSessionStorage(state: PersistedState) { try { sessionStorage.setItem(detailsStorageName, JSON.stringify(state)) } catch (error) { - console.error("Error writing to session storage:", error) + logger.error("Error writing to session storage:", error) } } diff --git a/apps/scandic-web/utils/clientSession.ts b/apps/scandic-web/utils/clientSession.ts index 5556e3212..4cfbd891b 100644 --- a/apps/scandic-web/utils/clientSession.ts +++ b/apps/scandic-web/utils/clientSession.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import type { Session } from "next-auth" export function isValidClientSession(session: Session | null) { @@ -5,16 +7,16 @@ export function isValidClientSession(session: Session | null) { return false } if (session.error) { - console.log(`Session error: ${session.error}`) + logger.error(`Session error: ${session.error}`) return false } if (session.token.error) { - console.log(`Session token error: ${session.token.error}`) + logger.error(`Session token error: ${session.token.error}`) return false } if (session.token.expires_at && session.token.expires_at < Date.now()) { - console.log(`Session expired: ${session.token.expires_at}`) + logger.error(`Session expired: ${session.token.expires_at}`) return false } diff --git a/apps/scandic-web/utils/logger/index.ts b/apps/scandic-web/utils/logger/index.ts deleted file mode 100644 index aa125c766..000000000 --- a/apps/scandic-web/utils/logger/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -export function createLogger(loggerPrefix: string | (() => Promise)) { - const getLoggerPrefix: () => Promise = - typeof loggerPrefix === "string" ? async () => loggerPrefix : loggerPrefix - - return { - async debug(message: string, ...args: unknown[]): Promise { - console.debug(`[${await getLoggerPrefix()}] ${message}`, ...args) - }, - async warn(message: string, ...args: unknown[]): Promise { - console.warn(`[${await getLoggerPrefix()}] Warning - ${message}`, ...args) - }, - async error(message: string, ...args: unknown[]): Promise { - console.error(`[${await getLoggerPrefix()}] Error - ${message}`, ...args) - }, - } -} diff --git a/apps/scandic-web/utils/phone.ts b/apps/scandic-web/utils/phone.ts index d275f1819..36a79bd38 100644 --- a/apps/scandic-web/utils/phone.ts +++ b/apps/scandic-web/utils/phone.ts @@ -1,5 +1,7 @@ import parsePhoneNumberFromString, { type CountryCode } from "libphonenumber-js" +import { logger } from "@scandic-hotels/common/logger" + export function formatPhoneNumber( phoneNumber: string, phoneNumberCC?: string | null @@ -16,7 +18,7 @@ export function formatPhoneNumber( : parsePhoneNumberFromString(normalized) if (!parsedPhonenumber?.isValid()) { - console.warn( + logger.warn( `Invalid phone number: ${phoneNumber} with country code: ${phoneNumberCC}`, parsedPhonenumber ) diff --git a/apps/scandic-web/utils/tracking/base.ts b/apps/scandic-web/utils/tracking/base.ts index 61ce7b663..34c9ecd07 100644 --- a/apps/scandic-web/utils/tracking/base.ts +++ b/apps/scandic-web/utils/tracking/base.ts @@ -1,3 +1,5 @@ +import { logger } from "@scandic-hotels/common/logger" + import { SESSION_ID_KEY_NAME } from "@/hooks/useSessionId" export function trackEvent(data: any) { @@ -11,7 +13,7 @@ export function trackEvent(data: any) { try { sessionId = sessionStorage.getItem(SESSION_ID_KEY_NAME) ?? "" } catch (e) { - console.error("Error getting sessionId from sessionStorage", e) + logger.error("Error getting sessionId from sessionStorage", e) } data = { ...data, siteVersion: "new-web", sessionId } diff --git a/apps/scandic-web/utils/url.ts b/apps/scandic-web/utils/url.ts index 602857c12..66afb57b6 100644 --- a/apps/scandic-web/utils/url.ts +++ b/apps/scandic-web/utils/url.ts @@ -1,5 +1,6 @@ import { z } from "zod" +import { logger } from "@scandic-hotels/common/logger" import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast" import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter" @@ -81,7 +82,7 @@ export function parseBookingWidgetSearchParams( return result } catch (error) { - console.log("[URL] Error parsing search params for booking widget:", error) + logger.error("[URL] Error parsing search params for booking widget:", error) return {} } } @@ -118,7 +119,7 @@ export function parseSelectHotelSearchParams( return result } catch (error) { - console.log("[URL] Error parsing search params for select hotel:", error) + logger.error("[URL] Error parsing search params for select hotel:", error) return null } @@ -168,7 +169,7 @@ export function parseSelectRateSearchParams( return result } catch (error) { - console.log("[URL] Error parsing search params for select rate:", error) + logger.error("[URL] Error parsing search params for select rate:", error) return null } @@ -216,7 +217,7 @@ export function parseDetailsSearchParams( return result } catch (error) { - console.log("[URL] Error parsing search params for details:", error) + logger.error("[URL] Error parsing search params for details:", error) return null } diff --git a/packages/common/dataCache/logger.ts b/packages/common/dataCache/logger.ts index 303eef1aa..27731f4db 100644 --- a/packages/common/dataCache/logger.ts +++ b/packages/common/dataCache/logger.ts @@ -1,14 +1,6 @@ -export const cacheLogger = { - async debug(message: string, ...args: unknown[]): Promise { - console.debug(`${await loggerPrefix()} ${message}`, ...args) - }, - async warn(message: string, ...args: unknown[]): Promise { - console.warn(`${await loggerPrefix()} Warning - ${message}`, ...args) - }, - async error(message: string, ...args: unknown[]): Promise { - console.error(`${await loggerPrefix()} Error - ${message}`, ...args) - }, -} +import { createLogger } from "../logger/createLogger" + +export const cacheLogger = createLogger(loggerPrefix) async function loggerPrefix() { const instancePrefix = await getCachePrefix() diff --git a/packages/common/logger/createLogger.ts b/packages/common/logger/createLogger.ts new file mode 100644 index 000000000..465e871bc --- /dev/null +++ b/packages/common/logger/createLogger.ts @@ -0,0 +1,44 @@ +export function createLogger(loggerPrefix: string | (() => Promise)) { + const asyncWrapper: () => Promise = + typeof loggerPrefix === "string" ? async () => loggerPrefix : loggerPrefix + + const getLoggerPrefix = async () => { + const prefix = await asyncWrapper() + if (!prefix) { + return "" + } + + return `[${prefix}]` + } + + return { + async debug(message: string, ...args: unknown[]): Promise { + // TODO: Make this configurable + if (process.env.NODE_ENV !== "development") { + return + } + + console.debug( + "\x1b[36m%s\x1b[0m", + `${await getLoggerPrefix()} ${message}`.trim(), + ...args + ) + }, + + async info(message: string, ...args: unknown[]): Promise { + console.info(`${await getLoggerPrefix()} ${message}`.trim(), ...args) + }, + async warn(message: string, ...args: unknown[]): Promise { + console.warn( + `${await getLoggerPrefix()} [warn] - ${message}`.trim(), + ...args + ) + }, + async error(message: string, ...args: unknown[]): Promise { + console.error( + `${await getLoggerPrefix()} [error] - ${message}`.trim(), + ...args + ) + }, + } +} diff --git a/packages/common/logger/index.ts b/packages/common/logger/index.ts new file mode 100644 index 000000000..296168f12 --- /dev/null +++ b/packages/common/logger/index.ts @@ -0,0 +1,3 @@ +import { createLogger } from "./createLogger" + +export const logger = createLogger("") diff --git a/packages/common/package.json b/packages/common/package.json index 173f17134..a6d2915ed 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -16,6 +16,8 @@ "./telemetry": "./telemetry/index.ts", "./tokenManager": "./tokenManager/index.ts", "./dt": "./dt/dt.ts", + "./logger": "./logger/index.ts", + "./logger/*": "./logger/*.ts", "./utils/isEdge": "./utils/isEdge.ts", "./utils/safeTry": "./utils/safeTry.ts", "./utils/url": "./utils/url.ts", diff --git a/packages/common/telemetry/index.ts b/packages/common/telemetry/index.ts index 889513553..139227fcf 100644 --- a/packages/common/telemetry/index.ts +++ b/packages/common/telemetry/index.ts @@ -23,6 +23,8 @@ import { mapValues, } from "lodash-es" +import { logger } from "../logger" + import type { ZodError } from "zod" type AttributesInput = Record @@ -88,7 +90,7 @@ export function isValidAttributeValue(value: unknown): value is AttributeValue { * }; * * const sanitized = sanitize(input); - * console.log(sanitized); + * logger.log(sanitized); * // { * // key1: "Example", * // key2: 10, @@ -162,7 +164,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) counter.add(1, finalAttrs) - console.info(`[${fullName}] start:`, finalAttrs) + logger.info(`[${fullName}] start:`, finalAttrs) }, /** @@ -175,7 +177,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) success.add(1, finalAttrs) - console.info(`[${fullName}] success:`, finalAttrs) + logger.info(`[${fullName}] success:`, finalAttrs) }, /** @@ -199,7 +201,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) fail.add(1, finalAttrs) - console.error(`[${fullName}] dataError:`, finalAttrs) + logger.error(`[${fullName}] dataError:`, finalAttrs) }, /** @@ -221,7 +223,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) fail.add(1, finalAttrs) - console.error(`[${fullName}] noDataError:`, finalAttrs) + logger.error(`[${fullName}] noDataError:`, finalAttrs) }, /** @@ -241,7 +243,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) fail.add(1, finalAttrs) - console.error(`[${fullName}] validationError:`, finalAttrs) + logger.error(`[${fullName}] validationError:`, finalAttrs) }, /** @@ -271,7 +273,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) fail.add(1, finalAttrs) - console.error(`[${fullName}] httpError:`, finalAttrs) + logger.error(`[${fullName}] httpError:`, finalAttrs) }, /** @@ -301,7 +303,7 @@ export function createCounter(meterName: string, counterName: string) { const finalAttrs = sanitize(mergedAttrs) fail.add(1, finalAttrs) - console.error(`[${fullName}] fail:`, finalAttrs) + logger.error(`[${fullName}] fail:`, finalAttrs) }, } }, diff --git a/packages/common/utils/zod/passwordValidator.test.ts b/packages/common/utils/zod/passwordValidator.test.ts index 94bf6b01d..b10bbf6a4 100644 --- a/packages/common/utils/zod/passwordValidator.test.ts +++ b/packages/common/utils/zod/passwordValidator.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from "vitest" +import { beforeEach, describe, expect, test } from "vitest" import { passwordValidator } from "./passwordValidator" @@ -88,7 +88,6 @@ describe("Should validate password the same way as Curity", () => { curityPasswordRegex.lastIndex = 0 }) test.each(testCases)("$description", ({ password }) => { - console.log(password) const curityResult = curityPasswordRegex.test(password) const zodResult = passwordValidator().safeParse(password) diff --git a/packages/trpc/lib/graphql/_request.ts b/packages/trpc/lib/graphql/_request.ts index ebc1bd945..ad7dd7c69 100644 --- a/packages/trpc/lib/graphql/_request.ts +++ b/packages/trpc/lib/graphql/_request.ts @@ -3,6 +3,7 @@ import "server-only" import { ClientError, type GraphQLClient } from "graphql-request" import { Lang } from "@scandic-hotels/common/constants/language" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "../../env/server" @@ -10,6 +11,7 @@ import type { DocumentNode } from "graphql" import type { Data } from "../types/requestData" +const requestLogger = createLogger("graphql-request") export async function request( client: GraphQLClient, query: string | DocumentNode, @@ -41,13 +43,9 @@ export async function request( /** * TODO: Send to Monitoring (Logging and Metrics) */ - console.log({ + requestLogger.debug("complexity", { complexityLimit: rawResponse.headers.get("x-query-complexity"), - }) - console.log({ referenceDepth: rawResponse.headers.get("x-reference-depth"), - }) - console.log({ resolverCost: rawResponse.headers.get("x-resolver-cost"), }) @@ -63,17 +61,17 @@ export async function request( // @ts-expect-error: name does not exist (?) ).name.value - console.log(`[gql] Sending graphql request to ${env.CMS_URL}`, { + requestLogger.debug(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName, variables, }) } catch (e) { - console.error(`[gql] Unable to extract operation name from query`, { + requestLogger.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) - console.log(`[gql] Sending graphql request to ${env.CMS_URL}`, { + requestLogger.debug(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName: "", variables, }) @@ -94,18 +92,18 @@ export async function request( // @ts-expect-error: name does not exist (?) ).name.value - console.log(`[gql] Response for ${env.CMS_URL}`, { + requestLogger.debug(`[gql] Response for ${env.CMS_URL}`, { response, operationName, variables, }) } catch (e) { - console.error(`[gql] Unable to extract operation name from query`, { + requestLogger.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) - console.log(`[gql] Response for ${env.CMS_URL}`, { + requestLogger.debug(`[gql] Response for ${env.CMS_URL}`, { response, operationName: "", variables, @@ -138,7 +136,7 @@ export async function request( } } - console.error( + requestLogger.error( `[gql] Error sending graphql request to ${env.CMS_URL}`, error ) diff --git a/packages/trpc/lib/graphql/batchRequest.ts b/packages/trpc/lib/graphql/batchRequest.ts index 5daf5a7ff..8ce5d3603 100644 --- a/packages/trpc/lib/graphql/batchRequest.ts +++ b/packages/trpc/lib/graphql/batchRequest.ts @@ -3,6 +3,8 @@ import "server-only" import deepmerge from "deepmerge" import merge from "deepmerge" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { request } from "./request" import type { CacheTime } from "@scandic-hotels/common/dataCache" @@ -18,6 +20,7 @@ export async function batchRequest( } })[] ): Promise> { + const batchLogger = createLogger("graphql-batch-request") try { const response = await Promise.allSettled( queries.map((query) => @@ -37,15 +40,14 @@ export async function batchRequest( if (reasons.length) { reasons.forEach((reason) => { - console.error(`Batch request failed`, reason) + batchLogger.error(`Batch request failed`, reason) }) } return { data } } catch (error) { - console.error("Error in batched graphql request") - console.error(error) - throw new Error("Something went wrong") + batchLogger.error("Error in batched graphql request", error) + throw error } } diff --git a/packages/trpc/lib/graphql/request.ts b/packages/trpc/lib/graphql/request.ts index bc2536437..8b09b1f95 100644 --- a/packages/trpc/lib/graphql/request.ts +++ b/packages/trpc/lib/graphql/request.ts @@ -7,6 +7,7 @@ import { type CacheTime, getCacheClient, } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "../../env/server" import { getPreviewHash, isPreviewByUid } from "../previewContext" @@ -25,6 +26,8 @@ export async function request( ttl: CacheTime } ): Promise> { + const requestLogger = createLogger("graphql-request") + const shouldUsePreview = variables?.uid ? isPreviewByUid(variables.uid) : false @@ -33,12 +36,12 @@ export async function request( internalRequest(query, shouldUsePreview, variables, getPreviewHash()) if (!cacheOptions) { - console.warn("[NO CACHE] for query", query) + requestLogger.warn("[NO CACHE] for query", query) return doCall() } if (shouldUsePreview) { - console.log("[NO CACHE] [PREVIEW] for query", query) + requestLogger.debug("[NO CACHE] [PREVIEW] for query", query) return doCall() } diff --git a/packages/trpc/lib/procedures.ts b/packages/trpc/lib/procedures.ts index b7b5deef2..9ed758ead 100644 --- a/packages/trpc/lib/procedures.ts +++ b/packages/trpc/lib/procedures.ts @@ -1,5 +1,6 @@ import * as Sentry from "@sentry/nextjs" +import { logger } from "@scandic-hotels/common/logger" import { getServiceToken } from "@scandic-hotels/common/tokenManager" import { env } from "../env/server" @@ -68,10 +69,10 @@ export const protectedProcedure = baseProcedure.use(async function (opts) { const session = await opts.ctx.auth() if (!authRequired && env.NODE_ENV === "development") { - console.info( + logger.debug( `❌❌❌❌ You are opting out of authorization, if its done on purpose maybe you should use the publicProcedure instead. ❌❌❌❌` ) - console.info(`path: ${opts.path} | type: ${opts.type}`) + logger.debug(`path: ${opts.path} | type: ${opts.type}`) } if (!session) { @@ -93,10 +94,10 @@ export const safeProtectedProcedure = baseProcedure.use(async function (opts) { const authRequired = opts.meta?.authRequired ?? true let session = await opts.ctx.auth() if (!authRequired && env.NODE_ENV === "development") { - console.info( + logger.debug( `❌❌❌❌ You are opting out of authorization, if its done on purpose maybe you should use the publicProcedure instead. ❌❌❌❌` ) - console.info(`path: ${opts.path} | type: ${opts.type}`) + logger.debug(`path: ${opts.path} | type: ${opts.type}`) } if (!session || session.error === "RefreshAccessTokenError") { diff --git a/packages/trpc/lib/routers/autocomplete/destinations.ts b/packages/trpc/lib/routers/autocomplete/destinations.ts index b9c81ab6d..b4e96ca95 100644 --- a/packages/trpc/lib/routers/autocomplete/destinations.ts +++ b/packages/trpc/lib/routers/autocomplete/destinations.ts @@ -2,6 +2,7 @@ import { z } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { isDefined } from "@scandic-hotels/common/utils/isDefined" import { safeTry } from "@scandic-hotels/common/utils/safeTry" @@ -97,6 +98,7 @@ export async function getAutoCompleteDestinationsData({ serviceToken: string warmup?: boolean }) { + const autoCompleteLogger = createLogger("autocomplete-destinations") const cacheClient = await getCacheClient() return await cacheClient.cacheOrGet( `autocomplete:destinations:locations:${lang}`, @@ -110,7 +112,7 @@ export async function getAutoCompleteDestinationsData({ }) if (!countries) { - console.error("Unable to fetch countries") + autoCompleteLogger.error("Unable to fetch countries") throw new Error("Unable to fetch countries") } @@ -146,7 +148,7 @@ export async function getAutoCompleteDestinationsData({ !cityUrls || !countryUrls ) { - console.error("Unable to fetch location URLs") + autoCompleteLogger.error("Unable to fetch location URLs") throw new Error("Unable to fetch location URLs") } diff --git a/packages/trpc/lib/routers/booking/mutation.ts b/packages/trpc/lib/routers/booking/mutation.ts index f71ee762d..ea4a89ca7 100644 --- a/packages/trpc/lib/routers/booking/mutation.ts +++ b/packages/trpc/lib/routers/booking/mutation.ts @@ -1,3 +1,4 @@ +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { router } from "../.." @@ -19,6 +20,7 @@ import { bookingConfirmationSchema, createBookingSchema } from "./output" import { cancelBooking } from "./utils" const refIdPlugin = createRefIdPlugin() +const bookingLogger = createLogger("trpc.booking") export const bookingMutationRouter = router({ create: safeProtectedServiceProcedure @@ -173,10 +175,10 @@ export const bookingMutationRouter = router({ continue } } else { - console.info( - `Cancelling booking failed for confirmationNumber: ${confirmationNumbers[idx]}` + bookingLogger.error( + `Cancelling booking failed for confirmationNumber: ${confirmationNumbers[idx]}`, + response.reason ) - console.error(response.reason) } cancelledRoomsSuccessfully.push(null) diff --git a/packages/trpc/lib/routers/contentstack/base/output.ts b/packages/trpc/lib/routers/contentstack/base/output.ts index 19b4943c1..2291ecf11 100644 --- a/packages/trpc/lib/routers/contentstack/base/output.ts +++ b/packages/trpc/lib/routers/contentstack/base/output.ts @@ -1,6 +1,7 @@ import { z, ZodError, ZodIssueCode } from "zod" import { Lang } from "@scandic-hotels/common/constants/language" +import { logger } from "@scandic-hotels/common/logger" import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url" import { AlertTypeEnum } from "../../../types/alertType" @@ -541,7 +542,7 @@ export const headerRefsSchema = z }) .transform((data) => { if (!data.all_header.items.length) { - console.info(`Zod Error - No header returned in refs request`) + logger.error(`Zod Error - No header returned in refs request`) throw new ZodError([ { code: ZodIssueCode.custom, @@ -688,7 +689,7 @@ export const headerSchema = z }) .transform((data) => { if (!data.all_header.items.length) { - console.info(`Zod Error - No header returned in request`) + logger.error(`Zod Error - No header returned in request`) throw new ZodError([ { code: ZodIssueCode.custom, diff --git a/packages/trpc/lib/routers/contentstack/languageSwitcher/utils.ts b/packages/trpc/lib/routers/contentstack/languageSwitcher/utils.ts index 9764dc95f..74dd4d7ce 100644 --- a/packages/trpc/lib/routers/contentstack/languageSwitcher/utils.ts +++ b/packages/trpc/lib/routers/contentstack/languageSwitcher/utils.ts @@ -1,4 +1,5 @@ import { Lang } from "@scandic-hotels/common/constants/language" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { removeTrailingSlash } from "@scandic-hotels/common/utils/url" @@ -68,6 +69,10 @@ export async function getUrlsOfAllLanguages( uid: string, contentType: string ) { + const languageSwitcherLogger = createLogger( + "trpc.contentstack.languageSwitcher" + ) + const getLanguageSwitcherCounter = createCounter( "trpc.contentstack", "languageSwitcher.get" @@ -143,8 +148,9 @@ export async function getUrlsOfAllLanguages( fiNoSvDocument = GetFiNoSvUrlsStartPage break default: - console.error(`type: [${contentType}]`) - console.error(`Trying to get a content type that is not supported`) + languageSwitcherLogger.error( + `Trying to get a content type that is not supported, ${contentType}` + ) throw internalServerError() } diff --git a/packages/trpc/lib/routers/hotels/output.ts b/packages/trpc/lib/routers/hotels/output.ts index eee41e74f..87c24329d 100644 --- a/packages/trpc/lib/routers/hotels/output.ts +++ b/packages/trpc/lib/routers/hotels/output.ts @@ -1,5 +1,6 @@ import { z } from "zod" +import { logger } from "@scandic-hotels/common/logger" import { toLang } from "@scandic-hotels/common/utils/languages" import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator" @@ -115,7 +116,7 @@ function getRate(rate: RateDefinition) { case "NotCancellable": return RateEnum.save default: - console.info( + logger.warn( `Unknown cancellationRule [${rate.cancellationRule}]. This should never happen!` ) return null diff --git a/packages/trpc/lib/routers/hotels/query.ts b/packages/trpc/lib/routers/hotels/query.ts index c01be1b22..2a49219ea 100644 --- a/packages/trpc/lib/routers/hotels/query.ts +++ b/packages/trpc/lib/routers/hotels/query.ts @@ -1,6 +1,7 @@ import { Lang } from "@scandic-hotels/common/constants/language" import { getCacheClient } from "@scandic-hotels/common/dataCache" import { dt } from "@scandic-hotels/common/dt" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { env } from "../../../env/server" @@ -79,6 +80,8 @@ import type { import type { CityLocation } from "../../types/locations" import type { Room } from "../../types/room" +const hotelQueryLogger = createLogger("hotelQueryRouter") + export const hotelQueryRouter = router({ availability: router({ hotelsByCity: safeProtectedServiceProcedure @@ -189,8 +192,10 @@ export const hotelQueryRouter = router({ const selectedRooms = [] for (const [idx, room] of availability.entries()) { if (!room || "error" in room) { - console.info(`Availability failed: ${room.error}`) - console.error(room.details) + hotelQueryLogger.error( + `Availability failed: ${room.error}`, + room.details + ) selectedRooms.push(null) continue } @@ -203,7 +208,7 @@ export const hotelQueryRouter = router({ ctx.userPoints ) if (!selected) { - console.error("Unable to find selected room") + hotelQueryLogger.error("Unable to find selected room") selectedRooms.push(null) continue } @@ -347,7 +352,7 @@ export const hotelQueryRouter = router({ ) if (!selected) { - console.error("Unable to find selected room") + hotelQueryLogger.error("Unable to find selected room") return null } @@ -895,13 +900,13 @@ export const hotelQueryRouter = router({ const data = await response.json() if (data.status !== "OK") { - console.error(`Geocode error: ${data.status}`) + hotelQueryLogger.error(`Geocode error: ${data.status}`) return null } const location = data.results[0]?.geometry?.location if (!location) { - console.error("No location found in geocode response") + hotelQueryLogger.error("No location found in geocode response") return null } diff --git a/packages/trpc/lib/routers/hotels/utils.ts b/packages/trpc/lib/routers/hotels/utils.ts index 70c61d22c..7737cf4ce 100644 --- a/packages/trpc/lib/routers/hotels/utils.ts +++ b/packages/trpc/lib/routers/hotels/utils.ts @@ -4,6 +4,7 @@ import stringify from "json-stable-stringify-without-jsonify" import { Lang } from "@scandic-hotels/common/constants/language" import { selectRate } from "@scandic-hotels/common/constants/routes/hotelReservation" import { getCacheClient } from "@scandic-hotels/common/dataCache" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { chunk } from "@scandic-hotels/common/utils/chunk" @@ -64,6 +65,8 @@ import type { import type { Cities } from "./output" export const locationsAffix = "locations" +const hotelUtilsLogger = createLogger("hotelUtils") + export async function getCitiesByCountry({ countries, lang, @@ -101,8 +104,11 @@ export async function getCitiesByCountry({ const countryJson = await countryResponse.json() const citiesByCountry = citiesByCountrySchema.safeParse(countryJson) if (!citiesByCountry.success) { - console.error(`Unable to parse cities by country ${country}`) - console.error(citiesByCountry.error) + hotelUtilsLogger.error( + `Unable to parse cities by country ${country}`, + citiesByCountry.error + ) + throw new Error(`Unable to parse cities by country ${country}`) } return { ...citiesByCountry.data, country } @@ -160,8 +166,10 @@ export async function getCountries({ const countriesJson = await countryResponse.json() const countries = countriesSchema.safeParse(countriesJson) if (!countries.success) { - console.info(`Validation for countries failed`) - console.error(countries.error) + hotelUtilsLogger.error( + `Validation for countries failed`, + countries.error + ) return null } @@ -447,8 +455,10 @@ export async function getLocations({ const apiJson = await apiResponse.json() const verifiedLocations = locationsSchema.safeParse(apiJson) if (!verifiedLocations.success) { - console.info(`Locations Verification Failed`) - console.error(verifiedLocations.error) + hotelUtilsLogger.error( + `Locations Verification Failed`, + verifiedLocations.error + ) throw new Error("Unable to parse locations") } const chunkedLocations = chunk(verifiedLocations.data.data, 10) @@ -471,10 +481,10 @@ export async function getLocations({ country, } } else { - console.info( - `Location cannot be found in any of the countries cities` + hotelUtilsLogger.error( + `Location cannot be found in any of the countries cities`, + location ) - console.info(location) } } } else if (location.type === "hotels") { @@ -614,9 +624,10 @@ export async function getCity({ const cityJson = await cityResponse.json() const city = citiesSchema.safeParse(cityJson) if (!city.success) { - console.info(`Validation of city failed`) - console.info(`cityUrl: ${cityUrl}`) - console.error(city.error) + hotelUtilsLogger.error(`Validation of city failed`, { + error: city.error, + cityUrl, + }) return null } diff --git a/packages/trpc/lib/routers/partners/sas/linkAccount.ts b/packages/trpc/lib/routers/partners/sas/linkAccount.ts index 7fba3fdf8..8e4839a07 100644 --- a/packages/trpc/lib/routers/partners/sas/linkAccount.ts +++ b/packages/trpc/lib/routers/partners/sas/linkAccount.ts @@ -1,6 +1,8 @@ import * as Sentry from "@sentry/nextjs" import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import * as api from "../../../api" import { protectedProcedure } from "../../../procedures" import { getOTPState } from "./otp/getOTPState" @@ -18,13 +20,14 @@ const outputSchema = z.object({ ]), }) +const sasLogger = createLogger("SAS") export const linkAccount = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { const sasAuthToken = await getSasToken() const { referenceId } = await getOTPState() - console.log("[SAS] link account") + sasLogger.debug("[SAS] link account") const apiResponse = await api.post(api.endpoints.v1.Profile.link, { headers: { @@ -47,7 +50,7 @@ export const linkAccount = protectedProcedure linkedAndBoosted || linkedWithoutBoost || linkedWithUnknownBoost if (linked) { - console.log("[SAS] link account done") + sasLogger.debug("[SAS] link account done") return { linkingState: "linked" } } @@ -56,12 +59,12 @@ export const linkAccount = protectedProcedure const data = badRequestSchema.safeParse(result) if (!data.success) { const linkAccountBadRequestSchemaError = `[SAS] failed to parse link account bad request schema ${JSON.stringify(data.error)}` - console.error(linkAccountBadRequestSchemaError) + sasLogger.error(linkAccountBadRequestSchemaError) Sentry.captureMessage(linkAccountBadRequestSchemaError) return { linkingState: "error" } } - console.log("[SAS] link account error with response", result) + sasLogger.error("[SAS] link account error with response", result) const { errors } = data.data @@ -89,7 +92,7 @@ export const linkAccount = protectedProcedure } const errorMessage = `[SAS] link account error with status code ${apiResponse.status} and response ${await apiResponse.text()}` - console.warn(errorMessage) + sasLogger.error(errorMessage) Sentry.captureMessage(errorMessage) return { linkingState: "error" } }) diff --git a/packages/trpc/lib/routers/partners/sas/otp/request/requestOtp.ts b/packages/trpc/lib/routers/partners/sas/otp/request/requestOtp.ts index 1b2a8a517..796a1f7e6 100644 --- a/packages/trpc/lib/routers/partners/sas/otp/request/requestOtp.ts +++ b/packages/trpc/lib/routers/partners/sas/otp/request/requestOtp.ts @@ -4,6 +4,8 @@ import { cookies } from "next/headers" import { v4 as uuidv4 } from "uuid" import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { env } from "../../../../../../env/server" import { protectedProcedure } from "../../../../../procedures" import { getSasToken } from "../../getSasToken" @@ -37,6 +39,7 @@ const failureSchema = z.object({ const outputSchema = z.union([successSchema, failureSchema]) +const sasLogger = createLogger("SAS") export const requestOtp = protectedProcedure .output(outputSchema) .mutation(async function () { @@ -47,8 +50,8 @@ export const requestOtp = protectedProcedure } const tokenResponse = await fetchRequestOtp({ sasAuthToken }) - console.log( - "[SAS] requestOtp", + sasLogger.debug( + "requestOtp", tokenResponse.status, tokenResponse.statusText ) @@ -56,7 +59,7 @@ export const requestOtp = protectedProcedure const body = await tokenResponse.json() const parseResult = outputSchema.safeParse(body) if (!parseResult.success) { - console.error("[SAS] requestOtp error", body) + sasLogger.error("requestOtp error", body) if (!tokenResponse.ok) { throw createError(body) @@ -67,8 +70,8 @@ export const requestOtp = protectedProcedure if (parseResult.data.status === "SENT") { setSASOtpCookie(parseResult.data) } else { - const sasRequestOtpErrorMessage = `[SAS] requestOtp did not return SENT status with body: ${JSON.stringify(body)}` - console.warn(sasRequestOtpErrorMessage) + const sasRequestOtpErrorMessage = `requestOtp did not return SENT status with body: ${JSON.stringify(body)}` + sasLogger.warn(sasRequestOtpErrorMessage) Sentry.captureMessage(sasRequestOtpErrorMessage) } @@ -87,7 +90,7 @@ function createError( | RequestOtpGeneralError ): TRPCError { const errorInfo = parseSASRequestOtpError(errorBody) - console.error("[SAS] createError", errorInfo) + sasLogger.error("createError", errorInfo) return new TRPCError({ code: "BAD_REQUEST", cause: errorInfo, @@ -97,7 +100,7 @@ function createError( async function fetchRequestOtp({ sasAuthToken }: { sasAuthToken: string }) { const endpoint = `${env.SAS_API_ENDPOINT}/api/scandic-partnership/customer/send-otp` - console.log("[SAS]: Requesting OTP") + sasLogger.debug("Requesting OTP") return await fetch(endpoint, { method: "POST", diff --git a/packages/trpc/lib/routers/partners/sas/otp/request/requestOtpError.ts b/packages/trpc/lib/routers/partners/sas/otp/request/requestOtpError.ts index bd2b358eb..83277fafd 100644 --- a/packages/trpc/lib/routers/partners/sas/otp/request/requestOtpError.ts +++ b/packages/trpc/lib/routers/partners/sas/otp/request/requestOtpError.ts @@ -1,5 +1,7 @@ import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + export type RequestOtpResponseError = "TOO_MANY_REQUESTS" | "UNKNOWN" const requestOtpGeneralError = z.enum([ @@ -39,14 +41,14 @@ const SAS_REQUEST_OTP_ERROR_CODES: { } = { TOO_MANY_REQUESTS: 10, } - +const sasLogger = createLogger("SAS") const getErrorCodeByNumber = (number: number): RequestOtpResponseError => { const v = Object.entries(SAS_REQUEST_OTP_ERROR_CODES).find( ([_, value]) => value === number )?.[0] ?? "UNKNOWN" - console.log("[SAS] getErrorCodeByNumber", number, v) + sasLogger.debug("getErrorCodeByNumber", number, v) return v as RequestOtpResponseError } diff --git a/packages/trpc/lib/routers/partners/sas/otp/verify/verifyOtp.ts b/packages/trpc/lib/routers/partners/sas/otp/verify/verifyOtp.ts index 7c42c4693..30f982783 100644 --- a/packages/trpc/lib/routers/partners/sas/otp/verify/verifyOtp.ts +++ b/packages/trpc/lib/routers/partners/sas/otp/verify/verifyOtp.ts @@ -1,6 +1,8 @@ import { TRPCError } from "@trpc/server" import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { env } from "../../../../../../env/server" import { protectedProcedure } from "../../../../../procedures" import { getSasToken } from "../../getSasToken" @@ -29,6 +31,7 @@ const outputSchema = z.object({ databaseUUID: z.string().uuid().optional(), }) +const sasLogger = createLogger("SAS") export const verifyOtp = protectedProcedure .input(inputSchema) .output(outputSchema) @@ -40,14 +43,14 @@ export const verifyOtp = protectedProcedure } const verifyResponse = await fetchVerifyOtp(input) - console.log( - "[SAS] verifyOTP", + sasLogger.debug( + "verifyOTP", verifyResponse.status, verifyResponse.statusText ) if (verifyResponse.status > 499) { - console.error("[SAS] verifyOTP error", await verifyResponse.text()) + sasLogger.error("verifyOTP error", await verifyResponse.text()) throw new TRPCError({ code: "SERVICE_UNAVAILABLE", message: "Error from downstream SAS service", @@ -55,15 +58,15 @@ export const verifyOtp = protectedProcedure } const data = await verifyResponse.json() - console.log("[SAS] verifyOTP data", data) + sasLogger.debug("verifyOTP data", data) const result = outputSchema.safeParse(data) if (!result.success) { - console.error("[SAS] verifyOTP error", result.error) + sasLogger.error("verifyOTP error", result.error) throw createError(data) } - console.log("[SAS] verifyOTP success") - console.log("[SAS] verifyOTP responding", result.data) + sasLogger.debug("verifyOTP success") + sasLogger.debug("verifyOTP responding", result.data) return result.data }) diff --git a/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts b/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts index 1b0cf9b0b..0d4385adf 100644 --- a/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts +++ b/packages/trpc/lib/routers/partners/sas/performLevelUpgrade.ts @@ -3,6 +3,7 @@ import { cookies } from "next/headers" import { z } from "zod" import { FriendsMembershipLevels } from "@scandic-hotels/common/constants/membershipLevels" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import * as api from "../../../api" import { protectedProcedure } from "../../../procedures" @@ -20,7 +21,7 @@ const notMatchedSchema = z.object({ }) const outputSchema = z.union([matchedSchema, notMatchedSchema]) - +const sasLogger = createLogger("SAS") export const performLevelUpgrade = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { @@ -36,7 +37,7 @@ export const performLevelUpgrade = protectedProcedure } const currentLevel = profile.data.membership.membershipLevel - console.log("[SAS] tier match started") + sasLogger.debug("tier match started") const apiResponse = await api.post(api.endpoints.v1.Profile.matchTier, { headers: { @@ -55,14 +56,14 @@ export const performLevelUpgrade = protectedProcedure const updated = apiResponse.status === 200 if (updated) { - console.log("[SAS] tier match complete - boosted") + sasLogger.debug("tier match complete - boosted") const result = await apiResponse.json() const user = getUserSchema.parse(result) if (!user.membership) { const tierMatchErrorNoMembershipMessage = - "[SAS] tier match error - no membership" - console.log(tierMatchErrorNoMembershipMessage) + "tier match error - no membership" + sasLogger.debug(tierMatchErrorNoMembershipMessage) Sentry.captureException(new Error(tierMatchErrorNoMembershipMessage)) return { tierMatchState: "error" } } @@ -77,21 +78,20 @@ export const performLevelUpgrade = protectedProcedure const matchedNoChange = apiResponse.status === 204 if (matchedNoChange) { - console.log("[SAS] tier match complete - no change") + sasLogger.debug("tier match complete - no change") return { tierMatchState: "alreadyMatched" } } const notLinked = apiResponse.status === 404 if (notLinked) { - const tierMatchErrorNotLinkedMessage = - "[SAS] tier match error - not linked" - console.warn(tierMatchErrorNotLinkedMessage) + const tierMatchErrorNotLinkedMessage = "tier match error - not linked" + sasLogger.error(tierMatchErrorNotLinkedMessage) Sentry.captureMessage(tierMatchErrorNotLinkedMessage) return { tierMatchState: "notLinked" } } - const tierMatchErrorMessage = `[SAS] tier match error with status code ${apiResponse.status} and response ${await apiResponse.text()}` - console.error(tierMatchErrorMessage) + const tierMatchErrorMessage = `tier match error with status code ${apiResponse.status} and response ${await apiResponse.text()}` + sasLogger.error(tierMatchErrorMessage) Sentry.captureException(new Error(tierMatchErrorMessage)) return { tierMatchState: "error" } }) diff --git a/packages/trpc/lib/routers/partners/sas/transferPoints.ts b/packages/trpc/lib/routers/partners/sas/transferPoints.ts index 7ce060ac9..dd30caf21 100644 --- a/packages/trpc/lib/routers/partners/sas/transferPoints.ts +++ b/packages/trpc/lib/routers/partners/sas/transferPoints.ts @@ -1,6 +1,8 @@ import * as Sentry from "@sentry/nextjs" import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import * as api from "../../../api" import { protectedProcedure } from "../../../procedures" import { getOTPState } from "./otp/getOTPState" @@ -14,6 +16,7 @@ const transferPointsInputSchema = z.object({ points: z.number(), }) +const sasLogger = createLogger("SAS") export const transferPoints = protectedProcedure .output(outputSchema) .input(transferPointsInputSchema) @@ -43,20 +46,20 @@ export const transferPoints = protectedProcedure const data = badRequestSchema.safeParse(result) if (!data.success) { const transferPointsBadRequestSchemaError = `[SAS] failed to parse transfer points bad request schema ${JSON.stringify(data.error)}` - console.error(transferPointsBadRequestSchemaError) + sasLogger.error(transferPointsBadRequestSchemaError) Sentry.captureMessage(transferPointsBadRequestSchemaError) return { transferState: "error" } } } if (apiResponse.status === 404) { const transferPointsNotFoundError = `[SAS] transfer points failed, no active partner link` - console.error(transferPointsNotFoundError) + sasLogger.error(transferPointsNotFoundError) Sentry.captureMessage(transferPointsNotFoundError) return { transferState: "notLinked" } } const errorMessage = `[SAS] transfer points error with status code ${apiResponse.status} and response ${await apiResponse.text()}` - console.warn(errorMessage) + sasLogger.error(errorMessage) Sentry.captureMessage(errorMessage) return { transferState: "error" } }) diff --git a/packages/trpc/lib/routers/partners/sas/unlinkAccount.ts b/packages/trpc/lib/routers/partners/sas/unlinkAccount.ts index a92c8bca6..11d9f95a1 100644 --- a/packages/trpc/lib/routers/partners/sas/unlinkAccount.ts +++ b/packages/trpc/lib/routers/partners/sas/unlinkAccount.ts @@ -1,5 +1,7 @@ import { z } from "zod" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import * as api from "../../../api" import { protectedProcedure } from "../../../procedures" import { getOTPState } from "./otp/getOTPState" @@ -8,7 +10,7 @@ import { getSasToken } from "./getSasToken" const outputSchema = z.object({ linkingState: z.enum(["unlinked", "notLinked", "error"]), }) - +const sasLogger = createLogger("SAS") export const unlinkAccount = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { @@ -29,24 +31,24 @@ export const unlinkAccount = protectedProcedure }) if (apiResponse.status === 204 || apiResponse.status === 202) { - console.log("[SAS] unlink account success") + sasLogger.debug("unlink account success") return { linkingState: "unlinked" } } if (apiResponse.status === 400) { const result = await apiResponse.json() - console.log("[SAS] unlink account error with response", result) + sasLogger.debug("unlink account error with response", result) return { linkingState: "error" } } if (apiResponse.status === 404) { - console.log("[SAS] tried unlinking an account that was not linked") + sasLogger.debug("tried unlinking an account that was not linked") return { linkingState: "notLinked" } } - console.log( - `[SAS] unlink account error with status code ${apiResponse.status} and response ${await apiResponse.text()}` + sasLogger.debug( + `unlink account error with status code ${apiResponse.status} and response ${await apiResponse.text()}` ) return { linkingState: "error" } }) diff --git a/packages/trpc/lib/routers/user/mutation.ts b/packages/trpc/lib/routers/user/mutation.ts index 19fecc6b0..f179383b1 100644 --- a/packages/trpc/lib/routers/user/mutation.ts +++ b/packages/trpc/lib/routers/user/mutation.ts @@ -1,4 +1,5 @@ import { signupVerify } from "@scandic-hotels/common/constants/routes/signup" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { createCounter } from "@scandic-hotels/common/telemetry" import { env } from "../../../env/server" @@ -14,13 +15,14 @@ import { } from "./input" import { initiateSaveCardSchema, subscriberIdSchema } from "./output" +const userMutationLogger = createLogger("userMutationRouter") export const userMutationRouter = router({ creditCard: router({ add: protectedProcedure.input(addCreditCardInput).mutation(async function ({ ctx, input, }) { - console.info( + userMutationLogger.info( "api.user.creditCard.add start", JSON.stringify({ query: { language: input.language } }) ) @@ -40,7 +42,7 @@ export const userMutationRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() - console.error( + userMutationLogger.error( "api.user.creditCard.add error", JSON.stringify({ query: { language: input.language }, @@ -57,7 +59,7 @@ export const userMutationRouter = router({ const apiJson = await apiResponse.json() const verifiedData = initiateSaveCardSchema.safeParse(apiJson) if (!verifiedData.success) { - console.error( + userMutationLogger.error( "api.user.creditCard.add validation error", JSON.stringify({ query: { language: input.language }, @@ -66,7 +68,7 @@ export const userMutationRouter = router({ ) return null } - console.info( + userMutationLogger.info( "api.user.creditCard.add success", JSON.stringify({ query: { language: input.language } }) ) @@ -75,7 +77,10 @@ export const userMutationRouter = router({ save: protectedProcedure .input(saveCreditCardInput) .mutation(async function ({ ctx, input }) { - console.info("api.user.creditCard.save start", JSON.stringify({})) + userMutationLogger.info( + "api.user.creditCard.save start", + JSON.stringify({}) + ) const apiResponse = await api.post( api.endpoints.v1.Profile.CreditCards.transaction(input.transactionId), { @@ -87,7 +92,7 @@ export const userMutationRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() - console.error( + userMutationLogger.error( "api.user.creditCard.save error", JSON.stringify({ error: { @@ -99,13 +104,16 @@ export const userMutationRouter = router({ ) return false } - console.info("api.user.creditCard.save success", JSON.stringify({})) + userMutationLogger.info( + "api.user.creditCard.save success", + JSON.stringify({}) + ) return true }), delete: protectedProcedure .input(deleteCreditCardInput) .mutation(async function ({ ctx, input }) { - console.info( + userMutationLogger.info( "api.user.creditCard.delete start", JSON.stringify({ query: {} }) ) @@ -122,7 +130,7 @@ export const userMutationRouter = router({ if (!apiResponse.ok) { const text = await apiResponse.text() - console.error( + userMutationLogger.error( "api.user.creditCard.delete error", JSON.stringify({ error: { @@ -135,7 +143,10 @@ export const userMutationRouter = router({ ) return false } - console.info("api.user.creditCard.delete success", JSON.stringify({})) + userMutationLogger.info( + "api.user.creditCard.delete success", + JSON.stringify({}) + ) return true }), }), diff --git a/packages/trpc/lib/serverClient.ts b/packages/trpc/lib/serverClient.ts index aad3b2d20..c69ebc99a 100644 --- a/packages/trpc/lib/serverClient.ts +++ b/packages/trpc/lib/serverClient.ts @@ -1,5 +1,7 @@ import * as Sentry from "@sentry/nextjs" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { appRouter } from "./routers/appRouter" import { createCallerFactory } from "." @@ -22,12 +24,13 @@ export function appServerClient( context: Context, options: ServerClientOptions = {} ) { + const serverClientLogger = createLogger("serverClient") return createCaller(context, { onError: (args) => { const { ctx, error, input, path, type } = args - console.error(`[serverClient] error for ${type}: ${path}`, error) + serverClientLogger.error(`error for ${type}: ${path}`, error) if (input) { - console.error(`[serverClient] received input:`, input) + serverClientLogger.error(`received input:`, input) } options.onError?.(args) diff --git a/packages/trpc/lib/utils/encryption.ts b/packages/trpc/lib/utils/encryption.ts index 2c6322ba9..0872995d0 100644 --- a/packages/trpc/lib/utils/encryption.ts +++ b/packages/trpc/lib/utils/encryption.ts @@ -2,12 +2,15 @@ import "server-only" import crypto from "crypto" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import { env } from "../../env/server" const algorithm = "DES-ECB" const encryptionKey = env.BOOKING_ENCRYPTION_KEY const bufferKey = Buffer.from(encryptionKey, "utf8") +const encryptionLogger = createLogger("encryption") export function encrypt(originalString: string) { try { const cipher = crypto.createCipheriv(algorithm, bufferKey, null) @@ -25,7 +28,7 @@ export function encrypt(originalString: string) { const result = Buffer.concat(buffers).toString("base64") return result } catch (e) { - console.log(e) + encryptionLogger.error("encryption error", e) return "" } } @@ -46,7 +49,7 @@ export function decrypt(encryptedString: string) { .replace(/(\x00)*/g, "") return result } catch (e) { - console.log(e) + encryptionLogger.error("decryption error", e) return "" } } diff --git a/packages/trpc/lib/utils/session.ts b/packages/trpc/lib/utils/session.ts index e345468b8..f89362a83 100644 --- a/packages/trpc/lib/utils/session.ts +++ b/packages/trpc/lib/utils/session.ts @@ -1,24 +1,27 @@ import "server-only" +import { createLogger } from "@scandic-hotels/common/logger/createLogger" + import type { Session } from "next-auth" export function isValidSession(session: Session | null): session is Session { + const sessionLogger = createLogger("session") if (!session) { return false } if (session.error) { - console.log(`Session error: ${session.error}`) + sessionLogger.error(`Session error: ${session.error}`) return false } const token = session.token if (token?.error) { - console.log(`Session token error: ${token.error}`) + sessionLogger.error(`Session token error: ${token.error}`) return false } if (token?.expires_at && token.expires_at < Date.now()) { - console.log(`Session expired: ${session.token.expires_at}`) + sessionLogger.debug(`Session expired: ${session.token.expires_at}`) return false }