fix: use util.inspect for more reliable logging (#37880)
The tests are probably overkill, but this way we will know if util.inspect changes dramatically.
This commit is contained in:
committed by
Randell Dawson
parent
450ac77e6a
commit
d40be9cbf2
@ -1,6 +1,7 @@
|
|||||||
import chai from 'chai';
|
import chai from 'chai';
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
import __toString from 'lodash/toString';
|
import __toString from 'lodash/toString';
|
||||||
|
import { format as __format } from '../../utils/format';
|
||||||
|
|
||||||
const __utils = (() => {
|
const __utils = (() => {
|
||||||
const MAX_LOGS_SIZE = 64 * 1024;
|
const MAX_LOGS_SIZE = 64 * 1024;
|
||||||
@ -16,16 +17,9 @@ const __utils = (() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function replacer(key, value) {
|
|
||||||
if (Number.isNaN(value)) {
|
|
||||||
return 'NaN';
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldLog = self.console.log.bind(self.console);
|
const oldLog = self.console.log.bind(self.console);
|
||||||
function proxyLog(...args) {
|
function proxyLog(...args) {
|
||||||
logs.push(args.map(arg => '' + JSON.stringify(arg, replacer)).join(' '));
|
logs.push(args.map(arg => __format(arg)).join(' '));
|
||||||
if (logs.join('\n').length > MAX_LOGS_SIZE) {
|
if (logs.join('\n').length > MAX_LOGS_SIZE) {
|
||||||
flushLogs();
|
flushLogs();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { toString, flow } from 'lodash';
|
import { toString, flow } from 'lodash';
|
||||||
|
import { format } from '../../../utils/format';
|
||||||
|
|
||||||
// we use two different frames to make them all essentially pure functions
|
// we use two different frames to make them all essentially pure functions
|
||||||
// main iframe is responsible rendering the preview and is where we proxy the
|
// main iframe is responsible rendering the preview and is where we proxy the
|
||||||
@ -81,7 +82,7 @@ const mountFrame = document => ({ element, ...rest }) => {
|
|||||||
const buildProxyConsole = proxyLogger => ctx => {
|
const buildProxyConsole = proxyLogger => ctx => {
|
||||||
const oldLog = ctx.window.console.log.bind(ctx.window.console);
|
const oldLog = ctx.window.console.log.bind(ctx.window.console);
|
||||||
ctx.window.console.log = function proxyConsole(...args) {
|
ctx.window.console.log = function proxyConsole(...args) {
|
||||||
proxyLogger(args.map(arg => '' + JSON.stringify(arg)).join(' '));
|
proxyLogger(args.map(arg => format(arg)).join(' '));
|
||||||
return oldLog(...args);
|
return oldLog(...args);
|
||||||
};
|
};
|
||||||
return ctx;
|
return ctx;
|
||||||
|
7
client/src/utils/format.js
Normal file
7
client/src/utils/format.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { inspect } from 'util';
|
||||||
|
|
||||||
|
export function format(x) {
|
||||||
|
// we're trying to mimic console.log, so we avoid wrapping strings in quotes:
|
||||||
|
if (typeof x === 'string') return x;
|
||||||
|
return inspect(x);
|
||||||
|
}
|
56
client/src/utils/format.test.js
Normal file
56
client/src/utils/format.test.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* global expect BigInt */
|
||||||
|
|
||||||
|
const { format } = require('./format');
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
function simpleFun() {
|
||||||
|
var x = 'y';
|
||||||
|
}
|
||||||
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
|
/* format uses util.inspect to do almost everything, the tests are just there
|
||||||
|
to warn us if util.inspect ever changes */
|
||||||
|
describe('format', () => {
|
||||||
|
it('returns a string', () => {
|
||||||
|
expect(typeof format('')).toBe('string');
|
||||||
|
expect(typeof format({})).toBe('string');
|
||||||
|
expect(typeof format([])).toBe('string');
|
||||||
|
});
|
||||||
|
it('does not modify strings', () => {
|
||||||
|
expect(format('')).toBe('');
|
||||||
|
expect(format('abcde')).toBe('abcde');
|
||||||
|
expect(format('Case Sensitive')).toBe('Case Sensitive');
|
||||||
|
});
|
||||||
|
it('formats shallow objects nicely', () => {
|
||||||
|
expect(format({})).toBe('{}');
|
||||||
|
expect(format({ a: 'one', b: 'two' })).toBe(`{ a: 'one', b: 'two' }`);
|
||||||
|
});
|
||||||
|
it('formats functions the same way as console.log', () => {
|
||||||
|
expect(format(simpleFun)).toBe('[Function: simpleFun]');
|
||||||
|
});
|
||||||
|
it('recurses into arrays', () => {
|
||||||
|
const objsInArr = [{ a: 'one' }, 'b', simpleFun];
|
||||||
|
expect(format(objsInArr)).toBe(
|
||||||
|
`[ { a: 'one' }, 'b', [Function: simpleFun] ]`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('handles all primitive values', () => {
|
||||||
|
const primitives = [
|
||||||
|
'str',
|
||||||
|
57,
|
||||||
|
BigInt(10),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
undefined,
|
||||||
|
Symbol('Sym')
|
||||||
|
];
|
||||||
|
expect(format(primitives)).toBe(
|
||||||
|
`[ 'str', 57, 10n, true, false, null, undefined, Symbol(Sym) ]`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it(`outputs NaN as 'NaN'`, () => {
|
||||||
|
expect(format(NaN)).toBe('NaN');
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user