Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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: 2 additions & 2 deletions packages/kernel-agents/test/e2e/agents.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@ocap/repo-tools/test-utils/mock-endoify';

import { consoleTransport, Logger } from '@metamask/logger';
import { makeConsoleTransport, Logger } from '@metamask/logger';
import { OllamaNodejsService } from '@ocap/kernel-language-model-service/ollama/nodejs';
import { fetchMock } from '@ocap/repo-tools/test-utils/fetch-mock';
import {
Expand All @@ -25,7 +25,7 @@ import { filterTransports, randomLetter } from '../utils.ts';

const logger = new Logger({
tags: ['test'],
transports: [filterTransports(consoleTransport)],
transports: [filterTransports(makeConsoleTransport())],
});

const makeJsonAgentWithMathCapabilities = (args: MakeAgentArgs) =>
Expand Down
1 change: 0 additions & 1 deletion packages/kernel-browser-runtime/test/build-tests.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { runTests } from '@ocap/repo-tools/build-utils/test';
import path from 'node:path';

// eslint-disable-next-line n/no-unsupported-features/node-builtins
const outDir = path.resolve(import.meta.dirname, '../dist/static');

const untransformedFiles = [
Expand Down
2 changes: 0 additions & 2 deletions packages/kernel-browser-runtime/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ const staticCopyTargets: readonly (string | Target)[] = [
'../../kernel-shims/dist/endoify.js',
];

// We will only run this where it's available, but ESLint doesn't know that
// eslint-disable-next-line n/no-unsupported-features/node-builtins
const sourceDir = path.resolve(import.meta.dirname, 'src');
const buildDir = path.resolve(sourceDir, '../dist/static');

Expand Down
8 changes: 6 additions & 2 deletions packages/kernel-test/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

import type { KernelDatabase } from '@metamask/kernel-store';
import { stringify, waitUntilQuiescent } from '@metamask/kernel-utils';
import { Logger, makeArrayTransport, consoleTransport } from '@metamask/logger';
import {
Logger,
makeArrayTransport,
makeConsoleTransport,
} from '@metamask/logger';
import type { LogEntry } from '@metamask/logger';
import { Kernel, kunser } from '@metamask/ocap-kernel';
import type { ClusterConfig, PlatformServices } from '@metamask/ocap-kernel';
Expand Down Expand Up @@ -193,7 +197,7 @@ export function logDatabase(
export const makeTestLogger = (): { logger: Logger; entries: LogEntry[] } => {
const entries: LogEntry[] = [];
const logger = new Logger({
transports: [consoleTransport, makeArrayTransport(entries)],
transports: [makeConsoleTransport(), makeArrayTransport(entries)],
});
return { logger, entries };
};
Expand Down
8 changes: 7 additions & 1 deletion packages/logger/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
export const logLevels = ['debug', 'info', 'log', 'warn', 'error'] as const;
export const logLevels = {
debug: 1,
info: 2,
log: 3,
warn: 4,
error: 5,
} as const;
export const TOKEN_UNDEFINED = 'e790f877-6987-4b06-9ce2-5fc889d5b9ac';
2 changes: 1 addition & 1 deletion packages/logger/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ describe('index', () => {
expect(Object.keys(indexModule).sort()).toStrictEqual(
expect.arrayContaining([
'Logger',
'consoleTransport',
'makeArrayTransport',
'makeConsoleTransport',
'makeStreamTransport',
'splitLoggerStream',
]),
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { Logger } from './logger.ts';
export {
consoleTransport,
makeConsoleTransport,
makeArrayTransport,
makeStreamTransport,
} from './transports.ts';
Expand Down
31 changes: 28 additions & 3 deletions packages/logger/src/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import type { DuplexStream } from '@metamask/streams';
import { delay } from '@ocap/repo-tools/test-utils';
import { describe, it, expect, vi } from 'vitest';

import { logLevels } from './constants.ts';
import { Logger } from './logger.ts';
import { lser } from './stream.ts';
import type { LogMessage } from './stream.ts';
import { consoleTransport } from './transports.ts';
import { makeConsoleTransport } from './transports.ts';

const consoleMethod = ['log', 'debug', 'info', 'warn', 'error'] as const;
const transports = [consoleTransport];
const transports = [makeConsoleTransport()];

describe('Logger', () => {
it.each([
['no arguments', undefined],
['an empty object', {}],
['a string tag', 'test'],
['an options bag', { tags: ['test'], transports: [consoleTransport] }],
[
'an options bag',
{ tags: ['test'], transports: [makeConsoleTransport()] },
],
])('can be constructed with $description', (_description, options) => {
const logger = new Logger(options);
expect(logger).toBeInstanceOf(Logger);
Expand Down Expand Up @@ -113,6 +117,27 @@ describe('Logger', () => {
});
});

describe('logging level limits output', () => {
consoleMethod.forEach((level) => {
it(`logging at level ${level}`, () => {
const testLogger = new Logger({
transports: [makeConsoleTransport(level)],
});
consoleMethod.forEach((method) => {
const consoleSpy = vi.spyOn(console, method);
testLogger[method](`foo ${method}`);
if (logLevels[level] <= logLevels[method]) {
// eslint-disable-next-line vitest/no-conditional-expect
expect(consoleSpy).toHaveBeenCalledWith(`foo ${method}`);
} else {
// eslint-disable-next-line vitest/no-conditional-expect
expect(consoleSpy).not.toHaveBeenCalled();
}
});
});
});
});

describe('injectStream', () => {
it('calls drain on the provided stream', () => {
const logger = new Logger();
Expand Down
20 changes: 8 additions & 12 deletions packages/logger/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ export class Logger {
* logger's tag.
* @param options.transports - The transports, which deliver the log messages
* to the appropriate destination.
* @param options.level - The log level for the logger, used as a default
* argument for the transports.
* @param options.tags - The tags for the logger, which are accumulated by
* sub-loggers and passed to the transports.
*/
Expand All @@ -99,16 +97,14 @@ export class Logger {

// Create aliases for the log methods, allowing them to be used in a
// manner similar to the console object.
const bind = (level: LogLevel): LogMethod =>
harden(
this.#dispatch.bind(this, {
...this.#options,
level,
}),
const bind = (level: LogLevel): LogMethod => {
return harden(
this.#dispatch.bind(this, { ...this.#options }, level),
) as LogMethod;
this.log = bind('log');
};
this.debug = bind('debug');
this.info = bind('info');
this.log = bind('log');
this.warn = bind('warn');
this.error = bind('error');
}
Expand Down Expand Up @@ -146,13 +142,13 @@ export class Logger {
const { level, tags, message, data } = lunser(args);
const logArgs: LogArgs =
message === undefined ? [] : [message, ...(data ?? [])];
this.#dispatch({ level, tags }, ...logArgs);
this.#dispatch({ tags }, level, ...logArgs);
})
.catch((problem) => onError?.(problem));
}

#dispatch(options: LoggerOptions, ...args: LogArgs): void {
const { transports, level, tags } = mergeOptions(this.#options, options);
#dispatch(options: LoggerOptions, level: LogLevel, ...args: LogArgs): void {
const { transports, tags } = mergeOptions(this.#options, options);
const [message, ...data] = args;
const entry: LogEntry = harden({ level, tags, message, data });
transports.forEach((transport) => transport(entry));
Expand Down
31 changes: 10 additions & 21 deletions packages/logger/src/options.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import { describe, expect, it, vi } from 'vitest';

import { DEFAULT_OPTIONS, mergeOptions, parseOptions } from './options.ts';
import type { LoggerOptions, LogLevel, Transport } from './types.ts';
import type { Transport } from './types.ts';

const mocks = vi.hoisted(() => ({
consoleTransport: vi.fn(),
makeConsoleTransport: vi.fn(),
}));

vi.mock('./transports.ts', () => ({
consoleTransport: mocks.consoleTransport,
makeConsoleTransport: mocks.makeConsoleTransport,
}));

describe('parseOptions', () => {
it('parses an undefined options bag', () => {
const options = parseOptions(undefined);
expect(options).toStrictEqual({ transports: [mocks.consoleTransport] });
expect(options).toStrictEqual({
transports: [mocks.makeConsoleTransport()],
});
});

it('parses an empty options bag', () => {
const options = parseOptions({});
expect(options).toStrictEqual({ transports: [mocks.consoleTransport] });
expect(options).toStrictEqual({
transports: [mocks.makeConsoleTransport()],
});
});

it('parses an options bag', () => {
Expand All @@ -38,7 +42,7 @@ describe('parseOptions', () => {
const options = parseOptions('test');
expect(options).toStrictEqual({
tags: ['test'],
transports: [mocks.consoleTransport],
transports: [mocks.makeConsoleTransport()],
});
});

Expand Down Expand Up @@ -100,19 +104,4 @@ describe('mergeOptions', () => {
]);
},
);

it.each([
{ left: { level: 'warn' }, right: { level: 'error' }, result: 'error' },
{ left: { level: undefined }, right: { level: 'warn' }, result: 'warn' },
{ left: { level: 'info' }, right: {}, result: 'info' },
] as { left: LoggerOptions; right: LoggerOptions; result: LogLevel }[])(
'merges levels as expected: $left and $right',
({ left, right, result }) => {
const options = mergeOptions(
{ ...left, transports: [] },
{ ...right, transports: [] },
);
expect(options.level).toBe(result);
},
);
});
10 changes: 4 additions & 6 deletions packages/logger/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { consoleTransport } from './transports.ts';
import { makeConsoleTransport } from './transports.ts';
import type { LoggerOptions } from './types.ts';

/**
* The default options for the logger.
*/
export const DEFAULT_OPTIONS: Required<LoggerOptions> = {
transports: [],
level: 'info',
tags: [],
};

Expand All @@ -24,13 +23,13 @@ export const parseOptions = (
switch (typeof options) {
case 'object':
if (!options.transports) {
return { transports: [consoleTransport], ...options };
return { transports: [makeConsoleTransport()], ...options };
}
return options;
case 'string':
return { tags: [options], transports: [consoleTransport] };
return { tags: [options], transports: [makeConsoleTransport()] };
case 'undefined':
return { transports: [consoleTransport] };
return { transports: [makeConsoleTransport()] };
default:
throw new Error('Invalid logger options');
}
Expand Down Expand Up @@ -61,7 +60,6 @@ export const mergeOptions = (
(acc, option) =>
({
transports: unique([...acc.transports, ...(option.transports ?? [])]),
level: option.level ?? acc.level,
tags: unique([...acc.tags, ...(option.tags ?? [])]),
}) as Required<LoggerOptions>,
DEFAULT_OPTIONS,
Expand Down
8 changes: 5 additions & 3 deletions packages/logger/src/transports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { describe, expect, it, vi } from 'vitest';

import { logLevels } from './constants.ts';
import {
consoleTransport,
makeConsoleTransport,
makeArrayTransport,
makeStreamTransport,
} from './transports.ts';
Expand All @@ -17,9 +17,11 @@ const makeLogEntry = (level: LogLevel): LogEntry => ({
});

describe('consoleTransport', () => {
it.each(logLevels)(
it.each(Object.keys(logLevels))(
'logs to the appropriate console alias: %s',
(level: LogLevel) => {
(levelString: string) => {
const consoleTransport = makeConsoleTransport();
const level = levelString as LogLevel;
const logEntry = makeLogEntry(level);
const consoleMethodSpy = vi.spyOn(console, level);
consoleTransport(logEntry);
Expand Down
46 changes: 34 additions & 12 deletions packages/logger/src/transports.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
import type { JsonRpcMessage } from '@metamask/kernel-utils';
import type { DuplexStream } from '@metamask/streams';

import { logLevels } from './constants.ts';
import { lser } from './stream.ts';
import type { Transport } from './types.ts';
import type { Transport, LogArgs, LogLevel, LogMethod } from './types.ts';

/**
* The console transport for the logger.
*
* @param entry - The log entry to transport.
* @param level - The logging level for this instance.
* @returns A transport function that writes to the console.
*/
export const consoleTransport: Transport = (entry) => {
const args = [
...(entry.tags.length > 0 ? [entry.tags] : []),
...(entry.message ? [entry.message] : []),
...(entry.data ?? []),
];
// Ultimately, a console somewhere is an acceptable terminal for logging
// eslint-disable-next-line no-console
console[entry.level](...args);
};
export function makeConsoleTransport(level: LogLevel = 'debug'): Transport {
const baseLevelIdx = logLevels[level];
const logFn = (method: LogLevel): LogMethod => {
if (baseLevelIdx <= logLevels[method]) {
return (...args: unknown[]) => {
// Ultimately, a console somewhere is an acceptable terminal for logging
// eslint-disable-next-line no-console
console[method](...args);
};
}
// eslint-disable-next-line no-empty-function
return harden(() => {}) as LogMethod;
};
const filteredConsole = {
debug: logFn('debug'),
info: logFn('info'),
log: logFn('log'),
warn: logFn('warn'),
error: logFn('error'),
};
const consoleTransport: Transport = (entry) => {
const args = [
...(entry.tags.length > 0 ? [entry.tags] : []),
...(entry.message ? [entry.message] : []),
...(entry.data ?? []),
] as LogArgs;
filteredConsole[entry.level](...args);
};
return consoleTransport;
}

/**
* The stream transport for the logger. Expects the stream is listening for
Expand Down
3 changes: 1 addition & 2 deletions packages/logger/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { logLevels } from './constants.ts';
/**
* The log level for the logger.
*/
export type LogLevel = (typeof logLevels)[number];
export type LogLevel = keyof typeof logLevels;

/**
* The log entry for the logger.
Expand All @@ -25,7 +25,6 @@ export type Transport = (entry: LogEntry) => void;
*/
export type LoggerOptions = {
transports?: Transport[];
level?: LogLevel;
tags?: string[];
};

Expand Down
1 change: 0 additions & 1 deletion packages/omnium-gatherum/test/build/build-tests.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { runTests } from '@ocap/repo-tools/build-utils/test';
import path from 'node:path';

// eslint-disable-next-line n/no-unsupported-features/node-builtins
const packageDir = path.resolve(import.meta.dirname, '../../');
const outDir = path.resolve(packageDir, 'dist');
const untransformedFiles = [
Expand Down
Loading
Loading