Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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`)
14 changes: 14 additions & 0 deletions .changeset/big-waves-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@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
---

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
17 changes: 12 additions & 5 deletions packages/gateway/src/commands/handleFork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ 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) => {
if (expectedToExit) {
log.debug(
`Worker ${worker.process.pid} exited with code ${code} and signal ${signal}`,
);
workerLogger.debug('exited', {
code,
signal,
});
} 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',
{
code,
signal,
},
);
}
workers.delete(worker);
if (!expectedToExit && workers.size === 0) {
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.

}
}
55 changes: 55 additions & 0 deletions packages/logger-json/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"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.9",
"@graphql-mesh/types": "^0.103.6",
"@graphql-mesh/utils": "^0.103.6",
"tslib": "^2.8.1"
},
"devDependencies": {
"graphql": "^16.9.0",
"pkgroll": "2.8.2"
},
"sideEffects": false
}
Loading
Loading