Likewise, a small little tip, I've two different loggers, one for server components / ssr / middleware and one (using a hook) for client components. The reason I do this is that I can add more context to the logs this way based on which context we are, here's rough examples: -- client: ```typescript // src/lib/get-server-logger.ts export const getServerLogger = (options?: LoggerConfig, req?: Request) => { const requestContext = getOptionalRequestContext(); const baseLogger = new Logger({ source: options?.source ?? "Server", req: req, args: { anonymousId: cookies().get("_h_anonymous_id")?.value || headers().get("x-anonymous-id") || null, requestId: headers().get("x-request-id"), request: { userAgent: headers().get("user-agent"), referer: headers().get("referer"), ip: headers().get("cf-connecting-ip") ?? headers().get("x-real-ip") ?? headers().get("x-forwarded-for"), country: headers().get("cf-ipcountry"), host: headers().get("host"), }, ...(requestContext?.cf ? { cf: { // All relevant properties from the Cloudflare request context timezone: requestContext.cf.timezone, colo: requestContext.cf.colo, country: requestContext.cf.country, region: requestContext.cf.region, city: requestContext.cf.city, latitude: requestContext.cf.latitude, longitude: requestContext.cf.longitude, postalCode: requestContext.cf.postalCode, metroCode: requestContext.cf.metroCode, regionCode: requestContext.cf.regionCode, botManagement: requestContext.cf.botManagement, clientTcpRtt: requestContext.cf.clientTcpRtt, requestPriority: requestContext.cf.requestPriority, asOrganization: requestContext.cf.asOrganization, asn: requestContext.cf.asn, }, } : {}), locale: cookies().get("NEXT_LOCALE")?.value, }, ...options, }); // Overwrite the flush method to wait for the request to finish const flush = baseLogger.flush.bind(baseLogger); baseLogger.flush = async () => { if (requestContext?.ctx.waitUntil) { console.debug("[Logger] Flushing logs async..."); requestContext.ctx.waitUntil(flush()); return; } flush(); }; return baseLogger; }; // src/lib/use-logger.ts export function useLogger(config: LoggerConfig = {}): Logger { const path = usePathname(); const memoizedConfig = useDeepMemo({ ...config, args: { anonymousId: getAnonymousId(), userAgent: typeof navigator !== "undefined" ? navigator.userAgent : null, locale: getCookie("NEXT_LOCALE"), path, ...(config.args ?? {}), }, }); const logger = useMemo(() => new Logger(memoizedConfig), [memoizedConfig]); // biome-ignore lint/correctness/useExhaustiveDependencies: We want to flush the logger when the path changes useEffect(() => { return () => { if (logger) { logger.flush(); } }; }, [path, logger.flush, logger]); return logger; } ``` Probably smarter ways to do this but this has worked pretty well!