Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/@graphql-hive_gateway-runtime-642-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@graphql-hive/gateway-runtime': patch
---

dependencies updates:

- Added dependency [`@graphql-hive/logger-json@workspace:^` ↗︎](https://www.npmjs.com/package/@graphql-hive/logger-json/v/workspace:^) (to `dependencies`)
15 changes: 15 additions & 0 deletions .changeset/big-waves-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@graphql-mesh/transport-http-callback': patch
'@graphql-mesh/plugin-opentelemetry': patch
'@graphql-mesh/fusion-runtime': patch
'@graphql-mesh/transport-ws': patch
'@graphql-hive/importer': patch
'@graphql-hive/gateway': patch
'@graphql-hive/gateway-runtime': patch
'@graphql-hive/logger-json': patch
---

New JSON-based logger

By default, it prints pretty still to the console unless NODE_ENV is production.
For JSON output, set the `LOG_FORMAT` environment variable to `json`.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
"vitest": "^3.0.1"
},
"resolutions": {
"@graphql-mesh/types": "0.103.16-alpha-20250212125252-6167fff12fe4017202b35363ff2769aafe28f98a",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update this before merging?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!

"@graphql-mesh/utils": "0.103.16-alpha-20250212125252-6167fff12fe4017202b35363ff2769aafe28f98a",
"@graphql-tools/delegate": "workspace:^",
"@opentelemetry/exporter-trace-otlp-http": "patch:@opentelemetry/exporter-trace-otlp-http@npm%3A0.56.0#~/.yarn/patches/@opentelemetry-exporter-trace-otlp-http-npm-0.56.0-dddd282e41.patch",
"@opentelemetry/otlp-exporter-base": "patch:@opentelemetry/otlp-exporter-base@npm%3A0.56.0#~/.yarn/patches/@opentelemetry-otlp-exporter-base-npm-0.56.0-ba3dc5f5c5.patch",
Expand Down
6 changes: 4 additions & 2 deletions packages/fusion-runtime/src/federation/supergraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,13 @@ export const handleFederationSupergraph: UnifiedGraphHandler = function ({
if (context?.request) {
requestId = requestIdByRequest.get(context.request);
if (requestId) {
currentLogger = currentLogger?.child(requestId);
currentLogger = currentLogger?.child({ requestId });
}
}
if (sourceSubschema.name) {
currentLogger = currentLogger?.child(sourceSubschema.name);
currentLogger = currentLogger?.child({
subgraph: sourceSubschema.name,
});
}
for (const onDelegationPlan of onDelegationPlanHooks) {
const onDelegationPlanDone = onDelegationPlan({
Expand Down
12 changes: 6 additions & 6 deletions packages/fusion-runtime/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function getTransportExecutor({
let logger = transportContext?.logger;
if (logger) {
if (subgraphName) {
logger = logger.child(subgraphName);
logger = logger.child({ subgraph: subgraphName });
}
logger?.debug(`Loading transport "${kind}"`);
}
Expand Down Expand Up @@ -195,10 +195,10 @@ export function getOnSubgraphExecute({
executionRequest.context?.request,
);
if (requestId) {
logger = logger.child(requestId);
logger = logger.child({ requestId });
}
if (subgraphName) {
logger = logger.child(subgraphName);
logger = logger.child({ subgraph: subgraphName });
}
logger.debug(`Initializing executor`);
}
Expand Down Expand Up @@ -287,7 +287,7 @@ export function wrapExecutorWithHooks({
let execReqLogger = transportContext?.logger;
if (execReqLogger) {
if (requestId) {
execReqLogger = execReqLogger.child(requestId);
execReqLogger = execReqLogger.child({ requestId });
}
loggerForExecutionRequest.set(baseExecutionRequest, execReqLogger);
}
Expand Down Expand Up @@ -548,11 +548,11 @@ export function wrapMergedTypeResolver<TContext extends Record<string, any>>(
if (logger && context['request']) {
requestId = requestIdByRequest.get(context['request']);
if (requestId) {
logger = logger.child(requestId);
logger = logger.child({ requestId });
}
}
if (subschema.name) {
logger = logger?.child(subschema.name);
logger = logger?.child({ subgraph: subschema.name });
}
let resolver = originalResolver as MergedTypeResolver<TContext>;
function setResolver(newResolver: MergedTypeResolver<TContext>) {
Expand Down
5 changes: 3 additions & 2 deletions packages/fusion-runtime/tests/polling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
createDefaultExecutor,
type DisposableExecutor,
} from '@graphql-mesh/transport-common';
import { DefaultLogger, makeDisposable } from '@graphql-mesh/utils';
import { makeDisposable } from '@graphql-mesh/utils';
import { normalizedExecutor } from '@graphql-tools/executor';
import {
createDeferred,
Expand All @@ -17,6 +17,7 @@ import { DisposableSymbols } from '@whatwg-node/disposablestack';
import { ExecutionResult, GraphQLSchema, parse } from 'graphql';
import { createSchema } from 'graphql-yoga';
import { describe, expect, it, vi } from 'vitest';
import { getDefaultLogger } from '../../runtime/src/getDefaultLogger';
import { UnifiedGraphManager } from '../src/unifiedGraphManager';

describe('Polling', () => {
Expand Down Expand Up @@ -334,7 +335,7 @@ describe('Polling', () => {
const unifiedGraphFetcher = vi.fn(() => {
return graphDeferred ? graphDeferred.promise : unifiedGraph;
});
const logger = new DefaultLogger();
const logger = getDefaultLogger();
await using executor = getExecutorForUnifiedGraph({
getUnifiedGraph: unifiedGraphFetcher,
pollingInterval: 10_000,
Expand Down
4 changes: 2 additions & 2 deletions packages/gateway/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'dotenv/config'; // inject dotenv options to process.env

import module from 'node:module';
import type { InitializeData } from '@graphql-hive/importer/hooks';
import { DefaultLogger } from '@graphql-mesh/utils';
import { getDefaultLogger } from '../../runtime/src/getDefaultLogger';
import { enableModuleCachingIfPossible, handleNodeWarnings, run } from './cli';

// @inject-version globalThis.__VERSION__ here
Expand All @@ -20,7 +20,7 @@ module.register('@graphql-hive/importer/hooks', {
enableModuleCachingIfPossible();
handleNodeWarnings();

const log = new DefaultLogger();
const log = getDefaultLogger();

run({ log }).catch((err) => {
log.error(err);
Expand Down
20 changes: 10 additions & 10 deletions packages/gateway/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {
InvalidArgumentError,
Option,
} from '@commander-js/extra-typings';
import type {
GatewayConfigContext,
GatewayConfigProxy,
GatewayConfigSubgraph,
GatewayConfigSupergraph,
GatewayGraphOSReportingOptions,
GatewayHiveReportingOptions,
import {
type GatewayConfigContext,
type GatewayConfigProxy,
type GatewayConfigSubgraph,
type GatewayConfigSupergraph,
type GatewayGraphOSReportingOptions,
type GatewayHiveReportingOptions,
} from '@graphql-hive/gateway-runtime';
import type UpstashRedisCache from '@graphql-mesh/cache-upstash-redis';
import type { JWTAuthPluginOptions } from '@graphql-mesh/plugin-jwt-auth';
Expand All @@ -26,8 +26,8 @@ import type {
MeshPubSub,
YamlConfig,
} from '@graphql-mesh/types';
import { DefaultLogger } from '@graphql-mesh/utils';
import parseDuration from 'parse-duration';
import { getDefaultLogger } from '../../runtime/src/getDefaultLogger';
import { addCommands } from './commands/index';
import { createDefaultConfigPaths } from './config';
import { getMaxConcurrency } from './getMaxConcurrency';
Expand Down Expand Up @@ -347,7 +347,7 @@ let cli = new Command()

export async function run(userCtx: Partial<CLIContext>) {
const ctx: CLIContext = {
log: userCtx.log || new DefaultLogger(),
log: userCtx.log || getDefaultLogger(),
productName: 'Hive Gateway',
productDescription: 'Federated GraphQL Gateway',
productPackageName: '@graphql-hive/gateway',
Expand All @@ -362,7 +362,7 @@ export async function run(userCtx: Partial<CLIContext>) {
cli = cli.name(binName).description(productDescription).version(version);

if (cluster.worker?.id) {
ctx.log = ctx.log.child(`Worker #${cluster.worker.id}`);
ctx.log = ctx.log.child({ worker: cluster.worker.id });
}

addCommands(ctx, cli);
Expand Down
23 changes: 16 additions & 7 deletions packages/gateway/src/commands/handleFork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,34 @@ export function handleFork(log: Logger, config: { fork?: number }): boolean {
log.debug(`Forking ${config.fork} workers`);
for (let i = 0; i < config.fork; i++) {
const worker = cluster.fork();
const workerLogger = log.child({ worker: worker.id });
worker.once('exit', (code, signal) => {
const logData: Record<string, string | number> = {
signal,
};
if (code != null) {
logData['code'] = code;
}
if (expectedToExit) {
log.debug(
`Worker ${worker.process.pid} exited with code ${code} and signal ${signal}`,
);
workerLogger.debug('exited', logData);
} else {
log.warn(`Worker ${worker.process.pid} exited unexpectedly with code ${code} and signal ${signal}\n
A restart is recommended to ensure the stability of the service`);
workerLogger.error(
'exited unexpectedly. A restart is recommended to ensure the stability of the service',
logData,
);
}
workers.delete(worker);
if (!expectedToExit && workers.size === 0) {
log.error(`All workers exited unexpectedly. Exiting`);
log.error(`All workers exited unexpectedly. Exiting`, logData);
process.exit(1);
}
});
workers.add(worker);
}
registerTerminateHandler((signal) => {
log.info(`Killing workers with ${signal}`);
log.info('Killing workers', {
signal,
});
expectedToExit = true;
workers.forEach((w) => {
w.kill(signal);
Expand Down
17 changes: 12 additions & 5 deletions packages/gateway/src/commands/handleLoggingOption.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Logger } from '@graphql-mesh/types';
import { CLIContext, DefaultLogger, LogLevel } from '..';
import { CLIContext, LogLevel } from '..';
import { getDefaultLogger } from '../../../runtime/src/getDefaultLogger';

export function handleLoggingConfig(
loggingConfig: boolean | Logger | LogLevel | undefined,
Expand All @@ -9,17 +10,23 @@ export function handleLoggingConfig(
ctx.log = loggingConfig;
} else if (typeof loggingConfig === 'boolean') {
if (!loggingConfig) {
if (ctx.log instanceof DefaultLogger) {
if ('logLevel' in ctx.log) {
ctx.log.logLevel = LogLevel.silent;
} else {
ctx.log = new DefaultLogger(ctx.log.name, LogLevel.silent);
ctx.log = getDefaultLogger({
name: ctx.log.name,
level: LogLevel.silent,
});
}
}
} else if (typeof loggingConfig === 'number') {
if (ctx.log instanceof DefaultLogger) {
if ('logLevel' in ctx.log) {
ctx.log.logLevel = loggingConfig;
} else {
ctx.log = new DefaultLogger(ctx.log.name, loggingConfig);
ctx.log = getDefaultLogger({
name: ctx.log.name,
level: loggingConfig,
});
}
}
}
5 changes: 3 additions & 2 deletions packages/gateway/src/commands/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ export const addCommand: AddCommand = (ctx, cli) =>
const hiveCdnEndpointOpt =
// TODO: take schema from optsWithGlobals once https://github.com/commander-js/extra-typings/pull/76 is merged
this.opts().schema || hiveCdnEndpoint;
const hiveCdnLogger = ctx.log.child({ source: 'Hive CDN' });
if (hiveCdnEndpointOpt) {
if (hiveCdnKey) {
if (!isUrl(hiveCdnEndpointOpt)) {
ctx.log.error(
'Hive CDN endpoint must be a URL when providing --hive-cdn-key but got ' +
hiveCdnLogger.error(
'Endpoint must be a URL when providing --hive-cdn-key but got ' +
hiveCdnEndpointOpt,
);
process.exit(1);
Expand Down
14 changes: 9 additions & 5 deletions packages/importer/src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
export const isDebug = ['1', 'y', 'yes', 't', 'true'].includes(
String(process.env['DEBUG']),
);
export const isDebug = ['importer'].includes(String(process.env['DEBUG']));

export function debug(msg: string) {
export function debug(message: string) {
if (isDebug) {
process.stderr.write(`[${new Date().toISOString()}] HOOKS ${msg}\n`);
process.stderr.write(
`${JSON.stringify({
name: 'importer',
level: 'debug',
message,
})}\n`,
);
Comment on lines +1 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Optional enhancement for debug condition and logging consistency.

  1. The debug check is strictly ['importer'].includes(String(process.env['DEBUG'])); consider partial matching (includes('importer')) if you want simpler usage (e.g., DEBUG=importer,other).
  2. The output format is consistent with the JSON-based logging approach. Optionally, you could centralize all logging via JSONLogger for consistency across the codebase.

}
}
56 changes: 56 additions & 0 deletions packages/logger-json/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"name": "@graphql-hive/logger-json",
"version": "0.0.0",
"type": "module",
Comment on lines +1 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Missing changeset file for the new package.

According to the coding guidelines, a changeset file is required for new packages. Please create one using yarn changeset with:

  • A description of the new JSON-based logger feature
  • An example of usage
  • A "minor" semver bump since this is a new feature

Let me check if a changeset file exists:


🏁 Script executed:

#!/bin/bash
# Look for changeset files
fd -e md . .changeset/

Length of output: 1716


Missing changeset file for @graphql-hive/logger-json package
No changeset file referencing @graphql-hive/logger-json was found in the repository's .changeset directory. Please add a new changeset file (using yarn changeset) that includes a description of the JSON-based logger feature, an example of usage, and specifies a "minor" semver bump.

"repository": {
"type": "git",
"url": "git+https://github.com/graphql-hive/gateway.git",
"directory": "packages/logger-json"
},
"author": {
"email": "[email protected]",
"name": "The Guild",
"url": "https://the-guild.dev"
},
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"main": "./dist/index.js",
"exports": {
".": {
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
},
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./package.json": "./package.json"
},
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "pkgroll --clean-dist",
"prepack": "yarn build"
},
Comment on lines +37 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Add test script to package.json.

Consider adding a test script to ensure the logger functionality is properly tested:

 "scripts": {
   "build": "pkgroll --clean-dist",
-  "prepack": "yarn build"
+  "prepack": "yarn build",
+  "test": "jest"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"scripts": {
"build": "pkgroll --clean-dist",
"prepack": "yarn build"
},
"scripts": {
"build": "pkgroll --clean-dist",
"prepack": "yarn build",
"test": "jest"
},

"peerDependencies": {
"graphql": "^15.9.0 || ^16.9.0"
},
"dependencies": {
"@graphql-mesh/cross-helpers": "^0.4.10",
"@graphql-mesh/types": "^0.103.16",
"@graphql-mesh/utils": "^0.103.16",
"cross-inspect": "^1.0.1",
"tslib": "^2.8.1"
},
"devDependencies": {
"graphql": "^16.9.0",
"pkgroll": "2.8.2"
},
"sideEffects": false
}
Comment on lines +1 to +56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify Linear issue and documentation requirements.

According to the coding guidelines:

  1. Please ensure there's a Linear issue (GW-*) linked to this PR
  2. Since this introduces a new JSON logging feature, documentation should be added to the console project

Let me check for documentation PRs:


🏁 Script executed:

gh search prs --repo graphql-hive/console --json title,url --jq '.[] | select(.title | contains("logger") or contains("logging"))' 

Length of output: 389


Action Required: Address Missing Linear Issue and Documentation Update

  • It appears that the PR does not include a reference to a Linear issue (GW-*) as required.
  • Additionally, while the console project shows some recent updates related to logging, there is no explicit documentation update linking to the new JSON logging feature.

Please update the PR description and/or commit messages to include a Linear issue reference and ensure that the console documentation is updated accordingly.

Loading
Loading