chore(connect): move logs to @trezor/utils

This commit is contained in:
Martin Varmuza
2024-03-11 17:41:19 +01:00
committed by martin
parent 6aef552a9b
commit 28c2b9fe57
6 changed files with 207 additions and 170 deletions

View File

@@ -1,29 +0,0 @@
import { initLog, enableLog, enableLogByPrefix, getLog } from '../debug';
describe('utils/debug', () => {
it('max entries', () => {
const l = initLog('test');
const l2 = initLog('test2');
for (let i = 0; i < 110; i++) {
l.log('entry');
l2.error('entry');
l.warn('entry');
l2.debug('entry');
}
expect(l.messages.length).toEqual(100);
expect(l2.messages.length).toEqual(100);
expect(getLog().length).toEqual(200); // combined
});
it('enable/disable', () => {
const l = initLog('test', true);
const l2 = initLog('test2');
enableLogByPrefix('foobar', false);
enableLogByPrefix('test2', true); // enable only one
expect(l.enabled).toEqual(true);
expect(l2.enabled).toEqual(true);
enableLog(false); // disable all
expect(l.enabled).toEqual(false);
expect(l2.enabled).toEqual(false);
});
});

View File

@@ -1,5 +1,4 @@
// origin: https://github.com/trezor/connect/blob/develop/src/js/utils/debug.js
/* eslint-disable no-console */
import { LogsManager } from '@trezor/utils';
const green = '#bada55';
const blue = '#20abd8';
@@ -24,144 +23,12 @@ const colors: Record<string, string> = {
'@trezor/connect-popup': `color: ${yellow}; background: #000;`,
};
export type LogMessage = {
level: string;
prefix: string;
message: any[];
timestamp: number;
};
const logsManager = new LogsManager({ colors });
export type LogWriter = {
add: (message: LogMessage) => void;
};
export const initLog = logsManager.initLog.bind(logsManager);
export const setLogWriter = logsManager.setLogWriter.bind(logsManager);
export const enableLog = logsManager.enableLog.bind(logsManager);
export const enableLogByPrefix = logsManager.enableLogByPrefix.bind(logsManager);
export const getLog = logsManager.getLog.bind(logsManager);
const MAX_ENTRIES = 100;
export class Log {
prefix: string;
enabled: boolean;
css: string;
messages: LogMessage[];
logWriter: LogWriter | undefined;
constructor(prefix: string, enabled: boolean, logWriter?: LogWriter) {
this.prefix = prefix;
this.enabled = enabled;
this.messages = [];
this.css = typeof window !== 'undefined' && colors[prefix] ? colors[prefix] : '';
if (logWriter) {
this.logWriter = logWriter;
}
}
addMessage(
{ level, prefix, timestamp }: { level: string; prefix: string; timestamp?: number },
...args: any[]
) {
const message = {
level,
prefix,
css: this.css,
message: args,
timestamp: timestamp || Date.now(),
};
this.messages.push(message);
if (this.logWriter) {
try {
this.logWriter.add(message);
} catch (err) {
// If this error happens it probably means that we are logging an object with a circular reference.
// If there is any `device` logged, do it with `device.toMessageObject()` instead.
console.error('There was an error adding log message', err, message);
}
}
if (this.messages.length > MAX_ENTRIES) {
this.messages.shift();
}
}
setWriter(logWriter: any) {
this.logWriter = logWriter;
}
log(...args: any[]) {
this.addMessage({ level: 'log', prefix: this.prefix }, ...args);
if (this.enabled) {
console.log(`%c${this.prefix}`, this.css, ...args);
}
}
error(...args: any[]) {
this.addMessage({ level: 'error', prefix: this.prefix }, ...args);
if (this.enabled) {
console.error(`%c${this.prefix}`, this.css, ...args);
}
}
warn(...args: any[]) {
this.addMessage({ level: 'warn', prefix: this.prefix }, ...args);
if (this.enabled) {
console.warn(`%c${this.prefix}`, this.css, ...args);
}
}
debug(...args: any[]) {
this.addMessage({ level: 'debug', prefix: this.prefix }, ...args);
if (this.enabled) {
if (this.css) {
console.log(`%c${this.prefix}`, this.css, ...args);
} else {
console.log(this.prefix, ...args);
}
}
}
}
const _logs: { [k: string]: Log } = {};
let writer: LogWriter | undefined;
export const initLog = (prefix: string, enabled?: boolean, logWriter?: LogWriter) => {
const instanceWriter = logWriter || writer;
const instance = new Log(prefix, !!enabled, instanceWriter);
_logs[prefix] = instance;
return instance;
};
export const setLogWriter = (logWriterFactory: () => LogWriter | undefined) => {
Object.keys(_logs).forEach(key => {
writer = logWriterFactory();
if (writer) {
_logs[key].setWriter(writer);
const { messages } = _logs[key];
// If there are any messages in the log when init, add them to the writer.
messages.forEach(message => {
writer?.add(message);
});
}
});
};
export const enableLog = (enabled?: boolean) => {
Object.keys(_logs).forEach(key => {
_logs[key].enabled = !!enabled;
});
};
export const enableLogByPrefix = (prefix: string, enabled: boolean) => {
if (_logs[prefix]) {
_logs[prefix].enabled = enabled;
}
};
export const getLog = () => {
let logs: LogMessage[] = [];
Object.keys(_logs).forEach(key => {
logs = logs.concat(_logs[key].messages);
});
logs.sort((a, b) => a.timestamp - b.timestamp);
return logs;
};
export type { LogMessage, LogWriter, Log } from '@trezor/utils';

View File

@@ -38,3 +38,5 @@ export * from './topologicalSort';
export * from './truncateMiddle';
export * from './typedEventEmitter';
export * from './urlToOnion';
export * from './logs';
export * from './logsManager';

107
packages/utils/src/logs.ts Normal file
View File

@@ -0,0 +1,107 @@
export type LogMessage = {
level: string;
prefix: string;
message: any[];
timestamp: number;
};
export type LogWriter = {
add: (message: LogMessage) => void;
};
export class Log {
prefix: string;
enabled: boolean;
css: string = '';
messages: LogMessage[];
logWriter: LogWriter | undefined;
MAX_ENTRIES = 100;
constructor(prefix: string, enabled: boolean, logWriter?: LogWriter) {
this.prefix = prefix;
this.enabled = enabled;
this.messages = [];
if (logWriter) {
this.logWriter = logWriter;
}
}
setColors(colors: Record<string, string>) {
this.css = typeof window !== 'undefined' && colors[this.prefix] ? colors[this.prefix] : '';
}
addMessage(
{ level, prefix, timestamp }: { level: string; prefix: string; timestamp?: number },
...args: any[]
) {
const message = {
level,
prefix,
css: this.css,
message: args,
timestamp: timestamp || Date.now(),
};
this.messages.push(message);
if (this.logWriter) {
try {
this.logWriter.add(message);
} catch (err) {
// If this error happens it probably means that we are logging an object with a circular reference.
// If there is any `device` logged, do it with `device.toMessageObject()` instead.
console.error('There was an error adding log message', err, message);
}
}
if (this.messages.length > this.MAX_ENTRIES) {
this.messages.shift();
}
}
setWriter(logWriter: any) {
this.logWriter = logWriter;
}
log(...args: any[]) {
this.addMessage({ level: 'log', prefix: this.prefix }, ...args);
if (this.enabled) {
console.log(`%c${this.prefix}`, this.css, ...args);
}
}
error(...args: any[]) {
this.addMessage({ level: 'error', prefix: this.prefix }, ...args);
if (this.enabled) {
console.error(`%c${this.prefix}`, this.css, ...args);
}
}
info(...args: any[]) {
this.addMessage({ level: 'info', prefix: this.prefix }, ...args);
if (this.enabled) {
console.info(`%c${this.prefix}`, this.css, ...args);
}
}
warn(...args: any[]) {
this.addMessage({ level: 'warn', prefix: this.prefix }, ...args);
if (this.enabled) {
console.warn(`%c${this.prefix}`, this.css, ...args);
}
}
debug(...args: any[]) {
this.addMessage({ level: 'debug', prefix: this.prefix }, ...args);
if (this.enabled) {
if (this.css) {
console.log(`%c${this.prefix}`, this.css, ...args);
} else {
console.log(this.prefix, ...args);
}
}
}
getLog() {
return this.messages;
}
}

View File

@@ -0,0 +1,57 @@
import { LogWriter, Log, LogMessage } from './logs';
export class LogsManager {
logs: { [k: string]: Log } = {};
writer: LogWriter | undefined;
colors?: Record<string, string> = {};
constructor({ colors }: { colors?: Record<string, string> }) {
this.colors = colors;
}
initLog(prefix: string, enabled?: boolean, logWriter?: LogWriter) {
const instanceWriter = logWriter || this.writer;
const instance = new Log(prefix, !!enabled, instanceWriter);
if (this.colors) {
instance.setColors(this.colors);
}
this.logs[prefix] = instance;
return instance;
}
setLogWriter(logWriterFactory: () => LogWriter | undefined) {
Object.keys(this.logs).forEach(key => {
this.writer = logWriterFactory();
if (this.writer) {
this.logs[key].setWriter(this.writer);
const { messages } = this.logs[key];
// If there are any messages in the log when init, add them to the writer.
messages.forEach(message => {
this.writer?.add(message);
});
}
});
}
enableLog(enabled?: boolean) {
Object.keys(this.logs).forEach(key => {
this.logs[key].enabled = !!enabled;
});
}
enableLogByPrefix(prefix: string, enabled: boolean) {
if (this.logs[prefix]) {
this.logs[prefix].enabled = enabled;
}
}
getLog() {
let logs: LogMessage[] = [];
Object.keys(this.logs).forEach(key => {
logs = logs.concat(this.logs[key].messages);
});
logs.sort((a, b) => a.timestamp - b.timestamp);
return logs;
}
}

View File

@@ -0,0 +1,33 @@
import { LogsManager } from '../src/logsManager';
describe('utils/debug', () => {
it('max entries', () => {
const logsManager = new LogsManager({});
const l = logsManager.initLog('test');
const l2 = logsManager.initLog('test2');
for (let i = 0; i < 110; i++) {
l.log('entry');
l2.error('entry');
l.warn('entry');
l2.debug('entry');
}
expect(l.messages.length).toEqual(100);
expect(l2.messages.length).toEqual(100);
expect(logsManager.getLog().length).toEqual(200); // combined
});
it('enable/disable', () => {
const logsManager = new LogsManager({});
const l = logsManager.initLog('test', true);
const l2 = logsManager.initLog('test2');
logsManager.enableLogByPrefix('foobar', false);
logsManager.enableLogByPrefix('test2', true); // enable only one
expect(l.enabled).toEqual(true);
expect(l2.enabled).toEqual(true);
logsManager.enableLog(false); // disable all
expect(l.enabled).toEqual(false);
expect(l2.enabled).toEqual(false);
});
});