Skip to content
Merged
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: 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