From 9362edae40468ffdf377fb0e01ccb97ef3479be7 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 20 Jun 2025 10:31:42 +0200 Subject: [PATCH 01/10] create a logger to have consistent logging across the app --- packages/gitbook/openNext/queue/server.ts | 4 +++- .../gitbook/openNext/tagCache/middleware.ts | 10 +++++--- packages/gitbook/src/app/utils.ts | 8 +++++++ .../src/app/~gitbook/revalidate/route.ts | 5 ++-- packages/gitbook/src/lib/context.ts | 5 +++- .../gitbook/src/lib/images/resizer/cdn-cgi.ts | 5 ++-- .../src/lib/images/resizer/cf-fetch.ts | 5 ++-- .../src/lib/images/resizer/resizeImage.ts | 4 +++- packages/gitbook/src/lib/images/signatures.ts | 5 ++-- packages/gitbook/src/lib/logger.ts | 23 +++++++++++++++++++ 10 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 packages/gitbook/src/lib/logger.ts diff --git a/packages/gitbook/openNext/queue/server.ts b/packages/gitbook/openNext/queue/server.ts index 9a5b3b689b..9f57ff9a80 100644 --- a/packages/gitbook/openNext/queue/server.ts +++ b/packages/gitbook/openNext/queue/server.ts @@ -1,9 +1,11 @@ import type { Queue } from '@opennextjs/aws/types/overrides.js'; +import { getLogger } from '@v2/app/utils'; export default { name: 'GitbookISRQueue', send: async (msg) => { + const logger = getLogger().subLogger('GitbookISRQueue'); // We should never reach this point in the server. If that's the case, we should log it. - console.warn('GitbookISRQueue: send called on server side, this should not happen.', msg); + logger.warn('send called on server side, this should not happen.', msg); }, } satisfies Queue; diff --git a/packages/gitbook/openNext/tagCache/middleware.ts b/packages/gitbook/openNext/tagCache/middleware.ts index 4f06d7896b..f0bd8a5033 100644 --- a/packages/gitbook/openNext/tagCache/middleware.ts +++ b/packages/gitbook/openNext/tagCache/middleware.ts @@ -2,6 +2,7 @@ import { trace } from '@/lib/tracing'; import type { NextModeTagCache } from '@opennextjs/aws/types/overrides.js'; import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache'; import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-cache-filter'; +import { getLogger } from '@v2/app/utils'; const originalTagCache = doShardedTagCache({ baseShardSize: 12, @@ -23,8 +24,9 @@ export default { getLastRevalidated: async (tags: string[]) => { const tagsToCheck = tags.filter(softTagFilter); if (tagsToCheck.length === 0) { + const logger = getLogger().subLogger('gitbookTagCache'); // If we reach here, it probably means that there is an issue that we'll need to address. - console.warn( + logger.warn( 'getLastRevalidated - No valid tags to check for last revalidation, original tags:', tags ); @@ -43,8 +45,9 @@ export default { hasBeenRevalidated: async (tags: string[], lastModified?: number) => { const tagsToCheck = tags.filter(softTagFilter); if (tagsToCheck.length === 0) { + const logger = getLogger().subLogger('gitbookTagCache'); // If we reach here, it probably means that there is an issue that we'll need to address. - console.warn( + logger.warn( 'hasBeenRevalidated - No valid tags to check for revalidation, original tags:', tags ); @@ -70,7 +73,8 @@ export default { async () => { const tagsToWrite = tags.filter(softTagFilter); if (tagsToWrite.length === 0) { - console.warn('writeTags - No valid tags to write'); + const logger = getLogger().subLogger('gitbookTagCache'); + logger.warn('writeTags - No valid tags to write'); return; // If no tags to write, exit early } // Write only the filtered tags diff --git a/packages/gitbook/src/app/utils.ts b/packages/gitbook/src/app/utils.ts index 0e5d1688b0..2cb5820b93 100644 --- a/packages/gitbook/src/app/utils.ts +++ b/packages/gitbook/src/app/utils.ts @@ -1,9 +1,12 @@ +import crypto from 'node:crypto'; import { getVisitorAuthClaims, getVisitorAuthClaimsFromToken } from '@/lib/adaptive'; import { type SiteURLData, fetchSiteContextByURLLookup, getBaseContext } from '@/lib/context'; import { getDynamicCustomizationSettings } from '@/lib/customization'; +import { createLogger } from '@/lib/logger'; import type { SiteAPIToken } from '@gitbook/api'; import { jwtDecode } from 'jwt-decode'; import { forbidden } from 'next/navigation'; +import { cache } from 'react'; import rison from 'rison'; export type RouteParamMode = 'url-host' | 'url'; @@ -105,3 +108,8 @@ function getSiteURLDataFromParams(params: RouteLayoutParams): SiteURLData { const decoded = decodeURIComponent(params.siteData); return rison.decode(decoded); } + +export const getLogger = cache(() => { + const requestId = crypto.randomBytes(16).toString('hex'); + return createLogger('GBOV2', requestId); +}); diff --git a/packages/gitbook/src/app/~gitbook/revalidate/route.ts b/packages/gitbook/src/app/~gitbook/revalidate/route.ts index 17d03c1b84..04876c043b 100644 --- a/packages/gitbook/src/app/~gitbook/revalidate/route.ts +++ b/packages/gitbook/src/app/~gitbook/revalidate/route.ts @@ -1,5 +1,6 @@ import { type NextRequest, NextResponse } from 'next/server'; +import { getLogger } from '@/app/utils'; import { withVerifySignature } from '@/lib/routes'; import { revalidateTag } from 'next/cache'; @@ -12,6 +13,7 @@ interface JsonBody { * The body should be a JSON with { tags: string[] } */ export async function POST(req: NextRequest) { + const logger = getLogger().subLogger('revalidate'); return withVerifySignature(req, async (body) => { if (!body.tags || !Array.isArray(body.tags)) { return NextResponse.json( @@ -23,8 +25,7 @@ export async function POST(req: NextRequest) { } body.tags.forEach((tag) => { - // biome-ignore lint/suspicious/noConsole: we want to log here - console.log(`Revalidating tag: ${tag}`); + logger.log(`Revalidating tag: ${tag}`); revalidateTag(tag); }); diff --git a/packages/gitbook/src/lib/context.ts b/packages/gitbook/src/lib/context.ts index 7332da1f11..2d7e2e3f73 100644 --- a/packages/gitbook/src/lib/context.ts +++ b/packages/gitbook/src/lib/context.ts @@ -1,3 +1,4 @@ +import { getLogger } from '@/app/utils'; import { type GitBookDataFetcher, createDataFetcher, @@ -19,6 +20,7 @@ import type { SiteStructure, Space, } from '@gitbook/api'; + import assertNever from 'assert-never'; import { notFound } from 'next/navigation'; import { assert } from 'ts-essentials'; @@ -290,10 +292,11 @@ export async function fetchSiteContextByIds( return siteSpaceSettings; } + const logger = getLogger().subLogger('fetchSiteContextByIds'); // We got the pointer from an API and customizations from another. // It's possible that the two are unsynced leading to not found customizations for the space. // It's better to fallback on customization of the site that displaying an error. - console.warn('Customization not found for site space', ids.siteSpace); + logger.warn('Customization not found for site space', ids.siteSpace); } return customizations.site; diff --git a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts index b04c55693c..f17aff4fb8 100644 --- a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts +++ b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts @@ -1,3 +1,4 @@ +import { getLogger } from '@/app/utils'; import { GITBOOK_IMAGE_RESIZE_URL } from '@/lib/env'; import type { CloudflareImageOptions } from './types'; import { copyImageResponse } from './utils'; @@ -24,8 +25,8 @@ export async function resizeImageWithCDNCgi( resizeOptions )}/${encodeURIComponent(input)}`; - // biome-ignore lint/suspicious/noConsole: this log is useful for debugging - console.log(`resize image using cdn-cgi: ${resizeURL}`); + const logger = getLogger().subLogger('resize-image-cdn-cgi'); + logger.log(`resize image using cdn-cgi: ${resizeURL}`); return copyImageResponse( await fetch(resizeURL, { diff --git a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts index 2d6c509ae1..adf81bfcec 100644 --- a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts +++ b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts @@ -1,3 +1,4 @@ +import { getLogger } from '@v2/app/utils'; import type { CloudflareImageOptions } from './types'; import { copyImageResponse } from './utils'; @@ -13,8 +14,8 @@ export async function resizeImageWithCFFetch( ): Promise { const { signal, ...resizeOptions } = options; - // biome-ignore lint/suspicious/noConsole: this log is useful for debugging - console.log(`resize image using cf-fetch: ${input}`); + const logger = getLogger().subLogger('resize-image-cf-fetch'); + logger.log(`resize image using cf-fetch: ${input}`); return copyImageResponse( await fetch(input, { diff --git a/packages/gitbook/src/lib/images/resizer/resizeImage.ts b/packages/gitbook/src/lib/images/resizer/resizeImage.ts index 8e656f3b70..5ff996ee0a 100644 --- a/packages/gitbook/src/lib/images/resizer/resizeImage.ts +++ b/packages/gitbook/src/lib/images/resizer/resizeImage.ts @@ -1,4 +1,5 @@ import 'server-only'; +import { getLogger } from '@v2/app/utils'; import assertNever from 'assert-never'; import { GITBOOK_IMAGE_RESIZE_MODE } from '../../env'; import { SizableImageAction, checkIsSizableImageURL } from '../checkIsSizableImageURL'; @@ -34,7 +35,8 @@ export async function getImageSize( height: json.original.height, }; } catch (error) { - console.warn(`Error getting image size for ${input}:`, error); + const logger = getLogger().subLogger('get-image-size'); + logger.warn(`Error getting image size for ${input}:`, error); return null; } } diff --git a/packages/gitbook/src/lib/images/signatures.ts b/packages/gitbook/src/lib/images/signatures.ts index 21834a69c9..1c71fb726c 100644 --- a/packages/gitbook/src/lib/images/signatures.ts +++ b/packages/gitbook/src/lib/images/signatures.ts @@ -1,6 +1,7 @@ import 'server-only'; import fnv1a from '@sindresorhus/fnv1a'; +import { getLogger } from '@v2/app/utils'; import type { MaybePromise } from 'p-map'; import { assert } from 'ts-essentials'; import { GITBOOK_IMAGE_RESIZE_SIGNING_KEY } from '../env'; @@ -33,8 +34,8 @@ export async function verifyImageSignature( const generator = IMAGE_SIGNATURE_FUNCTIONS[version]; const generated = await generator(input); - // biome-ignore lint/suspicious/noConsole: we want to log the signature comparison - console.log( + const logger = getLogger().subLogger('image-signature'); + logger.log( `comparing image signature for "${input.url}" on identifier "${input.imagesContextId}": "${generated}" (expected) === "${signature}" (actual)` ); return generated === signature; diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts new file mode 100644 index 0000000000..8e6c180d59 --- /dev/null +++ b/packages/gitbook/src/lib/logger.ts @@ -0,0 +1,23 @@ +/** + * Creates a logger with the given name, the logger will prefix all log messages with the name in square brackets. + * @param name The name of the logger, which can be used to create a sub-logger. + * @param requestId An optional request ID to include in log messages for better traceability. + * @returns A logger object with methods for logging at different levels and creating sub-loggers. + */ +export const createLogger = (name: string, requestId?: string) => { + return { + subLogger: (subName: string) => createLogger(`${name}:${subName}`, requestId), + info: (...data: any[]) => + console.info(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + warn: (...data: any[]) => + console.warn(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + error: (...data: any[]) => + console.error(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + debug: (...data: any[]) => + console.debug(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + log: (...data: any[]) => + console.log(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + }; +}; + +export type GitbookLogger = ReturnType; From 6d809f7303326db9bcc27aeb4c1d2a7c3234e408 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 20 Jun 2025 13:38:11 +0200 Subject: [PATCH 02/10] move getLogger to it's own file --- packages/gitbook/openNext/queue/server.ts | 2 +- packages/gitbook/openNext/tagCache/middleware.ts | 2 +- packages/gitbook/src/app/utils.ts | 8 -------- .../gitbook/src/app/~gitbook/revalidate/route.ts | 2 +- packages/gitbook/src/lib/context.ts | 3 +-- packages/gitbook/src/lib/images/resizer/cdn-cgi.ts | 2 +- packages/gitbook/src/lib/images/resizer/cf-fetch.ts | 2 +- .../gitbook/src/lib/images/resizer/resizeImage.ts | 2 +- packages/gitbook/src/lib/images/signatures.ts | 2 +- packages/gitbook/src/lib/logger.ts | 13 +++++++++++++ 10 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/gitbook/openNext/queue/server.ts b/packages/gitbook/openNext/queue/server.ts index 9f57ff9a80..aaeddefd18 100644 --- a/packages/gitbook/openNext/queue/server.ts +++ b/packages/gitbook/openNext/queue/server.ts @@ -1,5 +1,5 @@ import type { Queue } from '@opennextjs/aws/types/overrides.js'; -import { getLogger } from '@v2/app/utils'; +import { getLogger } from '@v2/lib/logger'; export default { name: 'GitbookISRQueue', diff --git a/packages/gitbook/openNext/tagCache/middleware.ts b/packages/gitbook/openNext/tagCache/middleware.ts index f0bd8a5033..b94acd73a7 100644 --- a/packages/gitbook/openNext/tagCache/middleware.ts +++ b/packages/gitbook/openNext/tagCache/middleware.ts @@ -2,7 +2,7 @@ import { trace } from '@/lib/tracing'; import type { NextModeTagCache } from '@opennextjs/aws/types/overrides.js'; import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache'; import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-cache-filter'; -import { getLogger } from '@v2/app/utils'; +import { getLogger } from '@v2/lib/logger'; const originalTagCache = doShardedTagCache({ baseShardSize: 12, diff --git a/packages/gitbook/src/app/utils.ts b/packages/gitbook/src/app/utils.ts index 2cb5820b93..0e5d1688b0 100644 --- a/packages/gitbook/src/app/utils.ts +++ b/packages/gitbook/src/app/utils.ts @@ -1,12 +1,9 @@ -import crypto from 'node:crypto'; import { getVisitorAuthClaims, getVisitorAuthClaimsFromToken } from '@/lib/adaptive'; import { type SiteURLData, fetchSiteContextByURLLookup, getBaseContext } from '@/lib/context'; import { getDynamicCustomizationSettings } from '@/lib/customization'; -import { createLogger } from '@/lib/logger'; import type { SiteAPIToken } from '@gitbook/api'; import { jwtDecode } from 'jwt-decode'; import { forbidden } from 'next/navigation'; -import { cache } from 'react'; import rison from 'rison'; export type RouteParamMode = 'url-host' | 'url'; @@ -108,8 +105,3 @@ function getSiteURLDataFromParams(params: RouteLayoutParams): SiteURLData { const decoded = decodeURIComponent(params.siteData); return rison.decode(decoded); } - -export const getLogger = cache(() => { - const requestId = crypto.randomBytes(16).toString('hex'); - return createLogger('GBOV2', requestId); -}); diff --git a/packages/gitbook/src/app/~gitbook/revalidate/route.ts b/packages/gitbook/src/app/~gitbook/revalidate/route.ts index 04876c043b..fd90ade235 100644 --- a/packages/gitbook/src/app/~gitbook/revalidate/route.ts +++ b/packages/gitbook/src/app/~gitbook/revalidate/route.ts @@ -1,6 +1,6 @@ import { type NextRequest, NextResponse } from 'next/server'; -import { getLogger } from '@/app/utils'; +import { getLogger } from '@/lib/logger'; import { withVerifySignature } from '@/lib/routes'; import { revalidateTag } from 'next/cache'; diff --git a/packages/gitbook/src/lib/context.ts b/packages/gitbook/src/lib/context.ts index 2d7e2e3f73..85cb63432e 100644 --- a/packages/gitbook/src/lib/context.ts +++ b/packages/gitbook/src/lib/context.ts @@ -1,10 +1,10 @@ -import { getLogger } from '@/app/utils'; import { type GitBookDataFetcher, createDataFetcher, getDataOrNull, throwIfDataError, } from '@/lib/data'; +import { getLogger } from '@/lib/logger'; import { getSiteStructureSections } from '@/lib/sites'; import type { ChangeRequest, @@ -20,7 +20,6 @@ import type { SiteStructure, Space, } from '@gitbook/api'; - import assertNever from 'assert-never'; import { notFound } from 'next/navigation'; import { assert } from 'ts-essentials'; diff --git a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts index f17aff4fb8..b5dcb8db0b 100644 --- a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts +++ b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts @@ -1,5 +1,5 @@ -import { getLogger } from '@/app/utils'; import { GITBOOK_IMAGE_RESIZE_URL } from '@/lib/env'; +import { getLogger } from '@/lib/logger'; import type { CloudflareImageOptions } from './types'; import { copyImageResponse } from './utils'; diff --git a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts index adf81bfcec..9c75a0dfaa 100644 --- a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts +++ b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts @@ -1,4 +1,4 @@ -import { getLogger } from '@v2/app/utils'; +import { getLogger } from '@v2/lib/logger'; import type { CloudflareImageOptions } from './types'; import { copyImageResponse } from './utils'; diff --git a/packages/gitbook/src/lib/images/resizer/resizeImage.ts b/packages/gitbook/src/lib/images/resizer/resizeImage.ts index 5ff996ee0a..76a72e1844 100644 --- a/packages/gitbook/src/lib/images/resizer/resizeImage.ts +++ b/packages/gitbook/src/lib/images/resizer/resizeImage.ts @@ -1,5 +1,5 @@ import 'server-only'; -import { getLogger } from '@v2/app/utils'; +import { getLogger } from '@v2/lib/logger'; import assertNever from 'assert-never'; import { GITBOOK_IMAGE_RESIZE_MODE } from '../../env'; import { SizableImageAction, checkIsSizableImageURL } from '../checkIsSizableImageURL'; diff --git a/packages/gitbook/src/lib/images/signatures.ts b/packages/gitbook/src/lib/images/signatures.ts index 1c71fb726c..f9e782bfad 100644 --- a/packages/gitbook/src/lib/images/signatures.ts +++ b/packages/gitbook/src/lib/images/signatures.ts @@ -1,7 +1,7 @@ import 'server-only'; import fnv1a from '@sindresorhus/fnv1a'; -import { getLogger } from '@v2/app/utils'; +import { getLogger } from '@v2/lib/logger'; import type { MaybePromise } from 'p-map'; import { assert } from 'ts-essentials'; import { GITBOOK_IMAGE_RESIZE_SIGNING_KEY } from '../env'; diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts index 8e6c180d59..a407022448 100644 --- a/packages/gitbook/src/lib/logger.ts +++ b/packages/gitbook/src/lib/logger.ts @@ -1,3 +1,5 @@ +import { cache } from 'react'; +import 'server-only'; /** * Creates a logger with the given name, the logger will prefix all log messages with the name in square brackets. * @param name The name of the logger, which can be used to create a sub-logger. @@ -21,3 +23,14 @@ export const createLogger = (name: string, requestId?: string) => { }; export type GitbookLogger = ReturnType; + +export const getLogger = cache(() => { + // This is not cryptographically secure, but it's fine for logging purposes. + // It allows us to identify logs from the same request. + // If we are in the middleware, we don't set a request ID because cache won't work well there. + const requestId = + process.env.NEXT_RUNTIME === 'edge' + ? undefined + : Math.random().toString(36).substring(2, 15); + return createLogger('GBOV2', requestId); +}); From e0e3a7c779d302d9739a2672a5a27f18ca08f5f1 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 20 Jun 2025 14:25:30 +0200 Subject: [PATCH 03/10] use logger in tracing --- packages/gitbook/src/lib/logger.ts | 1 - packages/gitbook/src/lib/tracing.ts | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts index a407022448..757d3137e3 100644 --- a/packages/gitbook/src/lib/logger.ts +++ b/packages/gitbook/src/lib/logger.ts @@ -1,5 +1,4 @@ import { cache } from 'react'; -import 'server-only'; /** * Creates a logger with the given name, the logger will prefix all log messages with the name in square brackets. * @param name The name of the logger, which can be used to create a sub-logger. diff --git a/packages/gitbook/src/lib/tracing.ts b/packages/gitbook/src/lib/tracing.ts index 71b5c072e8..1d9401e7ed 100644 --- a/packages/gitbook/src/lib/tracing.ts +++ b/packages/gitbook/src/lib/tracing.ts @@ -1,3 +1,5 @@ +import { getLogger } from '@v2/lib/logger'; + export interface TraceSpan { setAttribute: (label: string, value: boolean | string | number) => void; } @@ -38,8 +40,8 @@ export async function trace( } finally { if (process.env.SILENT !== 'true' && process.env.NODE_ENV !== 'development') { const end = now(); - // biome-ignore lint/suspicious/noConsole: we want to log performance data - console.log( + const logger = getLogger().subLogger(operation); + logger.log( `trace ${completeName} ${traceError ? `failed with ${traceError.message}` : 'succeeded'} in ${end - start}ms`, attributes ); From 87166b2b162b93a75d3e60a2e1afc96b003a6ccb Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Mon, 23 Jun 2025 16:38:01 +0200 Subject: [PATCH 04/10] add a way to add labels to the logger --- packages/gitbook/src/lib/context.ts | 2 +- packages/gitbook/src/lib/logger.ts | 47 +++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/gitbook/src/lib/context.ts b/packages/gitbook/src/lib/context.ts index 85cb63432e..0cb9ad1e84 100644 --- a/packages/gitbook/src/lib/context.ts +++ b/packages/gitbook/src/lib/context.ts @@ -291,7 +291,7 @@ export async function fetchSiteContextByIds( return siteSpaceSettings; } - const logger = getLogger().subLogger('fetchSiteContextByIds'); + const logger = getLogger().subLogger('fetchSiteContextByIds', {}); // We got the pointer from an API and customizations from another. // It's possible that the two are unsynced leading to not found customizations for the space. // It's better to fallback on customization of the site that displaying an error. diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts index 757d3137e3..fca5dd9d0b 100644 --- a/packages/gitbook/src/lib/logger.ts +++ b/packages/gitbook/src/lib/logger.ts @@ -1,23 +1,44 @@ import { cache } from 'react'; +export type LogLabelValue = string | number | undefined | boolean; + +export type LogLabels = { [key: string]: LogLabelValue }; + +export type SubLoggerOptions = { + labels?: LogLabels; +}; + +export type LoggerOptions = SubLoggerOptions & { + requestId?: string; +}; + +const formatPrefix = (name: string, options: LoggerOptions) => { + const { labels } = options; + return `%${JSON.stringify(labels ?? {})}%[${name}]`; +}; + /** * Creates a logger with the given name, the logger will prefix all log messages with the name in square brackets. + * By default it will include a `requestId` label, and output labels in the log messages. + * Format of log messages will be: + * `%{"label1":"value1","label2":"value2"}%[loggerName] message...` * @param name The name of the logger, which can be used to create a sub-logger. * @param requestId An optional request ID to include in log messages for better traceability. * @returns A logger object with methods for logging at different levels and creating sub-loggers. */ -export const createLogger = (name: string, requestId?: string) => { +export const createLogger = (name: string, options: LoggerOptions) => { + const { requestId, labels } = options; + const finalOptions = { requestId, labels: { ...labels, requestId } }; return { - subLogger: (subName: string) => createLogger(`${name}:${subName}`, requestId), - info: (...data: any[]) => - console.info(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), - warn: (...data: any[]) => - console.warn(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), - error: (...data: any[]) => - console.error(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), - debug: (...data: any[]) => - console.debug(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), - log: (...data: any[]) => - console.log(`[${name}] ${requestId ? `(${requestId})` : ''}`, ...data), + subLogger: (subName: string, options?: SubLoggerOptions) => + createLogger(`${name}:${subName}`, { + requestId, + labels: { ...labels, ...(options?.labels ?? {}) }, + }), + info: (...data: any[]) => console.info(formatPrefix(name, finalOptions), ...data), + warn: (...data: any[]) => console.warn(formatPrefix(name, finalOptions), ...data), + error: (...data: any[]) => console.error(formatPrefix(name, finalOptions), ...data), + debug: (...data: any[]) => console.debug(formatPrefix(name, finalOptions), ...data), + log: (...data: any[]) => console.log(formatPrefix(name, finalOptions), ...data), }; }; @@ -31,5 +52,5 @@ export const getLogger = cache(() => { process.env.NEXT_RUNTIME === 'edge' ? undefined : Math.random().toString(36).substring(2, 15); - return createLogger('GBOV2', requestId); + return createLogger('GBOV2', { requestId }); }); From daa4fad32291d94f38193921d9a0af6b5084d1dd Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Mon, 23 Jun 2025 18:03:53 +0200 Subject: [PATCH 05/10] use requestId from OpenNext --- packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc | 3 ++- .../gitbook/openNext/customWorkers/middlewareWrangler.jsonc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc b/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc index 05b61fab74..88cc738565 100644 --- a/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc +++ b/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc @@ -125,7 +125,8 @@ "vars": { // This is a bit misleading, but it means that we can have 500 concurrent revalidations // This means that we'll have up to 100 durable objects instance running at the same time - "MAX_REVALIDATE_CONCURRENCY": "100" + "MAX_REVALIDATE_CONCURRENCY": "100", + "OPEN_NEXT_REQUEST_ID_HEADER": true }, "r2_buckets": [ { diff --git a/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc b/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc index 09e48afcc0..51c92b2160 100644 --- a/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc +++ b/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc @@ -153,7 +153,8 @@ // TODO: remove this once the issue is fixed "DEBUG_CLOUDFLARE": "true", "WORKER_VERSION_ID": "TO_REPLACE", - "STAGE": "production" + "STAGE": "production", + "OPEN_NEXT_REQUEST_ID_HEADER": true }, "routes": [ { From 86aa01316beaf2ad80a1d4d8cc453bff9da36730 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Sat, 28 Jun 2025 13:40:09 +0200 Subject: [PATCH 06/10] fix rebase --- .../src/lib/images/resizer/cf-fetch.ts | 2 +- .../src/lib/images/resizer/resizeImage.ts | 2 +- packages/gitbook/src/lib/images/signatures.ts | 2 +- packages/gitbook/src/lib/logger.ts | 26 +++++++++++-------- packages/gitbook/src/lib/tracing.ts | 2 +- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts index 9c75a0dfaa..2c37d4dafe 100644 --- a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts +++ b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts @@ -1,4 +1,4 @@ -import { getLogger } from '@v2/lib/logger'; +import { getLogger } from '@/lib/logger'; import type { CloudflareImageOptions } from './types'; import { copyImageResponse } from './utils'; diff --git a/packages/gitbook/src/lib/images/resizer/resizeImage.ts b/packages/gitbook/src/lib/images/resizer/resizeImage.ts index 76a72e1844..ea33a530e7 100644 --- a/packages/gitbook/src/lib/images/resizer/resizeImage.ts +++ b/packages/gitbook/src/lib/images/resizer/resizeImage.ts @@ -1,5 +1,5 @@ import 'server-only'; -import { getLogger } from '@v2/lib/logger'; +import { getLogger } from '@/lib/logger'; import assertNever from 'assert-never'; import { GITBOOK_IMAGE_RESIZE_MODE } from '../../env'; import { SizableImageAction, checkIsSizableImageURL } from '../checkIsSizableImageURL'; diff --git a/packages/gitbook/src/lib/images/signatures.ts b/packages/gitbook/src/lib/images/signatures.ts index f9e782bfad..f813a72906 100644 --- a/packages/gitbook/src/lib/images/signatures.ts +++ b/packages/gitbook/src/lib/images/signatures.ts @@ -1,7 +1,7 @@ import 'server-only'; +import { getLogger } from '@/lib/logger'; import fnv1a from '@sindresorhus/fnv1a'; -import { getLogger } from '@v2/lib/logger'; import type { MaybePromise } from 'p-map'; import { assert } from 'ts-essentials'; import { GITBOOK_IMAGE_RESIZE_SIGNING_KEY } from '../env'; diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts index fca5dd9d0b..ef5a07f80a 100644 --- a/packages/gitbook/src/lib/logger.ts +++ b/packages/gitbook/src/lib/logger.ts @@ -1,4 +1,3 @@ -import { cache } from 'react'; export type LogLabelValue = string | number | undefined | boolean; export type LogLabels = { [key: string]: LogLabelValue }; @@ -44,13 +43,18 @@ export const createLogger = (name: string, options: LoggerOptions) => { export type GitbookLogger = ReturnType; -export const getLogger = cache(() => { - // This is not cryptographically secure, but it's fine for logging purposes. - // It allows us to identify logs from the same request. - // If we are in the middleware, we don't set a request ID because cache won't work well there. - const requestId = - process.env.NEXT_RUNTIME === 'edge' - ? undefined - : Math.random().toString(36).substring(2, 15); - return createLogger('GBOV2', { requestId }); -}); +const getRequestId = (fallbackRequestId?: string) => { + // We are in OpenNext and we should have access to the request ID. + if ((globalThis as any).__openNextAls) { + return (globalThis as any).__openNextAls.getStore()?.requestId; + } + return fallbackRequestId; +}; + +export const getLogger = + process.env.NEXT_RUNTIME === 'edge' + ? () => createLogger('GBOV2', { requestId: getRequestId() }) + : () => + createLogger('GBOV2', { + requestId: getRequestId(Math.random().toString(36).substring(2, 15)), + }); diff --git a/packages/gitbook/src/lib/tracing.ts b/packages/gitbook/src/lib/tracing.ts index 1d9401e7ed..925d27e5f9 100644 --- a/packages/gitbook/src/lib/tracing.ts +++ b/packages/gitbook/src/lib/tracing.ts @@ -1,4 +1,4 @@ -import { getLogger } from '@v2/lib/logger'; +import { getLogger } from '@/lib/logger'; export interface TraceSpan { setAttribute: (label: string, value: boolean | string | number) => void; From 8d7c6db13c731dba74d6f0d3e2ea6de892cf1fc8 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Wed, 9 Jul 2025 18:42:54 +0200 Subject: [PATCH 07/10] remove some useless log --- packages/gitbook/openNext/incrementalCache.ts | 173 ++++++++---------- packages/gitbook/openNext/queue/middleware.ts | 7 +- packages/gitbook/openNext/queue/server.ts | 2 +- .../gitbook/openNext/tagCache/middleware.ts | 62 ++----- packages/gitbook/src/lib/images/signatures.ts | 9 +- 5 files changed, 95 insertions(+), 158 deletions(-) diff --git a/packages/gitbook/openNext/incrementalCache.ts b/packages/gitbook/openNext/incrementalCache.ts index 6a373ff32b..f16a2b4e7e 100644 --- a/packages/gitbook/openNext/incrementalCache.ts +++ b/packages/gitbook/openNext/incrementalCache.ts @@ -1,6 +1,4 @@ import { createHash } from 'node:crypto'; - -import { trace } from '@/lib/tracing'; import type { CacheEntryType, CacheValue, @@ -34,41 +32,31 @@ class GitbookIncrementalCache implements IncrementalCache { cacheType?: CacheType ): Promise> | null> { const cacheKey = this.getR2Key(key, cacheType); - return trace( - { - operation: 'openNextIncrementalCacheGet', - name: cacheKey, - }, - async (span) => { - span.setAttribute('cacheType', cacheType ?? 'cache'); - const r2 = getCloudflareContext().env[BINDING_NAME]; - const localCache = await this.getCacheInstance(); - if (!r2) throw new Error('No R2 bucket'); - try { - // Check local cache first if available - const localCacheEntry = await localCache.match(this.getCacheUrlKey(cacheKey)); - if (localCacheEntry) { - span.setAttribute('cacheHit', 'local'); - const result = (await localCacheEntry.json()) as WithLastModified< - CacheValue - >; - return this.returnNullOn404(result); - } - const r2Object = await r2.get(cacheKey); - if (!r2Object) return null; - - span.setAttribute('cacheHit', 'r2'); - return this.returnNullOn404({ - value: await r2Object.json(), - lastModified: r2Object.uploaded.getTime(), - }); - } catch (e) { - console.error('Failed to get from cache', e); - return null; - } + const r2 = getCloudflareContext().env[BINDING_NAME]; + const localCache = await this.getCacheInstance(); + if (!r2) throw new Error('No R2 bucket'); + try { + // Check local cache first if available + const localCacheEntry = await localCache.match(this.getCacheUrlKey(cacheKey)); + if (localCacheEntry) { + const result = (await localCacheEntry.json()) as WithLastModified< + CacheValue + >; + return this.returnNullOn404(result); } - ); + + const r2Object = await r2.get(cacheKey); + if (!r2Object) return null; + + return this.returnNullOn404({ + value: await r2Object.json(), + lastModified: r2Object.uploaded.getTime(), + }); + } catch (e) { + console.error('Failed to get from cache', e); + return null; + } } //TODO: This is a workaround to handle 404 responses in the cache. @@ -89,75 +77,60 @@ class GitbookIncrementalCache implements IncrementalCache { cacheType?: CacheType ): Promise { const cacheKey = this.getR2Key(key, cacheType); - return trace( - { - operation: 'openNextIncrementalCacheSet', - name: cacheKey, - }, - async (span) => { - span.setAttribute('cacheType', cacheType ?? 'cache'); - const localCache = await this.getCacheInstance(); - - try { - await this.writeToR2(cacheKey, JSON.stringify(value)); - - //TODO: Check if there is any places where we don't have tags - // Ideally we should always have tags, but in case we don't, we need to decide how to handle it - // For now we default to a build ID tag, which allow us to invalidate the cache in case something is wrong in this deployment - const tags = this.getTagsFromCacheEntry(value) ?? [ - `build_id/${process.env.NEXT_BUILD_ID}`, - ]; - - // We consider R2 as the source of truth, so we update the local cache - // only after a successful R2 write - await localCache.put( - this.getCacheUrlKey(cacheKey), - new Response( - JSON.stringify({ - value, - // Note: `Date.now()` returns the time of the last IO rather than the actual time. - // See https://developers.cloudflare.com/workers/reference/security-model/ - lastModified: Date.now(), - }), - { - headers: { - // Cache-Control default to 30 minutes, will be overridden by `revalidate` - // In theory we should always get the `revalidate` value - 'cache-control': `max-age=${value.revalidate ?? 60 * 30}`, - 'cache-tag': tags.join(','), - }, - } - ) - ); - } catch (e) { - console.error('Failed to set to cache', e); - } - } - ); + + const localCache = await this.getCacheInstance(); + + try { + await this.writeToR2(cacheKey, JSON.stringify(value)); + + //TODO: Check if there is any places where we don't have tags + // Ideally we should always have tags, but in case we don't, we need to decide how to handle it + // For now we default to a build ID tag, which allow us to invalidate the cache in case something is wrong in this deployment + const tags = this.getTagsFromCacheEntry(value) ?? [ + `build_id/${process.env.NEXT_BUILD_ID}`, + ]; + + // We consider R2 as the source of truth, so we update the local cache + // only after a successful R2 write + await localCache.put( + this.getCacheUrlKey(cacheKey), + new Response( + JSON.stringify({ + value, + // Note: `Date.now()` returns the time of the last IO rather than the actual time. + // See https://developers.cloudflare.com/workers/reference/security-model/ + lastModified: Date.now(), + }), + { + headers: { + // Cache-Control default to 30 minutes, will be overridden by `revalidate` + // In theory we should always get the `revalidate` value + 'cache-control': `max-age=${value.revalidate ?? 60 * 30}`, + 'cache-tag': tags.join(','), + }, + } + ) + ); + } catch (e) { + console.error('Failed to set to cache', e); + } } async delete(key: string): Promise { const cacheKey = this.getR2Key(key); - return trace( - { - operation: 'openNextIncrementalCacheDelete', - name: cacheKey, - }, - async () => { - const r2 = getCloudflareContext().env[BINDING_NAME]; - const localCache = await this.getCacheInstance(); - if (!r2) throw new Error('No R2 bucket'); - - try { - await r2.delete(cacheKey); - - // Here again R2 is the source of truth, so we delete from local cache first - await localCache.delete(this.getCacheUrlKey(cacheKey)); - } catch (e) { - console.error('Failed to delete from cache', e); - } - } - ); + + const r2 = getCloudflareContext().env[BINDING_NAME]; + const localCache = await this.getCacheInstance(); + if (!r2) throw new Error('No R2 bucket'); + + try { + await r2.delete(cacheKey); + + // Here again R2 is the source of truth, so we delete from local cache first + await localCache.delete(this.getCacheUrlKey(cacheKey)); + } catch (e) { + console.error('Failed to delete from cache', e); + } } async writeToR2(key: string, value: string): Promise { diff --git a/packages/gitbook/openNext/queue/middleware.ts b/packages/gitbook/openNext/queue/middleware.ts index 5ab486a975..11428f4640 100644 --- a/packages/gitbook/openNext/queue/middleware.ts +++ b/packages/gitbook/openNext/queue/middleware.ts @@ -1,4 +1,3 @@ -import { trace } from '@/lib/tracing'; import type { Queue } from '@opennextjs/aws/types/overrides.js'; import { getCloudflareContext } from '@opennextjs/cloudflare'; import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue'; @@ -6,9 +5,7 @@ import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue'; export default { name: 'GitbookISRQueue', send: async (msg) => { - return trace({ operation: 'gitbookISRQueueSend', name: msg.MessageBody.url }, async () => { - const { ctx } = getCloudflareContext(); - ctx.waitUntil(doQueue.send(msg)); - }); + const { ctx } = getCloudflareContext(); + ctx.waitUntil(doQueue.send(msg)); }, } satisfies Queue; diff --git a/packages/gitbook/openNext/queue/server.ts b/packages/gitbook/openNext/queue/server.ts index aaeddefd18..9e3756748c 100644 --- a/packages/gitbook/openNext/queue/server.ts +++ b/packages/gitbook/openNext/queue/server.ts @@ -1,5 +1,5 @@ +import { getLogger } from '@/lib/logger'; import type { Queue } from '@opennextjs/aws/types/overrides.js'; -import { getLogger } from '@v2/lib/logger'; export default { name: 'GitbookISRQueue', diff --git a/packages/gitbook/openNext/tagCache/middleware.ts b/packages/gitbook/openNext/tagCache/middleware.ts index b94acd73a7..6ee480cda6 100644 --- a/packages/gitbook/openNext/tagCache/middleware.ts +++ b/packages/gitbook/openNext/tagCache/middleware.ts @@ -1,8 +1,7 @@ -import { trace } from '@/lib/tracing'; +import { getLogger } from '@/lib/logger'; import type { NextModeTagCache } from '@opennextjs/aws/types/overrides.js'; import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache'; import { softTagFilter } from '@opennextjs/cloudflare/overrides/tag-cache/tag-cache-filter'; -import { getLogger } from '@v2/lib/logger'; const originalTagCache = doShardedTagCache({ baseShardSize: 12, @@ -24,62 +23,27 @@ export default { getLastRevalidated: async (tags: string[]) => { const tagsToCheck = tags.filter(softTagFilter); if (tagsToCheck.length === 0) { - const logger = getLogger().subLogger('gitbookTagCache'); - // If we reach here, it probably means that there is an issue that we'll need to address. - logger.warn( - 'getLastRevalidated - No valid tags to check for last revalidation, original tags:', - tags - ); return 0; // If no tags to check, return 0 } - return trace( - { - operation: 'gitbookTagCacheGetLastRevalidated', - name: tagsToCheck.join(', '), - }, - async () => { - return await originalTagCache.getLastRevalidated(tagsToCheck); - } - ); + + return await originalTagCache.getLastRevalidated(tagsToCheck); }, hasBeenRevalidated: async (tags: string[], lastModified?: number) => { const tagsToCheck = tags.filter(softTagFilter); if (tagsToCheck.length === 0) { - const logger = getLogger().subLogger('gitbookTagCache'); - // If we reach here, it probably means that there is an issue that we'll need to address. - logger.warn( - 'hasBeenRevalidated - No valid tags to check for revalidation, original tags:', - tags - ); return false; // If no tags to check, return false } - return trace( - { - operation: 'gitbookTagCacheHasBeenRevalidated', - name: tagsToCheck.join(', '), - }, - async () => { - const result = await originalTagCache.hasBeenRevalidated(tagsToCheck, lastModified); - return result; - } - ); + + return await originalTagCache.hasBeenRevalidated(tagsToCheck, lastModified); }, writeTags: async (tags: string[]) => { - return trace( - { - operation: 'gitbookTagCacheWriteTags', - name: tags.join(', '), - }, - async () => { - const tagsToWrite = tags.filter(softTagFilter); - if (tagsToWrite.length === 0) { - const logger = getLogger().subLogger('gitbookTagCache'); - logger.warn('writeTags - No valid tags to write'); - return; // If no tags to write, exit early - } - // Write only the filtered tags - await originalTagCache.writeTags(tagsToWrite); - } - ); + const tagsToWrite = tags.filter(softTagFilter); + if (tagsToWrite.length === 0) { + const logger = getLogger().subLogger('gitbookTagCache'); + logger.warn('writeTags - No valid tags to write'); + return; // If no tags to write, exit early + } + // Write only the filtered tags + await originalTagCache.writeTags(tagsToWrite); }, } satisfies NextModeTagCache; diff --git a/packages/gitbook/src/lib/images/signatures.ts b/packages/gitbook/src/lib/images/signatures.ts index f813a72906..bec38771f0 100644 --- a/packages/gitbook/src/lib/images/signatures.ts +++ b/packages/gitbook/src/lib/images/signatures.ts @@ -35,9 +35,12 @@ export async function verifyImageSignature( const generated = await generator(input); const logger = getLogger().subLogger('image-signature'); - logger.log( - `comparing image signature for "${input.url}" on identifier "${input.imagesContextId}": "${generated}" (expected) === "${signature}" (actual)` - ); + if (generated !== signature) { + // We only log if the signature does not match, to avoid logging useless information + logger.log( + `comparing image signature for "${input.url}" on identifier "${input.imagesContextId}": "${generated}" (expected) === "${signature}" (actual)` + ); + } return generated === signature; } From 058ed9bc427b305b1299d6991edaf00257ac6575 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Wed, 9 Jul 2025 18:43:43 +0200 Subject: [PATCH 08/10] append request id in prod headers --- .../gitbook/openNext/customWorkers/defaultWrangler.jsonc | 8 ++++++-- .../openNext/customWorkers/middlewareWrangler.jsonc | 8 +++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc b/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc index 88cc738565..77f0bfde6e 100644 --- a/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc +++ b/packages/gitbook/openNext/customWorkers/defaultWrangler.jsonc @@ -16,7 +16,8 @@ "env": { "dev": { "vars": { - "STAGE": "dev" + "STAGE": "dev", + "OPEN_NEXT_REQUEST_ID_HEADER": "true" }, "r2_buckets": [ { @@ -84,6 +85,9 @@ } }, "staging": { + "vars": { + "OPEN_NEXT_REQUEST_ID_HEADER": "true" + }, "r2_buckets": [ { "binding": "NEXT_INC_CACHE_R2_BUCKET", @@ -126,7 +130,7 @@ // This is a bit misleading, but it means that we can have 500 concurrent revalidations // This means that we'll have up to 100 durable objects instance running at the same time "MAX_REVALIDATE_CONCURRENCY": "100", - "OPEN_NEXT_REQUEST_ID_HEADER": true + "OPEN_NEXT_REQUEST_ID_HEADER": "true" }, "r2_buckets": [ { diff --git a/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc b/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc index 51c92b2160..d9c379809d 100644 --- a/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc +++ b/packages/gitbook/openNext/customWorkers/middlewareWrangler.jsonc @@ -21,7 +21,8 @@ "dev": { "vars": { "STAGE": "dev", - "NEXT_PRIVATE_DEBUG_CACHE": "true" + "NEXT_PRIVATE_DEBUG_CACHE": "true", + "OPEN_NEXT_REQUEST_ID_HEADER": "true" }, "r2_buckets": [ { @@ -85,7 +86,8 @@ "staging": { "vars": { "STAGE": "staging", - "WORKER_VERSION_ID": "TO_REPLACE" + "WORKER_VERSION_ID": "TO_REPLACE", + "OPEN_NEXT_REQUEST_ID_HEADER": "true" }, "routes": [ { @@ -154,7 +156,7 @@ "DEBUG_CLOUDFLARE": "true", "WORKER_VERSION_ID": "TO_REPLACE", "STAGE": "production", - "OPEN_NEXT_REQUEST_ID_HEADER": true + "OPEN_NEXT_REQUEST_ID_HEADER": "true" }, "routes": [ { From d1cf1f675570234bca15f6e2662a815109882866 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 10 Jul 2025 16:23:49 +0200 Subject: [PATCH 09/10] remove useless trace --- packages/gitbook/src/lib/data/api.ts | 150 +++++++++++---------------- 1 file changed, 62 insertions(+), 88 deletions(-) diff --git a/packages/gitbook/src/lib/data/api.ts b/packages/gitbook/src/lib/data/api.ts index 3494c38649..7bae34cad5 100644 --- a/packages/gitbook/src/lib/data/api.ts +++ b/packages/gitbook/src/lib/data/api.ts @@ -50,124 +50,98 @@ export function createDataFetcher( // API that are tied to the token // getPublishedContentSite(params) { - return trace('getPublishedContentSite', () => - getPublishedContentSite(input, { - organizationId: params.organizationId, - siteId: params.siteId, - siteShareKey: params.siteShareKey, - }) - ); + return getPublishedContentSite(input, { + organizationId: params.organizationId, + siteId: params.siteId, + siteShareKey: params.siteShareKey, + }); }, getSiteRedirectBySource(params) { - return trace('getSiteRedirectBySource', () => - getSiteRedirectBySource(input, { - organizationId: params.organizationId, - siteId: params.siteId, - siteShareKey: params.siteShareKey, - source: params.source, - }) - ); + return getSiteRedirectBySource(input, { + organizationId: params.organizationId, + siteId: params.siteId, + siteShareKey: params.siteShareKey, + source: params.source, + }); }, getRevision(params) { - return trace('getRevision', () => - getRevision(input, { - spaceId: params.spaceId, - revisionId: params.revisionId, - }) - ); + return getRevision(input, { + spaceId: params.spaceId, + revisionId: params.revisionId, + }); }, getRevisionPageByPath(params) { - return trace('getRevisionPageByPath', () => - getRevisionPageByPath(input, { - spaceId: params.spaceId, - revisionId: params.revisionId, - path: params.path, - }) - ); + return getRevisionPageByPath(input, { + spaceId: params.spaceId, + revisionId: params.revisionId, + path: params.path, + }); }, getRevisionPageMarkdown(params) { - return trace('getRevisionPageMarkdown', () => - getRevisionPageMarkdown(input, { - spaceId: params.spaceId, - revisionId: params.revisionId, - pageId: params.pageId, - }) - ); + return getRevisionPageMarkdown(input, { + spaceId: params.spaceId, + revisionId: params.revisionId, + pageId: params.pageId, + }); }, getRevisionPageDocument(params) { - return trace('getRevisionPageDocument', () => - getRevisionPageDocument(input, { - spaceId: params.spaceId, - revisionId: params.revisionId, - pageId: params.pageId, - }) - ); + return getRevisionPageDocument(input, { + spaceId: params.spaceId, + revisionId: params.revisionId, + pageId: params.pageId, + }); }, getLatestOpenAPISpecVersionContent(params) { - return trace('getLatestOpenAPISpecVersionContent', () => - getLatestOpenAPISpecVersionContent(input, { - organizationId: params.organizationId, - slug: params.slug, - }) - ); + return getLatestOpenAPISpecVersionContent(input, { + organizationId: params.organizationId, + slug: params.slug, + }); }, getSpace(params) { - return trace('getSpace', () => - getSpace(input, { - spaceId: params.spaceId, - shareKey: params.shareKey, - }) - ); + return getSpace(input, { + spaceId: params.spaceId, + shareKey: params.shareKey, + }); }, getChangeRequest(params) { - return trace('getChangeRequest', () => - getChangeRequest(input, { - spaceId: params.spaceId, - changeRequestId: params.changeRequestId, - }) - ); + return getChangeRequest(input, { + spaceId: params.spaceId, + changeRequestId: params.changeRequestId, + }); }, getDocument(params) { - return trace('getDocument', () => - getDocument(input, { - spaceId: params.spaceId, - documentId: params.documentId, - }) - ); + return getDocument(input, { + spaceId: params.spaceId, + documentId: params.documentId, + }); }, getComputedDocument(params) { - return trace('getComputedDocument', () => - getComputedDocument(input, { - organizationId: params.organizationId, - spaceId: params.spaceId, - source: params.source, - seed: params.seed, - }) - ); + return getComputedDocument(input, { + organizationId: params.organizationId, + spaceId: params.spaceId, + source: params.source, + seed: params.seed, + }); }, getEmbedByUrl(params) { - return trace('getEmbedByUrl', () => - getEmbedByUrl(input, { - url: params.url, - spaceId: params.spaceId, - }) - ); + return getEmbedByUrl(input, { + url: params.url, + spaceId: params.spaceId, + }); }, searchSiteContent(params) { - return trace('searchSiteContent', () => searchSiteContent(input, params)); + return searchSiteContent(input, params); }, renderIntegrationUi(params) { - return trace('renderIntegrationUi', () => - renderIntegrationUi(input, { - integrationName: params.integrationName, - request: params.request, - }) - ); + return renderIntegrationUi(input, { + integrationName: params.integrationName, + request: params.request, + }); }, getUserById(userId) { - return trace('getUserById', () => getUserById(input, { userId })); + return getUserById(input, { userId }); }, }; } From a59357aed9f98b58778c25488fdef308cd17caf0 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 11 Jul 2025 10:19:57 +0200 Subject: [PATCH 10/10] review fix --- packages/gitbook/src/lib/images/resizer/cdn-cgi.ts | 2 +- packages/gitbook/src/lib/images/resizer/cf-fetch.ts | 2 +- packages/gitbook/src/lib/images/resizer/resizeImage.ts | 2 +- packages/gitbook/src/lib/images/signatures.ts | 2 +- packages/gitbook/src/lib/logger.ts | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts index b5dcb8db0b..1151c59b09 100644 --- a/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts +++ b/packages/gitbook/src/lib/images/resizer/cdn-cgi.ts @@ -25,7 +25,7 @@ export async function resizeImageWithCDNCgi( resizeOptions )}/${encodeURIComponent(input)}`; - const logger = getLogger().subLogger('resize-image-cdn-cgi'); + const logger = getLogger().subLogger('imageResizing'); logger.log(`resize image using cdn-cgi: ${resizeURL}`); return copyImageResponse( diff --git a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts index 2c37d4dafe..fe5eaa2ca0 100644 --- a/packages/gitbook/src/lib/images/resizer/cf-fetch.ts +++ b/packages/gitbook/src/lib/images/resizer/cf-fetch.ts @@ -14,7 +14,7 @@ export async function resizeImageWithCFFetch( ): Promise { const { signal, ...resizeOptions } = options; - const logger = getLogger().subLogger('resize-image-cf-fetch'); + const logger = getLogger().subLogger('imageResizing'); logger.log(`resize image using cf-fetch: ${input}`); return copyImageResponse( diff --git a/packages/gitbook/src/lib/images/resizer/resizeImage.ts b/packages/gitbook/src/lib/images/resizer/resizeImage.ts index ea33a530e7..75503350fd 100644 --- a/packages/gitbook/src/lib/images/resizer/resizeImage.ts +++ b/packages/gitbook/src/lib/images/resizer/resizeImage.ts @@ -35,7 +35,7 @@ export async function getImageSize( height: json.original.height, }; } catch (error) { - const logger = getLogger().subLogger('get-image-size'); + const logger = getLogger().subLogger('imageResizing'); logger.warn(`Error getting image size for ${input}:`, error); return null; } diff --git a/packages/gitbook/src/lib/images/signatures.ts b/packages/gitbook/src/lib/images/signatures.ts index bec38771f0..831aca04fa 100644 --- a/packages/gitbook/src/lib/images/signatures.ts +++ b/packages/gitbook/src/lib/images/signatures.ts @@ -34,7 +34,7 @@ export async function verifyImageSignature( const generator = IMAGE_SIGNATURE_FUNCTIONS[version]; const generated = await generator(input); - const logger = getLogger().subLogger('image-signature'); + const logger = getLogger().subLogger('imageResizing'); if (generated !== signature) { // We only log if the signature does not match, to avoid logging useless information logger.log( diff --git a/packages/gitbook/src/lib/logger.ts b/packages/gitbook/src/lib/logger.ts index ef5a07f80a..8f446c677d 100644 --- a/packages/gitbook/src/lib/logger.ts +++ b/packages/gitbook/src/lib/logger.ts @@ -12,6 +12,7 @@ export type LoggerOptions = SubLoggerOptions & { const formatPrefix = (name: string, options: LoggerOptions) => { const { labels } = options; + // The tail worker used for extracting the labels expect this format. return `%${JSON.stringify(labels ?? {})}%[${name}]`; };