Skip to content
Open
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
4 changes: 4 additions & 0 deletions packages/snap-networks-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **BREAKING** Replace the logger utilities with a configurable `Logger` class that defaults to trace logging and supports level filtering, per-instance prefixes, and method decorators. `log` is retained as a deprecated alias for `info`.

## [1.0.0]

### Added
Expand Down
8 changes: 1 addition & 7 deletions packages/snap-networks-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ yarn workspace @metamask/tron-wallet-snap add @metamask/snap-networks-utils@work

### Logger

```typescript
import { logger, createPrefixedLogger } from '@metamask/snap-networks-utils';
// or: import { logger } from '@metamask/snap-networks-utils/logger';

const snapLogger = createPrefixedLogger(logger, '[tron-wallet-snap]');
snapLogger.info('account synced');
```
See the [logger README](./src/logger/README.md).

### Core AssetsController reads

Expand Down
8 changes: 4 additions & 4 deletions packages/snap-networks-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@
},
"./logger": {
"import": {
"types": "./dist/logger.d.mts",
"default": "./dist/logger.mjs"
"types": "./dist/logger/index.d.mts",
"default": "./dist/logger/index.mjs"
},
"require": {
"types": "./dist/logger.d.cts",
"default": "./dist/logger.cjs"
"types": "./dist/logger/index.d.cts",
"default": "./dist/logger/index.cjs"
}
},
"./package.json": "./package.json"
Expand Down
2 changes: 0 additions & 2 deletions packages/snap-networks-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export type { Logger } from './logger';
export { createPrefixedLogger, logger, noOpLogger } from './logger';
export {
ASSETS_PROVIDER_NAME,
AssetsProvider,
Expand Down
55 changes: 0 additions & 55 deletions packages/snap-networks-utils/src/logger.test.ts

This file was deleted.

66 changes: 0 additions & 66 deletions packages/snap-networks-utils/src/logger.ts

This file was deleted.

168 changes: 168 additions & 0 deletions packages/snap-networks-utils/src/logger/Logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { Logger, LogLevel } from './Logger';

const setupTest = () => {

Check failure on line 3 in packages/snap-networks-utils/src/logger/Logger.test.ts

View workflow job for this annotation

GitHub Actions / Lint, build, and test / Lint (lint:eslint)

Missing return type on function
jest.restoreAllMocks();

return {
loggerMethods: [
{ method: 'log', consoleMethod: 'info', filteredAt: LogLevel.WARN },
{ method: 'info', consoleMethod: 'info', filteredAt: LogLevel.WARN },
{ method: 'warn', consoleMethod: 'warn', filteredAt: LogLevel.ERROR },
{
method: 'error',
consoleMethod: 'error',
filteredAt: LogLevel.SILENT,
},
{ method: 'debug', consoleMethod: 'debug', filteredAt: LogLevel.INFO },
{ method: 'trace', consoleMethod: 'trace', filteredAt: LogLevel.DEBUG },
] as const,
mockConsole: {
debug: jest.spyOn(console, 'debug').mockImplementation(),
error: jest.spyOn(console, 'error').mockImplementation(),
info: jest.spyOn(console, 'info').mockImplementation(),
trace: jest.spyOn(console, 'trace').mockImplementation(),
warn: jest.spyOn(console, 'warn').mockImplementation(),
},
};
};

describe('Logger', () => {
it('forwards calls to the matching console method', () => {
const { loggerMethods, mockConsole } = setupTest();

const logger = new Logger({
enabled: true,
});

for (const { method, consoleMethod } of loggerMethods) {
logger[method]('hello', 42);

expect(mockConsole[consoleMethod]).toHaveBeenCalledWith('hello', 42);
}
});

it('prefixes messages with a derived logger', () => {
const { mockConsole } = setupTest();

const logger = new Logger({
enabled: true,
});

const prefixed = logger.withPrefix('[snap-networks-utils]');

prefixed.info('a');
prefixed.warn('b');
prefixed.error('c');
prefixed.debug('d');
prefixed.trace('e');

expect(mockConsole.info).toHaveBeenCalledWith('[snap-networks-utils]', 'a');
expect(mockConsole.warn).toHaveBeenCalledWith('[snap-networks-utils]', 'b');
expect(mockConsole.error).toHaveBeenCalledWith(
'[snap-networks-utils]',
'c',
);
expect(mockConsole.debug).toHaveBeenCalledWith(
'[snap-networks-utils]',
'd',
);
expect(mockConsole.trace).toHaveBeenCalledWith(
'[snap-networks-utils]',
'e',
);
});

it('combines prefixes from derived loggers', () => {
const { mockConsole } = setupTest();

const logger = new Logger({
enabled: true,
});

const parentLogger = logger.withPrefix('[parent]');
const childLogger = parentLogger.withPrefix('[child]');

childLogger.info('message');

expect(mockConsole.info).toHaveBeenCalledWith(
'[parent] [child]',
'message',
);
});

it('defaults to the trace level', () => {
const { mockConsole } = setupTest();

const logger = new Logger({ enabled: true });

logger.trace('trace');

expect(mockConsole.trace).toHaveBeenCalledWith('trace');
});

it('runs decorators through the configured output', () => {
const decorator = jest.fn((next: (...args: unknown[]) => void) => {
next('decoded error');
});
const { mockConsole } = setupTest();

const baseLogger = new Logger({
enabled: true,
decorators: { error: decorator },
});

const logger = baseLogger.withPrefix('[Solana]');

logger.error('original error');

expect(decorator).toHaveBeenCalledWith(
expect.any(Function),
'original error',
);
expect(mockConsole.error).toHaveBeenCalledWith('[Solana]', 'decoded error');
});

it('does not run decorators when logging is disabled', () => {
const decorator = jest.fn();
const { mockConsole } = setupTest();

const logger = new Logger({
enabled: false,
decorators: { error: decorator },
});

logger.error('silent');

expect(decorator).not.toHaveBeenCalled();
expect(mockConsole.error).not.toHaveBeenCalled();
});

it('does not log calls when disabled', () => {
const { loggerMethods, mockConsole } = setupTest();

const logger = new Logger({
enabled: false,
});

for (const { method, consoleMethod } of loggerMethods) {
logger[method]('silent');

expect(mockConsole[consoleMethod]).not.toHaveBeenCalled();
}
});

it('filters messages above the configured level', () => {
const { loggerMethods, mockConsole } = setupTest();

for (const { method, consoleMethod, filteredAt } of loggerMethods) {
const logger = new Logger({
enabled: true,
level: filteredAt,
});

logger[method]('filtered');

expect(mockConsole[consoleMethod]).not.toHaveBeenCalled();
}
});
});
Loading
Loading