From 98957eaf75758e986be0514eb6e1af96045d519f Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Wed, 19 Nov 2025 14:47:01 +0100 Subject: [PATCH 1/3] feat: move logger property to top level instead of having it in agent object --- packages/libraries/core/src/client/agent.ts | 6 +- packages/libraries/core/src/client/client.ts | 4 +- packages/libraries/core/src/client/types.ts | 8 + packages/libraries/core/tests/usage.spec.ts | 146 +++++++++++++++++++ 4 files changed, 161 insertions(+), 3 deletions(-) diff --git a/packages/libraries/core/src/client/agent.ts b/packages/libraries/core/src/client/agent.ts index d310a0cb941..06e470a328e 100644 --- a/packages/libraries/core/src/client/agent.ts +++ b/packages/libraries/core/src/client/agent.ts @@ -67,7 +67,11 @@ export interface AgentOptions { */ maxSize?: number; /** - * Custom logger (defaults to console) + * Custom logger. + * + * Default: console based logger + * + * @deprecated Instead, provide a logger for the root Hive SDK. If a logger is provided on the root Hive SDK, this one is ignored. */ logger?: Logger; /** diff --git a/packages/libraries/core/src/client/client.ts b/packages/libraries/core/src/client/client.ts index 4c37eadd226..b7c84666db8 100644 --- a/packages/libraries/core/src/client/client.ts +++ b/packages/libraries/core/src/client/client.ts @@ -14,9 +14,9 @@ import { createHiveLogger, isLegacyAccessToken } from './utils.js'; export function createHive(options: HivePluginOptions): HiveClient { const logger = createHiveLogger( - options?.agent?.logger ?? console, + options?.logger ?? options?.agent?.logger ?? console, '[hive]', - options.debug ?? false, + options.debug, ); let enabled = options.enabled ?? true; diff --git a/packages/libraries/core/src/client/types.ts b/packages/libraries/core/src/client/types.ts index 85374d3cfb1..d2b1febe253 100644 --- a/packages/libraries/core/src/client/types.ts +++ b/packages/libraries/core/src/client/types.ts @@ -210,8 +210,16 @@ export type HivePluginOptions = OptionalWhenFalse< * Debugging mode * * Default: false + * + * @deprecated Use the {logger} property instead. */ debug?: boolean; + /** + * Custom logger. + * + * Default: console based logger + */ + logger?: Logger; /** * Access Token for usage reporting */ diff --git a/packages/libraries/core/tests/usage.spec.ts b/packages/libraries/core/tests/usage.spec.ts index 74f844a5dc5..732947997e8 100644 --- a/packages/libraries/core/tests/usage.spec.ts +++ b/packages/libraries/core/tests/usage.spec.ts @@ -885,3 +885,149 @@ test('constructs URL with usage.target (hvu1/)', async ({ expect }) => { expect(url).toEqual('http://localhost/the-guild/graphql-hive/staging'); await hive.dispose(); }); + +test('no debug property -> logger.debug is invoked', async ({ expect }) => { + const logger = createHiveTestingLogger(); + const token = 'hvu1/brrrrt'; + + const hive = createHive({ + enabled: true, + agent: { + timeout: 500, + maxRetries: 0, + sendInterval: 1, + maxSize: 1, + async fetch() { + return new Response('', { + status: 200, + }); + }, + logger, + }, + token, + selfHosting: { + graphqlEndpoint: 'http://localhost:2/graphql', + applicationUrl: 'http://localhost:1', + usageEndpoint: 'http://localhost', + }, + usage: { + target: 'the-guild/graphql-hive/staging', + }, + }); + + await hive.collectUsage()( + { + schema, + document: op, + operationName: 'asd', + }, + {}, + ); + + await hive.dispose(); + expect(logger.getLogs()).toMatchInlineSnapshot(` + [DBG] [hive][usage][agent] Disposing + [DBG] [hive][usage][agent] Sending immediately + [DBG] [hive][usage][agent] Sending report (queue 1) + [DBG] [hive][usage][agent] POST http://localhost/the-guild/graphql-hive/staging (x-request-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) + [DBG] [hive][usage][agent] POST http://localhost/the-guild/graphql-hive/staging (x-request-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) succeeded with status 200 (666ms). + [DBG] [hive][usage][agent] Report sent! + `); +}); + +test('debug: false -> logger.debug is not invoked', async ({ expect }) => { + const logger = createHiveTestingLogger(); + const token = 'hvu1/brrrrt'; + + const hive = createHive({ + enabled: true, + debug: false, + agent: { + timeout: 500, + maxRetries: 0, + sendInterval: 1, + maxSize: 1, + async fetch() { + return new Response('', { + status: 200, + }); + }, + logger, + }, + token, + selfHosting: { + graphqlEndpoint: 'http://localhost:2/graphql', + applicationUrl: 'http://localhost:1', + usageEndpoint: 'http://localhost', + }, + usage: { + target: 'the-guild/graphql-hive/staging', + }, + }); + + await hive.collectUsage()( + { + schema, + document: op, + operationName: 'asd', + }, + {}, + ); + + await hive.dispose(); + expect(logger.getLogs()).toMatchInlineSnapshot(``); +}); + +test('debug: true and missing logger.debug method -> logger.info is invoked (to cover legacy logger implementation)', async ({ + expect, +}) => { + const logger = createHiveTestingLogger(); + // @ts-expect-error + logger.debug = undefined; + const token = 'hvu1/brrrrt'; + + const hive = createHive({ + enabled: true, + debug: true, + agent: { + timeout: 500, + maxRetries: 0, + sendInterval: 1, + maxSize: 1, + async fetch() { + return new Response('', { + status: 200, + }); + }, + logger, + }, + token, + selfHosting: { + graphqlEndpoint: 'http://localhost:2/graphql', + applicationUrl: 'http://localhost:1', + usageEndpoint: 'http://localhost', + }, + usage: { + target: 'the-guild/graphql-hive/staging', + }, + }); + + await hive.collectUsage()( + { + schema, + document: op, + operationName: 'asd', + }, + {}, + ); + + await hive.dispose(); + expect(logger.getLogs()).toMatchInlineSnapshot(` + [INF] [hive][usage][agent] Disposing + [INF] [hive][usage][agent] Sending immediately + [INF] [hive][usage][agent] Sending report (queue 1) + [INF] [hive][usage][agent] POST http://localhost/the-guild/graphql-hive/staging (x-request-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) + [INF] [hive][usage][agent] POST http://localhost/the-guild/graphql-hive/staging (x-request-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) succeeded with status 200 (666ms). + [INF] [hive][usage][agent] Report sent! + `); +}); From 176f5386c66ec9555443b8cdabe8e0b1f7079e89 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Wed, 19 Nov 2025 15:01:48 +0100 Subject: [PATCH 2/3] wow --- packages/libraries/core/src/client/agent.ts | 2 +- packages/libraries/core/src/client/client.ts | 53 ++++++++++++++++++-- packages/libraries/core/src/client/types.ts | 4 +- packages/libraries/core/src/client/utils.ts | 6 +-- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/libraries/core/src/client/agent.ts b/packages/libraries/core/src/client/agent.ts index 06e470a328e..c0a65bc9a78 100644 --- a/packages/libraries/core/src/client/agent.ts +++ b/packages/libraries/core/src/client/agent.ts @@ -123,7 +123,7 @@ export function createAgent( ? null : pluginOptions.circuitBreaker, }; - const logger = createHiveLogger(pluginOptions.logger ?? console, '[agent]', pluginOptions.debug); + const logger = createHiveLogger(pluginOptions.logger ?? console, '[agent]'); let circuitBreaker: CircuitBreakerInterface< Parameters, diff --git a/packages/libraries/core/src/client/client.ts b/packages/libraries/core/src/client/client.ts index b7c84666db8..b4888d869fd 100644 --- a/packages/libraries/core/src/client/client.ts +++ b/packages/libraries/core/src/client/client.ts @@ -10,14 +10,61 @@ import { createPersistedDocuments } from './persisted-documents.js'; import { createReporting } from './reporting.js'; import type { HiveClient, HiveInternalPluginOptions, HivePluginOptions } from './types.js'; import { createUsage } from './usage.js'; -import { createHiveLogger, isLegacyAccessToken } from './utils.js'; +import { createHiveLogger, HiveLogger, isLegacyAccessToken } from './utils.js'; -export function createHive(options: HivePluginOptions): HiveClient { - const logger = createHiveLogger( +function chooseDefaultLogger(options: HivePluginOptions): HiveLogger { + if (options.logger === 'debug') { + return createHiveLogger( + { + debug(...args) { + console.debug(...args); + }, + info(...args) { + console.info(...args); + }, + error(...args) { + console.error(...args); + }, + }, + '[hive]', + ); + } + if (options.logger === 'info') { + return createHiveLogger( + { + debug() {}, + info(...args) { + console.info(...args); + }, + error(...args) { + console.error(...args); + }, + }, + '[hive]', + ); + } + if (options.logger === 'error') { + return createHiveLogger( + { + debug() {}, + info() {}, + error(...args) { + console.error(...args); + }, + }, + '[hive]', + ); + } + + return createHiveLogger( options?.logger ?? options?.agent?.logger ?? console, '[hive]', options.debug, ); +} + +export function createHive(options: HivePluginOptions): HiveClient { + const logger = chooseDefaultLogger(options); let enabled = options.enabled ?? true; if (enabled === false && !options.experimental__persistedDocuments) { diff --git a/packages/libraries/core/src/client/types.ts b/packages/libraries/core/src/client/types.ts index d2b1febe253..28181c4a7da 100644 --- a/packages/libraries/core/src/client/types.ts +++ b/packages/libraries/core/src/client/types.ts @@ -217,9 +217,9 @@ export type HivePluginOptions = OptionalWhenFalse< /** * Custom logger. * - * Default: console based logger + * Default: 'info' */ - logger?: Logger; + logger?: Logger | 'error' | 'info' | 'debug'; /** * Access Token for usage reporting */ diff --git a/packages/libraries/core/src/client/utils.ts b/packages/libraries/core/src/client/utils.ts index 3ee19bbcf1a..55c4c3867ca 100644 --- a/packages/libraries/core/src/client/utils.ts +++ b/packages/libraries/core/src/client/utils.ts @@ -210,9 +210,6 @@ export function createHiveLogger(baseLogger: Logger, prefix: string, debug = tru return { [hiveSymbol]: context, - info: (message: string) => { - logger.info(printPath(path) + message); - }, error: (error: any, ...data: any[]) => { if (error.stack) { const pth = printPath(path); @@ -223,6 +220,9 @@ export function createHiveLogger(baseLogger: Logger, prefix: string, debug = tru logger.error(printPath(path) + String(error), ...data); } }, + info: (message: string) => { + logger.info(printPath(path) + message); + }, debug: (message: string) => { if (!context.debug) { return; From 2114519e6ccea59042b54324e9dab6a987058f29 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Wed, 19 Nov 2025 15:08:45 +0100 Subject: [PATCH 3/3] fix --- packages/libraries/core/tests/usage.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/libraries/core/tests/usage.spec.ts b/packages/libraries/core/tests/usage.spec.ts index 732947997e8..dc49dee59c8 100644 --- a/packages/libraries/core/tests/usage.spec.ts +++ b/packages/libraries/core/tests/usage.spec.ts @@ -982,7 +982,7 @@ test('debug: true and missing logger.debug method -> logger.info is invoked (to expect, }) => { const logger = createHiveTestingLogger(); - // @ts-expect-error + // @ts-expect-error we remove this property to emulate logger without it logger.debug = undefined; const token = 'hvu1/brrrrt';