Skip to content

Commit

Permalink
feat(logs): Added an option to control log level
Browse files Browse the repository at this point in the history
  • Loading branch information
vijayasingam-paddle committed Jun 19, 2024
1 parent dcb5f0a commit d9f1689
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 7 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ When we make [non-breaking changes](https://developer.paddle.com/api-reference/a

This means when upgrading minor versions of the SDK, you may notice type errors. You can safely ignore these or fix by adding additional type guards.

## 1.4.0 - 2024-06-20

### Added

- Added a new option to change the logging level of the SDK. You can now set the logging level to `verbose`, `warn`, `error` or `none`. The default logging level is `verbose`.

---

## 1.3.0 - 2024-04-18

### Changed
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ You can also pass an environment to work with the sandbox:
```typescript
const paddle = new Paddle('API_KEY', {
environment: Environment.production, // or Environment.sandbox for accessing sandbox API
logLevel: 'verbose' // or 'error' for less verbose logging
})
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@paddle/paddle-node-sdk",
"version": "1.3.0",
"version": "1.4.0",
"description": "A Node.js SDK that you can use to integrate Paddle Billing with applications written in server-side JavaScript.",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
Expand Down
82 changes: 82 additions & 0 deletions src/__tests__/internal/logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { LogLevel } from '../../internal';
import { Logger } from '../../internal/base/logger';
import { type Response } from 'node-fetch';

describe('logger', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test.each([
[LogLevel.verbose, LogLevel.verbose, true],
[LogLevel.verbose, LogLevel.warn, true],
[LogLevel.verbose, LogLevel.error, true],
[LogLevel.verbose, LogLevel.none, false],
[LogLevel.warn, LogLevel.verbose, false],
[LogLevel.warn, LogLevel.warn, true],
[LogLevel.warn, LogLevel.error, true],
[LogLevel.warn, LogLevel.none, false],
[LogLevel.error, LogLevel.verbose, false],
[LogLevel.error, LogLevel.warn, false],
[LogLevel.error, LogLevel.error, true],
[LogLevel.error, LogLevel.none, false],
[LogLevel.none, LogLevel.verbose, false],
[LogLevel.none, LogLevel.warn, false],
[LogLevel.none, LogLevel.error, false],
[LogLevel.none, LogLevel.none, false],
])('shouldLog(%s) with logLevel %s should return %s', (logLevel, level, expected) => {
Logger.logLevel = logLevel;
// @ts-expect-error - testing private method
expect(Logger.shouldLog(level)).toBe(expected);
});
test('log', () => {
Logger.logLevel = LogLevel.verbose;
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
Logger.log('test');
expect(consoleSpy).toHaveBeenCalledWith('[Paddle] [LOG]', 'test');
});
test('warn', () => {
Logger.logLevel = LogLevel.warn;
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
Logger.warn('test');
expect(consoleSpy).toHaveBeenCalledWith('[Paddle] [WARN]', 'test');
});
test('error', () => {
Logger.logLevel = LogLevel.error;
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
Logger.error('test');
expect(consoleSpy).toHaveBeenCalledWith('[Paddle] [ERROR]', 'test');
});
test('logRequest', () => {
Logger.logLevel = LogLevel.verbose;
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
Logger.logRequest('GET', 'https://example.com', { 'X-Transaction-ID': '123' });
expect(consoleSpy).toHaveBeenCalledWith(
'[Paddle] [LOG]',
'[Request]',
'GET',
'https://example.com',
'Transaction ID:',
'123',
);
});
test('logResponse', () => {
Logger.logLevel = LogLevel.verbose;
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
const response = {
status: 200,
headers: new Map([['Request-Id', '456']]),
};
Logger.logResponse('GET', 'https://example.com', { 'X-Transaction-ID': '123' }, response as unknown as Response);
expect(consoleSpy).toHaveBeenCalledWith(
'[Paddle] [LOG]',
'[Response]',
'GET',
'https://example.com',
'200',
'Transaction ID:',
'123',
'Request ID:',
'456',
);
});
});
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Changes may be overwritten as part of auto-generation.
*/

export { Environment, ApiError, type PaddleOptions } from './internal';
export { Environment, LogLevel, ApiError, type PaddleOptions } from './internal';
export { SDK_VERSION } from './version';

export { Paddle } from './paddle';
Expand Down
3 changes: 3 additions & 0 deletions src/internal/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { randomUUID } from 'node:crypto';
import { Logger } from '../base/logger';
import { convertToSnakeCase } from './case-helpers';
import { type ErrorResponse } from '../types/response';
import { LogLevel } from './log-level';

export class Client {
private readonly baseUrl: string;
Expand All @@ -17,6 +18,8 @@ export class Client {
private readonly options: PaddleOptions,
) {
this.baseUrl = this.getBaseUrl(this.options.environment);
// TODO - Change the default to `error` in next major version
Logger.logLevel = this.options.logLevel ?? LogLevel.verbose;
}

private getBaseUrl(environment?: Environment): string {
Expand Down
1 change: 1 addition & 0 deletions src/internal/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Environment } from './environment';
export { convertToSnakeCase } from './case-helpers';
export { LogLevel } from './log-level';
6 changes: 6 additions & 0 deletions src/internal/api/log-level.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum LogLevel {
verbose = 'verbose',
warn = 'warn',
error = 'error',
none = 'none',
}
27 changes: 24 additions & 3 deletions src/internal/base/logger.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import { type Response } from 'node-fetch';
import { LogLevel } from '../api';

type LogInputProps = Array<string | undefined | null>;

export class Logger {
static logLevel: LogLevel;

private static shouldLog(level: LogLevel) {
switch (Logger.logLevel) {
case LogLevel.verbose:
return level !== LogLevel.none;
case LogLevel.warn:
return level === LogLevel.warn || level === LogLevel.error;
case LogLevel.error:
return level === LogLevel.error;
default:
return false;
}
}
static log(...args: LogInputProps) {

Check failure on line 21 in src/internal/base/logger.ts

View workflow job for this annotation

GitHub Actions / Run linters

Expected blank line between class members
console.log('[Paddle] [LOG]', ...args);
if (Logger.shouldLog(LogLevel.verbose)) {
console.log('[Paddle] [LOG]', ...args);
}
}

static warn(...args: LogInputProps) {
console.warn('[Paddle] [WARN]', ...args);
if (Logger.shouldLog(LogLevel.warn)) {
console.warn('[Paddle] [WARN]', ...args);
}
}

static error(...args: LogInputProps) {
console.error('[Paddle] [ERROR]', ...args);
if (Logger.shouldLog(LogLevel.error)) {
console.error('[Paddle] [ERROR]', ...args);
}
}

static logRequest(method: string, url: string | undefined, headers: Record<string, string>) {
Expand Down
3 changes: 2 additions & 1 deletion src/internal/types/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Environment } from '../api';
import { type Environment, LogLevel } from '../api';

Check failure on line 1 in src/internal/types/config.ts

View workflow job for this annotation

GitHub Actions / Run linters

All imports in the declaration are only used as types. Use `import type`

export interface PaddleOptions {
environment?: Environment;
logLevel?: LogLevel;
}
3 changes: 2 additions & 1 deletion src/paddle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ import {
SubscriptionsResource,
TransactionsResource,
} from './resources';
import { Environment, type PaddleOptions } from './internal';
import { Environment, LogLevel, type PaddleOptions } from './internal';
import { EventsResource } from './resources/events';
import { Webhooks } from './notifications';

export class Paddle {
private readonly client: Client;
private readonly defaultPaddleOptions: Partial<PaddleOptions> = {
environment: Environment.production,
logLevel: LogLevel.verbose, // TODO - Change the default to `error` in next major version
};

public products: ProductsResource;
Expand Down

0 comments on commit d9f1689

Please sign in to comment.