Merged in feature/wrap-logging (pull request #2511)

Feature/wrap logging

* feat: change all logging to go through our own logger function so that we can control log levels

* move packages/trpc to using our own logger

* merge


Approved-by: Linus Flood
This commit is contained in:
Joakim Jäderberg
2025-07-03 12:37:04 +00:00
parent 7e32ed294d
commit daf765f3d5
110 changed files with 681 additions and 441 deletions

View File

@@ -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)
}

View File

@@ -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",

View File

@@ -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)
}

View File

@@ -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<LinkEmployeeResult> {
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()
}
}

View File

@@ -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() })
}
}

View File

@@ -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() })
}
}

View File

@@ -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() })
}
}

View File

@@ -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() })
}
}

View File

@@ -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)