Skip to content

Commit 5229612

Browse files
n1ru4lenisdenjo
andauthored
feat: move logger property to top level instead of having it in agent object; use hive-logger (#7290)
Co-authored-by: Denis Badurina <badurinadenis@gmail.com>
1 parent f48065a commit 5229612

File tree

25 files changed

+728
-288
lines changed

25 files changed

+728
-288
lines changed

.changeset/big-pigs-help.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
'@graphql-hive/core': minor
3+
'@graphql-hive/apollo': minor
4+
'@graphql-hive/envelop': minor
5+
'@graphql-hive/yoga': minor
6+
---
7+
8+
Add support for providing a logger object via `HivePluginOptions`.
9+
10+
It is possible to provide the following options:
11+
12+
- **'trace'**
13+
- **'debug'**
14+
- **'info'** default
15+
- **'warn'**
16+
- **'error'**
17+
18+
```ts
19+
import { createHive } from '@graphql-hive/core'
20+
21+
const client = createHive({
22+
logger: 'info'
23+
})
24+
```
25+
26+
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.
27+
28+
```ts
29+
import { createHive } from '@graphql-hive/core'
30+
import { Logger } from '@graphql-hive/logger'
31+
32+
const client = createHive({
33+
logger: new Logger()
34+
})
35+
```
36+
37+
Head to our [Hive Logger documentation](https://the-guild.dev/graphql/hive/docs/logger) to learn more.
38+
39+
___
40+
41+
**The `HivePluginOptions.debug` option is now deprecated.** Instead, please provide the option `debug`
42+
instead for the logger.
43+
44+
```diff
45+
import { createHive } from '@graphql-hive/core'
46+
47+
const client = createHive({
48+
- debug: process.env.DEBUG === "1",
49+
+ logger: process.env.DEBUG === "1" ? "debug" : "info",
50+
})
51+
```
52+
53+
**Note**: If the `logger` property is provided, the `debug` option is ignored.
54+
55+
___
56+
57+
**The `HivePluginOptions.agent.logger` option is now deprecated.** Instead, please provide
58+
`HivePluginOptions.logger`.
59+
60+
```diff
61+
import { createHive } from '@graphql-hive/core'
62+
63+
const logger = new Logger()
64+
65+
const client = createHive({
66+
agent: {
67+
- logger,
68+
},
69+
+ logger,
70+
})
71+
```
72+
73+
**Note**: If both options are provided, the `agent` option is ignored.

packages/libraries/apollo/tests/apollo.spec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { startStandaloneServer } from '@apollo/server/standalone';
1313
import { expressMiddleware } from '@as-integrations/express4';
1414
import { http } from '@graphql-hive/core';
1515
import { makeExecutableSchema } from '@graphql-tools/schema';
16+
import { createHiveTestingLogger } from '../../core/tests/test-utils';
1617
import { createHive, useHive } from '../src';
1718

1819
function createLogger() {
@@ -60,11 +61,9 @@ function handleProcess() {
6061
};
6162
}
6263

63-
test('should not interrupt the process', async () => {
64-
const logger = {
65-
error: vi.fn(),
66-
info: vi.fn(),
67-
};
64+
test('should not interrupt the process', async ({ expect }) => {
65+
const logger = createHiveTestingLogger();
66+
6867
const clean = handleProcess();
6968
const apollo = new ApolloServer({
7069
typeDefs,
@@ -102,9 +101,7 @@ test('should not interrupt the process', async () => {
102101
await waitFor(200);
103102
await apollo.stop();
104103
clean();
105-
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][info]'));
106-
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][usage]'));
107-
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('[hive][reporting]'));
104+
expect(logger.getLogs()).toContain(`[DBG] Disposing`);
108105
}, 1_000);
109106

110107
test('should capture client name and version headers', async () => {

packages/libraries/cli/src/commands/artifact/fetch.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,19 @@ export default class ArtifactsFetch extends Command<typeof ArtifactsFetch> {
6969
retry: {
7070
retries: 3,
7171
},
72-
logger: {
73-
info: (...args) => {
74-
if (this.flags.debug) {
75-
console.info(...args);
72+
logger: this.flags.debug
73+
? {
74+
info: (...args: Array<unknown>) => {
75+
this.logInfo(...args);
76+
},
77+
error: (...args: Array<unknown>) => {
78+
this.logFailure(...args);
79+
},
80+
debug: (...args: Array<unknown>) => {
81+
this.logInfo(...args);
82+
},
7683
}
77-
},
78-
error: (...args) => {
79-
if (this.flags.debug) {
80-
console.error(...args);
81-
}
82-
},
83-
},
84+
: undefined,
8485
});
8586
} catch (e: any) {
8687
const sourceError = e?.cause ?? e;

packages/libraries/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"graphql": "^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
4747
},
4848
"dependencies": {
49+
"@graphql-hive/logger": "^1.0.9",
4950
"@graphql-hive/signal": "^2.0.0",
5051
"@graphql-tools/utils": "^10.0.0",
5152
"@whatwg-node/fetch": "^0.10.13",

packages/libraries/core/src/client/agent.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import CircuitBreaker from '../circuit-breaker/circuit.js';
22
import { version } from '../version.js';
33
import { http } from './http-client.js';
4-
import type { Logger } from './types.js';
5-
import { createHiveLogger } from './utils.js';
4+
import type { LegacyLogger } from './types.js';
5+
import { chooseLogger } from './utils.js';
66

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

@@ -67,9 +67,13 @@ export interface AgentOptions {
6767
*/
6868
maxSize?: number;
6969
/**
70-
* Custom logger (defaults to console)
70+
* Custom logger.
71+
*
72+
* Default: console based logger
73+
*
74+
* @deprecated Instead, provide a logger for the root Hive SDK. If a logger is provided on the root Hive SDK, this one is ignored.
7175
*/
72-
logger?: Logger;
76+
logger?: LegacyLogger;
7377
/**
7478
* Circuit Breaker Configuration.
7579
* true -> Use default configuration
@@ -119,13 +123,12 @@ export function createAgent<TEvent>(
119123
? null
120124
: pluginOptions.circuitBreaker,
121125
};
122-
const logger = createHiveLogger(pluginOptions.logger ?? console, '[agent]', pluginOptions.debug);
126+
const logger = chooseLogger(pluginOptions.logger).child({ module: 'hive-agent' });
123127

124128
let circuitBreaker: CircuitBreakerInterface<
125129
Parameters<typeof sendHTTPCall>,
126130
ReturnType<typeof sendHTTPCall>
127131
>;
128-
const breakerLogger = createHiveLogger(logger, '[circuit breaker]');
129132

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

268271
circuitBreakerInstance.on('open', () =>
269-
breakerLogger.error('circuit opened - backend seems unreachable.'),
272+
logger.error('circuit opened - backend seems unreachable.'),
270273
);
271274
circuitBreakerInstance.on('halfOpen', () =>
272-
breakerLogger.info('circuit half open - testing backend connectivity'),
273-
);
274-
circuitBreakerInstance.on('close', () =>
275-
breakerLogger.info('circuit closed - backend recovered '),
275+
logger.info('circuit half open - testing backend connectivity'),
276276
);
277+
circuitBreakerInstance.on('close', () => logger.info('circuit closed - backend recovered '));
277278
} else {
278279
circuitBreaker = {
279280
getSignal() {
@@ -289,7 +290,7 @@ export function createAgent<TEvent>(
289290
return await circuitBreaker.fire(...args);
290291
} catch (err: unknown) {
291292
if (err instanceof Error && 'code' in err && err.code === 'EOPENBREAKER') {
292-
breakerLogger.info('circuit open - sending report skipped');
293+
logger.info('circuit open - sending report skipped');
293294
return null;
294295
}
295296

packages/libraries/core/src/client/client.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@ import {
44
type GraphQLSchema,
55
type subscribe as SubscribeImplementation,
66
} from 'graphql';
7+
import { Logger } from '@graphql-hive/logger';
78
import { version } from '../version.js';
89
import { http } from './http-client.js';
910
import { createPersistedDocuments } from './persisted-documents.js';
1011
import { createReporting } from './reporting.js';
1112
import type { HiveClient, HiveInternalPluginOptions, HivePluginOptions } from './types.js';
1213
import { createUsage } from './usage.js';
13-
import { createHiveLogger, isLegacyAccessToken } from './utils.js';
14+
import { chooseLogger, isLegacyAccessToken } from './utils.js';
15+
16+
function resolveLoggerFromConfigOptions(options: HivePluginOptions): Logger {
17+
if (typeof options.logger == 'string') {
18+
return new Logger({
19+
level: options.logger,
20+
});
21+
}
22+
23+
if (options.logger instanceof Logger) {
24+
return options.logger;
25+
}
26+
27+
return chooseLogger(options.logger ?? options.agent?.logger, options.debug);
28+
}
1429

1530
export function createHive(options: HivePluginOptions): HiveClient {
16-
const logger = createHiveLogger(
17-
options?.agent?.logger ?? console,
18-
'[hive]',
19-
options.debug ?? false,
20-
);
31+
const logger = resolveLoggerFromConfigOptions(options).child({ module: 'hive' });
2132
let enabled = options.enabled ?? true;
2233

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

67-
const infoLogger = createHiveLogger(logger, '[info]');
68-
6978
const info = printTokenInfo
7079
? async () => {
7180
try {
@@ -109,7 +118,7 @@ export function createHive(options: HivePluginOptions): HiveClient {
109118
}
110119
`;
111120

112-
infoLogger.info('Fetching token details...');
121+
logger.info('Fetching token details...');
113122

114123
const clientVersionForDetails = options.agent?.version || version;
115124
const response = await http.post(
@@ -128,7 +137,7 @@ export function createHive(options: HivePluginOptions): HiveClient {
128137
},
129138
timeout: 30_000,
130139
fetchImplementation: options?.agent?.fetch,
131-
logger: infoLogger,
140+
logger,
132141
},
133142
);
134143

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

163-
infoLogger.info(
172+
logger.info(
164173
[
165174
'Token details',
166175
'',
@@ -176,21 +185,17 @@ export function createHive(options: HivePluginOptions): HiveClient {
176185
].join('\n'),
177186
);
178187
} else if (result.data?.tokenInfo.message) {
179-
infoLogger.error(`Token not found. Reason: ${result.data?.tokenInfo.message}`);
180-
infoLogger.info(
181-
`How to create a token? https://docs.graphql-hive.com/features/tokens`,
182-
);
188+
logger.error(`Token not found. Reason: ${result.data?.tokenInfo.message}`);
189+
logger.info(`How to create a token? https://docs.graphql-hive.com/features/tokens`);
183190
} else {
184-
infoLogger.error(`${result.errors![0].message}`);
185-
infoLogger.info(
186-
`How to create a token? https://docs.graphql-hive.com/features/tokens`,
187-
);
191+
logger.error(`${result.errors![0].message}`);
192+
logger.info(`How to create a token? https://docs.graphql-hive.com/features/tokens`);
188193
}
189194
} else {
190-
infoLogger.error(`Error ${response.status}: ${response.statusText}`);
195+
logger.error(`Error ${response.status}: ${response.statusText}`);
191196
}
192197
} catch (error) {
193-
infoLogger.error(`Error ${(error as Error)?.message ?? error}`);
198+
logger.error(`Error ${(error as Error)?.message ?? error}`);
194199
}
195200
}
196201
: () => {};

packages/libraries/core/src/client/gateways.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { version } from '../version.js';
22
import { http } from './http-client.js';
33
import type { SchemaFetcherOptions, ServicesFetcherOptions } from './types.js';
4-
import { createHash, createHiveLogger, joinUrl } from './utils.js';
4+
import { chooseLogger, createHash, joinUrl } from './utils.js';
55

66
interface Schema {
77
sdl: string;
@@ -10,7 +10,7 @@ interface Schema {
1010
}
1111

1212
function createFetcher(options: SchemaFetcherOptions & ServicesFetcherOptions) {
13-
const logger = createHiveLogger(options.logger ?? console, '');
13+
const logger = chooseLogger(options.logger ?? console);
1414
let cacheETag: string | null = null;
1515
let cached: {
1616
id: string;

0 commit comments

Comments
 (0)