Skip to content

Commit

Permalink
Improve Logging Experience (#3860)
Browse files Browse the repository at this point in the history
* Improve Logging Experience

* Remove resolutions
  • Loading branch information
ardatan committed Apr 22, 2022
1 parent 331b626 commit f963b57
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 41 deletions.
9 changes: 9 additions & 0 deletions .changeset/many-cows-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@graphql-mesh/cli': minor
'@graphql-mesh/config': minor
'@graphql-mesh/runtime': minor
'@graphql-mesh/types': minor
'@graphql-mesh/utils': minor
---

Improve Logging Experience
10 changes: 9 additions & 1 deletion packages/cli/src/commands/serve/graphql-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MeshInstance } from '@graphql-mesh/runtime';
import { RequestHandler } from 'express';
import { createServer, useExtendContext } from '@graphql-yoga/node';
import { createServer, useExtendContext, useLogger } from '@graphql-yoga/node';

export const graphqlHandler = (
mesh$: Promise<MeshInstance>,
Expand All @@ -19,6 +19,14 @@ export const graphqlHandler = (
cookies: req.cookies,
res,
})),
useLogger({
skipIntrospection: true,
logFn: (eventName, { args }) => {
if (eventName.endsWith('-start')) {
mesh.logger.debug(() => [`\t headers: `, args.contextValue.headers]);
}
},
}),
],
logging: mesh.logger,
maskedErrors: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/serve/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export async function serveMesh(
});
logger.info(`${cliParams.serveMessage}: ${serverUrl}`);
registerTerminateHandler(eventName => {
const eventLogger = logger.child(`${eventName}💀`);
const eventLogger = logger.child(`${eventName} 💀`);
eventLogger.info(`Destroying the server`);
mesh.destroy();
});
Expand Down Expand Up @@ -275,7 +275,7 @@ export async function serveMesh(
httpServer,
app,
readyFlag,
logger: logger,
logger,
}));
}
return null;
Expand Down
13 changes: 9 additions & 4 deletions packages/cli/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { ConfigProcessOptions, processConfig } from '@graphql-mesh/config';
import { jsonSchema, YamlConfig } from '@graphql-mesh/types';
import { defaultImportFn, loadYaml } from '@graphql-mesh/utils';
import { defaultImportFn, loadYaml, DefaultLogger } from '@graphql-mesh/utils';
import Ajv from 'ajv';
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
import { path } from '@graphql-mesh/cross-helpers';

export function validateConfig(config: any): asserts config is YamlConfig.Config {
export function validateConfig(config: any, filepath: string): asserts config is YamlConfig.Config {
const ajv = new Ajv({
strict: false,
} as any);
jsonSchema.$schema = undefined;
const isValid = ajv.validate(jsonSchema, config);
if (!isValid) {
console.warn(`Configuration is not valid:\n${ajv.errorsText()}`);
const logger = new DefaultLogger('🕸️ Mesh - Config');
logger.warn(
`${filepath} configuration file is not valid:\n${ajv.errorsText(ajv.errors, {
separator: '\n',
})}\nThis is just a warning! It doesn't have any effects on runtime.`
);
}
}

Expand Down Expand Up @@ -48,7 +53,7 @@ export async function findAndParseConfig(options?: ConfigProcessOptions) {
}

const config = results.config;
validateConfig(config);
validateConfig(config, results.filepath);
return processConfig(config, { dir, ...restOptions });
}

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/handleFatalError.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Logger } from '@graphql-mesh/types';
import { DefaultLogger } from '@graphql-mesh/utils';

export function handleFatalError(e: Error, logger: Logger = new DefaultLogger('🕸️')): any {
export function handleFatalError(e: Error, logger: Logger = new DefaultLogger('🕸️ Mesh')): any {
logger.error(e.stack || e.message);
if (process.env.JEST == null) {
process.exit(1);
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { handleFatalError } from './handleFatalError';
import { cwd, env } from 'process';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { YamlConfig } from '@graphql-mesh/types';
import { Logger, YamlConfig } from '@graphql-mesh/types';
import { register as tsNodeRegister } from 'ts-node';
import { register as tsConfigPathsRegister } from 'tsconfig-paths';
import { config as dotEnvRegister } from 'dotenv';
Expand Down Expand Up @@ -45,7 +45,7 @@ export interface GraphQLMeshCLIParams {

export const DEFAULT_CLI_PARAMS: GraphQLMeshCLIParams = {
commandName: 'mesh',
initialLoggerPrefix: '🕸️',
initialLoggerPrefix: '🕸️ Mesh',
configName: 'mesh',
artifactsDir: '.mesh',
serveMessage: 'Serving GraphQL Mesh',
Expand All @@ -62,7 +62,7 @@ export const DEFAULT_CLI_PARAMS: GraphQLMeshCLIParams = {

export async function graphqlMesh(cliParams = DEFAULT_CLI_PARAMS, args = hideBin(process.argv), cwdPath = cwd()) {
let baseDir = cwdPath;
let logger = new DefaultLogger(cliParams.initialLoggerPrefix);
let logger: Logger = new DefaultLogger(cliParams.initialLoggerPrefix);
return yargs(args)
.help()
.option('r', {
Expand Down
4 changes: 2 additions & 2 deletions packages/config/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ export async function resolveLogger(
code: '',
};
}
const logger = new DefaultLogger('🕸️');
const logger = new DefaultLogger('🕸️ Mesh');
return {
logger,
importCode: `import { DefaultLogger } from '@graphql-mesh/utils';`,
code: `const logger = new DefaultLogger('🕸️');`,
code: `const logger = new DefaultLogger('🕸️ Mesh');`,
};
}
7 changes: 2 additions & 5 deletions packages/runtime/src/get-mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
memoize1,
parseSelectionSet,
} from '@graphql-tools/utils';
import { enableIf, envelop, useErrorHandler, useExtendContext, useLogger, useSchema } from '@envelop/core';
import { enableIf, envelop, useErrorHandler, useExtendContext, useSchema } from '@envelop/core';
import { useLiveQuery } from '@envelop/live-query';
import { CompiledQuery, compileQuery, isCompiledQuery } from 'graphql-jit';

Expand Down Expand Up @@ -84,7 +84,7 @@ const memoizedGetEnvelopedFactory = memoize1((plugins: EnvelopPlugins) => envelo

export async function getMesh<TMeshContext = any>(options: GetMeshOptions): Promise<MeshInstance<TMeshContext>> {
const rawSources: RawSourceOutput[] = [];
const { pubsub, cache, logger = new DefaultLogger('🕸️'), additionalEnvelopPlugins = [] } = options;
const { pubsub, cache, logger = new DefaultLogger('🕸️ Mesh'), additionalEnvelopPlugins = [] } = options;

const getMeshLogger = logger.child('GetMesh');
getMeshLogger.debug(() => `Getting subschemas from source handlers`);
Expand Down Expand Up @@ -366,9 +366,6 @@ See more at https://www.graphql-mesh.com/docs/recipes/live-queries`);
});
return useLiveQuery({ liveQueryStore });
}),
useLogger({
logFn: (eventName, args) => logger.child(eventName).debug(() => inspect(args)),
}),
useErrorHandler(errors => {
errors.forEach(error => logger.error(error.stack || error.message));
}),
Expand Down
12 changes: 6 additions & 6 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,15 @@ export type GraphQLOperation<TData, TVariables> = TypedDocumentNode<TData, TVari

export type ImportFn = <T = any>(moduleId: string) => Promise<T>;

export type LazyLoggerMessage = (() => string) | string;
export type LazyLoggerMessage = (() => any | any[]) | any;

export type Logger = {
name?: string;
log: (message: string) => void;
warn: (message: string) => void;
info: (message: string) => void;
error: (message: string) => void;
debug: (message: LazyLoggerMessage) => void;
log: (...args: any[]) => void;
warn: (...args: any[]) => void;
info: (...args: any[]) => void;
error: (...args: any[]) => void;
debug: (...lazyArgs: LazyLoggerMessage[]) => void;
child: (name: string) => Logger;
};

Expand Down
73 changes: 56 additions & 17 deletions packages/utils/src/logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LazyLoggerMessage, Logger } from '@graphql-mesh/types';
import { inspect } from '@graphql-tools/utils';
import chalk from 'chalk';

type MessageTransformer = (msg: string) => string;
Expand All @@ -9,36 +10,74 @@ const errorColor: MessageTransformer = chalk.red;
const debugColor: MessageTransformer = chalk.magenta;
const titleBold: MessageTransformer = chalk.bold;

function handleLazyMessage(lazyMessage: LazyLoggerMessage) {
if (typeof lazyMessage === 'function') {
return lazyMessage();
}
return lazyMessage;
function handleLazyMessage(...lazyArgs: LazyLoggerMessage[]) {
const flattenedArgs = lazyArgs.flat(Infinity).flatMap(arg => {
if (typeof arg === 'function') {
return arg();
}
return arg;
});
return getLoggerMessage(flattenedArgs);
}

function getLoggerMessage(...args: any[]) {
return args
.flat(Infinity)
.map(arg => (typeof arg === 'string' ? arg : inspect(arg)))
.join(` `);
}

export class DefaultLogger implements Logger {
constructor(public name?: string) {}
log(message: string) {
const finalMessage = this.name ? `${titleBold(this.name)}: ${message}` : message;
return console.log(finalMessage);

private getPrefix() {
return this.name ? titleBold(this.name) : ``;
}

warn(message: string) {
return this.log(warnColor(message));
log(...args: any[]) {
const message = getLoggerMessage(...args);
return console.log(`${this.getPrefix()} ${message}`);
}

info(message: string) {
return this.log(infoColor(message));
warn(...args: any[]) {
const message = getLoggerMessage(...args);
const fullMessage = `⚠️ ${this.getPrefix()} ${warnColor(message)}`;
if (console.warn) {
console.warn(fullMessage);
} else {
console.log(fullMessage);
}
}

error(message: string) {
return this.log(errorColor(message));
info(...args: any[]) {
const message = getLoggerMessage(...args);
const fullMessage = `💡 ${this.getPrefix()} ${infoColor(message)}`;
if (console.info) {
console.info(fullMessage);
} else {
console.log(fullMessage);
}
}

error(...args: any[]) {
const message = getLoggerMessage(...args);
const fullMessage = `💥 ${this.getPrefix()} ${errorColor(message)}`;
if (console.error) {
console.error(fullMessage);
} else {
console.log(fullMessage);
}
}

debug(lazyMessage: LazyLoggerMessage) {
debug(...lazyArgs: LazyLoggerMessage[]) {
if ((process.env.DEBUG && process.env.DEBUG === '1') || this.name.includes(process.env.DEBUG)) {
const message = handleLazyMessage(lazyMessage);
return this.log(debugColor(message));
const message = handleLazyMessage(lazyArgs);
const fullMessage = `🐛 ${this.getPrefix()} ${debugColor(message)}`;
if (console.debug) {
console.debug(fullMessage);
} else {
console.log(fullMessage);
}
}
}

Expand Down

1 comment on commit f963b57

@vercel
Copy link

@vercel vercel bot commented on f963b57 Apr 22, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.