Skip to content

Commit 30e41a6

Browse files
JSON based logger (#642)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 26a9c5b commit 30e41a6

File tree

31 files changed

+485
-115
lines changed

31 files changed

+485
-115
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@graphql-hive/gateway-runtime': patch
3+
---
4+
5+
dependencies updates:
6+
7+
- Added dependency [`@graphql-hive/logger-json@workspace:^` ↗︎](https://www.npmjs.com/package/@graphql-hive/logger-json/v/workspace:^) (to `dependencies`)

.changeset/big-waves-prove.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@graphql-mesh/transport-http-callback': patch
3+
'@graphql-mesh/plugin-opentelemetry': patch
4+
'@graphql-mesh/fusion-runtime': patch
5+
'@graphql-mesh/transport-ws': patch
6+
'@graphql-hive/importer': patch
7+
'@graphql-hive/gateway': patch
8+
'@graphql-hive/gateway-runtime': patch
9+
'@graphql-hive/logger-json': patch
10+
---
11+
12+
New JSON-based logger
13+
14+
By default, it prints pretty still to the console unless NODE_ENV is production.
15+
For JSON output, set the `LOG_FORMAT` environment variable to `json`.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
"vitest": "^3.0.1"
6161
},
6262
"resolutions": {
63+
"@graphql-mesh/types": "0.103.16-alpha-20250212125252-6167fff12fe4017202b35363ff2769aafe28f98a",
64+
"@graphql-mesh/utils": "0.103.16-alpha-20250212125252-6167fff12fe4017202b35363ff2769aafe28f98a",
6365
"@graphql-tools/delegate": "workspace:^",
6466
"@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",
6567
"@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",

packages/fusion-runtime/src/federation/supergraph.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,13 @@ export const handleFederationSupergraph: UnifiedGraphHandler = function ({
311311
if (context?.request) {
312312
requestId = requestIdByRequest.get(context.request);
313313
if (requestId) {
314-
currentLogger = currentLogger?.child(requestId);
314+
currentLogger = currentLogger?.child({ requestId });
315315
}
316316
}
317317
if (sourceSubschema.name) {
318-
currentLogger = currentLogger?.child(sourceSubschema.name);
318+
currentLogger = currentLogger?.child({
319+
subgraph: sourceSubschema.name,
320+
});
319321
}
320322
for (const onDelegationPlan of onDelegationPlanHooks) {
321323
const onDelegationPlanDone = onDelegationPlan({

packages/fusion-runtime/src/utils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function getTransportExecutor({
102102
let logger = transportContext?.logger;
103103
if (logger) {
104104
if (subgraphName) {
105-
logger = logger.child(subgraphName);
105+
logger = logger.child({ subgraph: subgraphName });
106106
}
107107
logger?.debug(`Loading transport "${kind}"`);
108108
}
@@ -195,10 +195,10 @@ export function getOnSubgraphExecute({
195195
executionRequest.context?.request,
196196
);
197197
if (requestId) {
198-
logger = logger.child(requestId);
198+
logger = logger.child({ requestId });
199199
}
200200
if (subgraphName) {
201-
logger = logger.child(subgraphName);
201+
logger = logger.child({ subgraph: subgraphName });
202202
}
203203
logger.debug(`Initializing executor`);
204204
}
@@ -287,7 +287,7 @@ export function wrapExecutorWithHooks({
287287
let execReqLogger = transportContext?.logger;
288288
if (execReqLogger) {
289289
if (requestId) {
290-
execReqLogger = execReqLogger.child(requestId);
290+
execReqLogger = execReqLogger.child({ requestId });
291291
}
292292
loggerForExecutionRequest.set(baseExecutionRequest, execReqLogger);
293293
}
@@ -548,11 +548,11 @@ export function wrapMergedTypeResolver<TContext extends Record<string, any>>(
548548
if (logger && context['request']) {
549549
requestId = requestIdByRequest.get(context['request']);
550550
if (requestId) {
551-
logger = logger.child(requestId);
551+
logger = logger.child({ requestId });
552552
}
553553
}
554554
if (subschema.name) {
555-
logger = logger?.child(subschema.name);
555+
logger = logger?.child({ subgraph: subschema.name });
556556
}
557557
let resolver = originalResolver as MergedTypeResolver<TContext>;
558558
function setResolver(newResolver: MergedTypeResolver<TContext>) {

packages/fusion-runtime/tests/polling.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
createDefaultExecutor,
66
type DisposableExecutor,
77
} from '@graphql-mesh/transport-common';
8-
import { DefaultLogger, makeDisposable } from '@graphql-mesh/utils';
8+
import { makeDisposable } from '@graphql-mesh/utils';
99
import { normalizedExecutor } from '@graphql-tools/executor';
1010
import {
1111
createDeferred,
@@ -17,6 +17,7 @@ import { DisposableSymbols } from '@whatwg-node/disposablestack';
1717
import { ExecutionResult, GraphQLSchema, parse } from 'graphql';
1818
import { createSchema } from 'graphql-yoga';
1919
import { describe, expect, it, vi } from 'vitest';
20+
import { getDefaultLogger } from '../../runtime/src/getDefaultLogger';
2021
import { UnifiedGraphManager } from '../src/unifiedGraphManager';
2122

2223
describe('Polling', () => {
@@ -334,7 +335,7 @@ describe('Polling', () => {
334335
const unifiedGraphFetcher = vi.fn(() => {
335336
return graphDeferred ? graphDeferred.promise : unifiedGraph;
336337
});
337-
const logger = new DefaultLogger();
338+
const logger = getDefaultLogger();
338339
await using executor = getExecutorForUnifiedGraph({
339340
getUnifiedGraph: unifiedGraphFetcher,
340341
pollingInterval: 10_000,

packages/gateway/src/bin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dotenv/config'; // inject dotenv options to process.env
33

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

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

23-
const log = new DefaultLogger();
23+
const log = getDefaultLogger();
2424

2525
run({ log }).catch((err) => {
2626
log.error(err);

packages/gateway/src/cli.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import {
77
InvalidArgumentError,
88
Option,
99
} from '@commander-js/extra-typings';
10-
import type {
11-
GatewayConfigContext,
12-
GatewayConfigProxy,
13-
GatewayConfigSubgraph,
14-
GatewayConfigSupergraph,
15-
GatewayGraphOSReportingOptions,
16-
GatewayHiveReportingOptions,
10+
import {
11+
type GatewayConfigContext,
12+
type GatewayConfigProxy,
13+
type GatewayConfigSubgraph,
14+
type GatewayConfigSupergraph,
15+
type GatewayGraphOSReportingOptions,
16+
type GatewayHiveReportingOptions,
1717
} from '@graphql-hive/gateway-runtime';
1818
import type UpstashRedisCache from '@graphql-mesh/cache-upstash-redis';
1919
import type { JWTAuthPluginOptions } from '@graphql-mesh/plugin-jwt-auth';
@@ -26,8 +26,8 @@ import type {
2626
MeshPubSub,
2727
YamlConfig,
2828
} from '@graphql-mesh/types';
29-
import { DefaultLogger } from '@graphql-mesh/utils';
3029
import parseDuration from 'parse-duration';
30+
import { getDefaultLogger } from '../../runtime/src/getDefaultLogger';
3131
import { addCommands } from './commands/index';
3232
import { createDefaultConfigPaths } from './config';
3333
import { getMaxConcurrency } from './getMaxConcurrency';
@@ -347,7 +347,7 @@ let cli = new Command()
347347

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

364364
if (cluster.worker?.id) {
365-
ctx.log = ctx.log.child(`Worker #${cluster.worker.id}`);
365+
ctx.log = ctx.log.child({ worker: cluster.worker.id });
366366
}
367367

368368
addCommands(ctx, cli);

packages/gateway/src/commands/handleFork.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,34 @@ export function handleFork(log: Logger, config: { fork?: number }): boolean {
1010
log.debug(`Forking ${config.fork} workers`);
1111
for (let i = 0; i < config.fork; i++) {
1212
const worker = cluster.fork();
13+
const workerLogger = log.child({ worker: worker.id });
1314
worker.once('exit', (code, signal) => {
15+
const logData: Record<string, string | number> = {
16+
signal,
17+
};
18+
if (code != null) {
19+
logData['code'] = code;
20+
}
1421
if (expectedToExit) {
15-
log.debug(
16-
`Worker ${worker.process.pid} exited with code ${code} and signal ${signal}`,
17-
);
22+
workerLogger.debug('exited', logData);
1823
} else {
19-
log.warn(`Worker ${worker.process.pid} exited unexpectedly with code ${code} and signal ${signal}\n
20-
A restart is recommended to ensure the stability of the service`);
24+
workerLogger.error(
25+
'exited unexpectedly. A restart is recommended to ensure the stability of the service',
26+
logData,
27+
);
2128
}
2229
workers.delete(worker);
2330
if (!expectedToExit && workers.size === 0) {
24-
log.error(`All workers exited unexpectedly. Exiting`);
31+
log.error(`All workers exited unexpectedly. Exiting`, logData);
2532
process.exit(1);
2633
}
2734
});
2835
workers.add(worker);
2936
}
3037
registerTerminateHandler((signal) => {
31-
log.info(`Killing workers with ${signal}`);
38+
log.info('Killing workers', {
39+
signal,
40+
});
3241
expectedToExit = true;
3342
workers.forEach((w) => {
3443
w.kill(signal);
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Logger } from '@graphql-mesh/types';
2-
import { CLIContext, DefaultLogger, LogLevel } from '..';
2+
import { CLIContext, LogLevel } from '..';
3+
import { getDefaultLogger } from '../../../runtime/src/getDefaultLogger';
34

45
export function handleLoggingConfig(
56
loggingConfig: boolean | Logger | LogLevel | undefined,
@@ -9,17 +10,23 @@ export function handleLoggingConfig(
910
ctx.log = loggingConfig;
1011
} else if (typeof loggingConfig === 'boolean') {
1112
if (!loggingConfig) {
12-
if (ctx.log instanceof DefaultLogger) {
13+
if ('logLevel' in ctx.log) {
1314
ctx.log.logLevel = LogLevel.silent;
1415
} else {
15-
ctx.log = new DefaultLogger(ctx.log.name, LogLevel.silent);
16+
ctx.log = getDefaultLogger({
17+
name: ctx.log.name,
18+
level: LogLevel.silent,
19+
});
1620
}
1721
}
1822
} else if (typeof loggingConfig === 'number') {
19-
if (ctx.log instanceof DefaultLogger) {
23+
if ('logLevel' in ctx.log) {
2024
ctx.log.logLevel = loggingConfig;
2125
} else {
22-
ctx.log = new DefaultLogger(ctx.log.name, loggingConfig);
26+
ctx.log = getDefaultLogger({
27+
name: ctx.log.name,
28+
level: loggingConfig,
29+
});
2330
}
2431
}
2532
}

0 commit comments

Comments
 (0)