Skip to content

Commit 5ac9b52

Browse files
authored
feat: Allow for custom logger to be configured and default to console (#186)
Provide the option to configure a custom logger to `RESTDataSource` to replace the default console logging.
1 parent ecaac80 commit 5ac9b52

File tree

6 files changed

+73
-8
lines changed

6 files changed

+73
-8
lines changed

.changeset/great-windows-warn.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@apollo/datasource-rest': minor
3+
---
4+
5+
Customize the logger used by `RESTDataSource`.
6+
By default the `RESTDataSource` will use `console`.
7+
Common use cases would be to override the default logger with `pino` or `winston`.
8+
9+
E.g.
10+
```typescript
11+
const pino = require('pino');
12+
const loggerPino = pino({});
13+
const dataSource = new (class extends RESTDataSource {})({
14+
logger: loggerPino,
15+
});
16+
```
17+
18+
In the example above, all logging calls made by the `RESTDataSource` will now use the `pino` logger instead of the `console` logger.

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ class MoviesAPI extends RESTDataSource {
5353

5454
This README lists all the protected methods. In practice, if you're looking to customize behavior by overriding methods, reading the [source code](https://github.com/apollographql/datasource-rest/tree/main/src/RESTDataSource.ts) is the best option.
5555

56+
#### Constructor
57+
58+
The `RESTDataSource` takes in a `DataSourceConfig` which allows for overriding some default behavior.
59+
60+
Configuration Overrides
61+
- `cache` - Custom [`KeyValueCache`](https://www.npmjs.com/package/@apollo/utils.keyvaluecache) implementation
62+
- `fetch` - Custom [`Fetcher`](https://www.npmjs.com/package/@apollo/utils.fetcher) implementation
63+
- `logger` - Custom [`Logger`](https://www.npmjs.com/package/@apollo/utils.logger) implementation that will replace all logging activity within `RESTDataSource`
64+
65+
To override the RESTDataSource, see the following example code:
66+
67+
```typescript
68+
const dataSource = new (class extends RESTDataSource {})({
69+
cache: customCache,
70+
fetch: customFetcher,
71+
logger: customLogger,
72+
});
73+
```
74+
5675
#### Properties
5776

5877
##### `baseURL`

package-lock.json

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"dependencies": {
5555
"@apollo/utils.fetcher": "^2.0.0",
5656
"@apollo/utils.keyvaluecache": "^2.0.0",
57+
"@apollo/utils.logger": "^2.0.1",
5758
"@apollo/utils.withrequired": "^2.0.0",
5859
"@types/http-cache-semantics": "^4.0.1",
5960
"http-cache-semantics": "^4.1.1",

src/RESTDataSource.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { WithRequired } from '@apollo/utils.withrequired';
88
import { GraphQLError } from 'graphql';
99
import isPlainObject from 'lodash.isplainobject';
1010
import { HTTPCache } from './HTTPCache';
11+
import type { Logger } from '@apollo/utils.logger';
1112
import type { Options as HttpCacheSemanticsOptions } from 'http-cache-semantics';
1213

1314
export type ValueOrPromise<T> = T | Promise<T>;
@@ -124,6 +125,7 @@ const NODE_ENV = process.env.NODE_ENV;
124125
export interface DataSourceConfig {
125126
cache?: KeyValueCache;
126127
fetch?: Fetcher;
128+
logger?: Logger;
127129
}
128130

129131
export interface RequestDeduplicationResult {
@@ -175,9 +177,11 @@ export abstract class RESTDataSource {
175177
protected httpCache: HTTPCache;
176178
protected deduplicationPromises = new Map<string, Promise<any>>();
177179
baseURL?: string;
180+
logger: Logger;
178181

179182
constructor(config?: DataSourceConfig) {
180183
this.httpCache = new HTTPCache(config?.cache, config?.fetch);
184+
this.logger = config?.logger ?? console;
181185
}
182186

183187
// By default, we use `cacheKey` from the request if provided, or the full
@@ -605,7 +609,7 @@ export abstract class RESTDataSource {
605609
// Override this method to handle these errors in a different way.
606610
protected catchCacheWritePromiseErrors(cacheWritePromise: Promise<void>) {
607611
cacheWritePromise.catch((e) => {
608-
console.error(`Error writing from RESTDataSource to cache: ${e}`);
612+
this.logger.error(`Error writing from RESTDataSource to cache: ${e}`);
609613
});
610614
}
611615

@@ -622,7 +626,7 @@ export abstract class RESTDataSource {
622626
} finally {
623627
const duration = Date.now() - startTime;
624628
const label = `${request.method || 'GET'} ${url}`;
625-
console.log(`${label} (${duration}ms)`);
629+
this.logger.info(`${label} (${duration}ms)`);
626630
}
627631
} else {
628632
return fn();

src/__tests__/RESTDataSource.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,35 @@ import nock from 'nock';
1414
import { nockAfterEach, nockBeforeEach } from './nockAssertions';
1515
import type { WithRequired } from '@apollo/utils.withrequired';
1616
import { Headers as NodeFetchHeaders } from 'node-fetch';
17+
import type { Logger } from '@apollo/utils.logger';
1718

1819
const apiUrl = 'https://api.example.com';
1920

2021
describe('RESTDataSource', () => {
2122
beforeEach(nockBeforeEach);
2223
afterEach(nockAfterEach);
2324

25+
it('not overriding logger will use "console" as logger', async () => {
26+
const dataSource = new (class extends RESTDataSource {})();
27+
28+
expect(dataSource.logger).toEqual(console);
29+
});
30+
31+
it('providing override to logger will use "console" as logger', async () => {
32+
const testLogger: Logger = {
33+
debug: jest.fn(),
34+
info: jest.fn(),
35+
error: jest.fn(),
36+
warn: jest.fn(),
37+
};
38+
const dataSource = new (class extends RESTDataSource {})({
39+
logger: testLogger,
40+
});
41+
42+
expect(dataSource.logger).not.toEqual(console);
43+
expect(dataSource.logger).toEqual(testLogger);
44+
});
45+
2446
describe('constructing requests', () => {
2547
it('interprets paths relative to the base URL', async () => {
2648
const dataSource = new (class extends RESTDataSource {

0 commit comments

Comments
 (0)