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
73 changes: 73 additions & 0 deletions .changeset/big-pigs-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
'@graphql-hive/core': minor
'@graphql-hive/apollo': minor
'@graphql-hive/envelop': minor
'@graphql-hive/yoga': minor
---

Add support for providing a logger object via `HivePluginOptions`.

It is possible to provide the following options:

- **'trace'**
- **'debug'**
- **'info'** default
- **'warn'**
- **'error'**

```ts
import { createHive } from '@graphql-hive/core'

const client = createHive({
logger: 'info'
})
```

In addition to that, it is also possible to provide a Hive Logger instance, that allows more control over how you want to log and forward logs.

```ts
import { createHive } from '@graphql-hive/core'
import { Logger } from '@graphql-hive/logger'

const client = createHive({
logger: new Logger()
})
```

Head to our [Hive Logger documentation](https://the-guild.dev/graphql/hive/docs/logger) to learn more.

___

**The `HivePluginOptions.debug` option is now deprecated.** Instead, please provide the option `debug`
instead for the logger.

```diff
import { createHive } from '@graphql-hive/core'

const client = createHive({
- debug: process.env.DEBUG === "1",
+ logger: process.env.DEBUG === "1" ? "debug" : "info",
})
```

**Note**: If the `logger` property is provided, the `debug` option is ignored.

___

**The `HivePluginOptions.agent.logger` option is now deprecated.** Instead, please provide
`HivePluginOptions.logger`.

```diff
import { createHive } from '@graphql-hive/core'

const logger = new Logger()

const client = createHive({
agent: {
- logger,
},
+ logger,
})
```

**Note**: If both options are provided, the `agent` option is ignored.
13 changes: 5 additions & 8 deletions packages/libraries/apollo/tests/apollo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { startStandaloneServer } from '@apollo/server/standalone';
import { expressMiddleware } from '@as-integrations/express4';
import { http } from '@graphql-hive/core';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { createHiveTestingLogger } from '../../core/tests/test-utils';
import { createHive, useHive } from '../src';

function createLogger() {
Expand Down Expand Up @@ -60,11 +61,9 @@ function handleProcess() {
};
}

test('should not interrupt the process', async () => {
const logger = {
error: vi.fn(),
info: vi.fn(),
};
test('should not interrupt the process', async ({ expect }) => {
const logger = createHiveTestingLogger();

const clean = handleProcess();
const apollo = new ApolloServer({
typeDefs,
Expand Down Expand Up @@ -102,9 +101,7 @@ test('should not interrupt the process', async () => {
await waitFor(200);
await apollo.stop();
clean();
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][info]'));
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][usage]'));
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][reporting]'));
expect(logger.getLogs()).toContain(`[DBG] Disposing`);
}, 1_000);

test('should capture client name and version headers', async () => {
Expand Down
23 changes: 12 additions & 11 deletions packages/libraries/cli/src/commands/artifact/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,19 @@ export default class ArtifactsFetch extends Command<typeof ArtifactsFetch> {
retry: {
retries: 3,
},
logger: {
info: (...args) => {
if (this.flags.debug) {
console.info(...args);
logger: this.flags.debug
? {
info: (...args: Array<unknown>) => {
this.logInfo(...args);
},
error: (...args: Array<unknown>) => {
this.logFailure(...args);
},
debug: (...args: Array<unknown>) => {
this.logInfo(...args);
},
}
},
error: (...args) => {
if (this.flags.debug) {
console.error(...args);
}
},
},
: undefined,
});
} catch (e: any) {
const sourceError = e?.cause ?? e;
Expand Down
1 change: 1 addition & 0 deletions packages/libraries/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"graphql": "^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
},
"dependencies": {
"@graphql-hive/logger": "^1.0.9",
"@graphql-hive/signal": "^2.0.0",
"@graphql-tools/utils": "^10.0.0",
"@whatwg-node/fetch": "^0.10.13",
Expand Down
25 changes: 13 additions & 12 deletions packages/libraries/core/src/client/agent.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import CircuitBreaker from '../circuit-breaker/circuit.js';
import { version } from '../version.js';
import { http } from './http-client.js';
import type { Logger } from './types.js';
import { createHiveLogger } from './utils.js';
import type { LegacyLogger } from './types.js';
import { chooseLogger } from './utils.js';

type ReadOnlyResponse = Pick<Response, 'status' | 'text' | 'json' | 'statusText'>;

Expand Down Expand Up @@ -67,9 +67,13 @@ 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;
logger?: LegacyLogger;
/**
* Circuit Breaker Configuration.
* true -> Use default configuration
Expand Down Expand Up @@ -119,13 +123,12 @@ export function createAgent<TEvent>(
? null
: pluginOptions.circuitBreaker,
};
const logger = createHiveLogger(pluginOptions.logger ?? console, '[agent]', pluginOptions.debug);
const logger = chooseLogger(pluginOptions.logger).child({ module: 'hive-agent' });

let circuitBreaker: CircuitBreakerInterface<
Parameters<typeof sendHTTPCall>,
ReturnType<typeof sendHTTPCall>
>;
const breakerLogger = createHiveLogger(logger, '[circuit breaker]');

const enabled = options.enabled !== false;
let timeoutID: ReturnType<typeof setTimeout> | null = null;
Expand Down Expand Up @@ -266,14 +269,12 @@ export function createAgent<TEvent>(
circuitBreaker = circuitBreakerInstance;

circuitBreakerInstance.on('open', () =>
breakerLogger.error('circuit opened - backend seems unreachable.'),
logger.error('circuit opened - backend seems unreachable.'),
);
circuitBreakerInstance.on('halfOpen', () =>
breakerLogger.info('circuit half open - testing backend connectivity'),
);
circuitBreakerInstance.on('close', () =>
breakerLogger.info('circuit closed - backend recovered '),
logger.info('circuit half open - testing backend connectivity'),
);
circuitBreakerInstance.on('close', () => logger.info('circuit closed - backend recovered '));
} else {
circuitBreaker = {
getSignal() {
Expand All @@ -289,7 +290,7 @@ export function createAgent<TEvent>(
return await circuitBreaker.fire(...args);
} catch (err: unknown) {
if (err instanceof Error && 'code' in err && err.code === 'EOPENBREAKER') {
breakerLogger.info('circuit open - sending report skipped');
logger.info('circuit open - sending report skipped');
return null;
}

Expand Down
47 changes: 26 additions & 21 deletions packages/libraries/core/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@ import {
type GraphQLSchema,
type subscribe as SubscribeImplementation,
} from 'graphql';
import { Logger } from '@graphql-hive/logger';
import { version } from '../version.js';
import { http } from './http-client.js';
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 { chooseLogger, isLegacyAccessToken } from './utils.js';

function resolveLoggerFromConfigOptions(options: HivePluginOptions): Logger {
if (typeof options.logger == 'string') {
return new Logger({
level: options.logger,
});
}

if (options.logger instanceof Logger) {
return options.logger;
}

return chooseLogger(options.logger ?? options.agent?.logger, options.debug);
}

export function createHive(options: HivePluginOptions): HiveClient {
const logger = createHiveLogger(
options?.agent?.logger ?? console,
'[hive]',
options.debug ?? false,
);
const logger = resolveLoggerFromConfigOptions(options).child({ module: 'hive' });
let enabled = options.enabled ?? true;

if (enabled === false && !options.experimental__persistedDocuments) {
Expand Down Expand Up @@ -64,8 +75,6 @@ export function createHive(options: HivePluginOptions): HiveClient {
? options.printTokenInfo === true || (!!options.debug && options.printTokenInfo !== false)
: false;

const infoLogger = createHiveLogger(logger, '[info]');

const info = printTokenInfo
? async () => {
try {
Expand Down Expand Up @@ -109,7 +118,7 @@ export function createHive(options: HivePluginOptions): HiveClient {
}
`;

infoLogger.info('Fetching token details...');
logger.info('Fetching token details...');

const clientVersionForDetails = options.agent?.version || version;
const response = await http.post(
Expand All @@ -128,7 +137,7 @@ export function createHive(options: HivePluginOptions): HiveClient {
},
timeout: 30_000,
fetchImplementation: options?.agent?.fetch,
logger: infoLogger,
logger,
},
);

Expand Down Expand Up @@ -160,7 +169,7 @@ export function createHive(options: HivePluginOptions): HiveClient {
const projectUrl = `${organizationUrl}/${project.slug}`;
const targetUrl = `${projectUrl}/${target.slug}`;

infoLogger.info(
logger.info(
[
'Token details',
'',
Expand All @@ -176,21 +185,17 @@ export function createHive(options: HivePluginOptions): HiveClient {
].join('\n'),
);
} else if (result.data?.tokenInfo.message) {
infoLogger.error(`Token not found. Reason: ${result.data?.tokenInfo.message}`);
infoLogger.info(
`How to create a token? https://docs.graphql-hive.com/features/tokens`,
);
logger.error(`Token not found. Reason: ${result.data?.tokenInfo.message}`);
logger.info(`How to create a token? https://docs.graphql-hive.com/features/tokens`);
} else {
infoLogger.error(`${result.errors![0].message}`);
infoLogger.info(
`How to create a token? https://docs.graphql-hive.com/features/tokens`,
);
logger.error(`${result.errors![0].message}`);
logger.info(`How to create a token? https://docs.graphql-hive.com/features/tokens`);
}
} else {
infoLogger.error(`Error ${response.status}: ${response.statusText}`);
logger.error(`Error ${response.status}: ${response.statusText}`);
}
} catch (error) {
infoLogger.error(`Error ${(error as Error)?.message ?? error}`);
logger.error(`Error ${(error as Error)?.message ?? error}`);
}
}
: () => {};
Expand Down
4 changes: 2 additions & 2 deletions packages/libraries/core/src/client/gateways.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { version } from '../version.js';
import { http } from './http-client.js';
import type { SchemaFetcherOptions, ServicesFetcherOptions } from './types.js';
import { createHash, createHiveLogger, joinUrl } from './utils.js';
import { chooseLogger, createHash, joinUrl } from './utils.js';

interface Schema {
sdl: string;
Expand All @@ -10,7 +10,7 @@ interface Schema {
}

function createFetcher(options: SchemaFetcherOptions & ServicesFetcherOptions) {
const logger = createHiveLogger(options.logger ?? console, '');
const logger = chooseLogger(options.logger ?? console);
let cacheETag: string | null = null;
let cached: {
id: string;
Expand Down
Loading
Loading