2018-10-16 10:25:37 +00:00
|
|
|
import ColorHash = require('color-hash');
|
|
|
|
import * as _ from 'lodash';
|
2020-02-27 12:38:50 +00:00
|
|
|
import type { Readable } from 'stream';
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2020-02-28 15:25:12 +00:00
|
|
|
import { getChalk } from '../lazy';
|
2018-10-16 10:25:37 +00:00
|
|
|
import Logger = require('../logger');
|
|
|
|
|
|
|
|
interface Log {
|
|
|
|
message: string;
|
|
|
|
timestamp?: number;
|
|
|
|
serviceName?: string;
|
|
|
|
|
|
|
|
// There's also a serviceId and imageId, but they're
|
|
|
|
// meaningless in local mode
|
|
|
|
}
|
|
|
|
|
|
|
|
interface BuildLog {
|
|
|
|
serviceName: string;
|
|
|
|
message: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Display logs from a device logging stream. This function will return
|
|
|
|
* when the log stream ends.
|
|
|
|
*
|
2019-04-24 13:59:07 +00:00
|
|
|
* @param logs A stream which produces newline seperated log
|
|
|
|
* objects
|
|
|
|
* @param logger A Logger instance which the logs will be
|
|
|
|
* displayed through
|
2019-04-24 16:30:18 +00:00
|
|
|
* @param system Only show system (and potentially the
|
|
|
|
* filterService) logs
|
2019-04-24 13:59:07 +00:00
|
|
|
* @param filterService Filter the logs so that only logs
|
|
|
|
* from a single service will be displayed
|
2018-10-16 10:25:37 +00:00
|
|
|
*/
|
|
|
|
export function displayDeviceLogs(
|
|
|
|
logs: Readable,
|
|
|
|
logger: Logger,
|
2019-04-24 16:30:18 +00:00
|
|
|
system: boolean,
|
2019-05-28 15:56:39 +00:00
|
|
|
filterServices?: string[],
|
2020-06-30 20:24:35 +00:00
|
|
|
): Promise<void> {
|
|
|
|
return new Promise((resolve, reject) => {
|
2020-06-15 22:53:07 +00:00
|
|
|
logs.on('data', (log) => {
|
2019-05-28 15:56:39 +00:00
|
|
|
displayLogLine(log, logger, system, filterServices);
|
2018-10-16 10:25:37 +00:00
|
|
|
});
|
2020-11-07 23:45:03 +00:00
|
|
|
logs.once('error', reject);
|
|
|
|
logs.once('end', () => {
|
|
|
|
logger.logWarn('Connection to device lost');
|
2019-05-13 10:51:41 +00:00
|
|
|
resolve();
|
|
|
|
});
|
2020-11-07 23:45:03 +00:00
|
|
|
process.once('SIGINT', () => logs.emit('close'));
|
|
|
|
process.once('SIGTERM', () => logs.emit('close'));
|
2018-10-16 10:25:37 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function displayBuildLog(log: BuildLog, logger: Logger): void {
|
|
|
|
const toPrint = `${getServiceColourFn(log.serviceName)(
|
|
|
|
`[${log.serviceName}]`,
|
|
|
|
)} ${log.message}`;
|
|
|
|
logger.logBuild(toPrint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// mutates serviceColours
|
2019-04-24 13:59:07 +00:00
|
|
|
function displayLogLine(
|
|
|
|
log: string | Buffer,
|
|
|
|
logger: Logger,
|
2019-04-24 16:30:18 +00:00
|
|
|
system: boolean,
|
2019-05-28 15:56:39 +00:00
|
|
|
filterServices?: string[],
|
2019-04-24 13:59:07 +00:00
|
|
|
): void {
|
2018-10-16 10:25:37 +00:00
|
|
|
try {
|
|
|
|
const obj: Log = JSON.parse(log.toString());
|
2019-05-28 15:56:39 +00:00
|
|
|
displayLogObject(obj, logger, system, filterServices);
|
2019-04-24 10:31:45 +00:00
|
|
|
} catch (e) {
|
|
|
|
logger.logDebug(`Dropping device log due to failed parsing: ${e}`);
|
|
|
|
}
|
|
|
|
}
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2019-04-24 13:59:07 +00:00
|
|
|
export function displayLogObject<T extends Log>(
|
|
|
|
obj: T,
|
|
|
|
logger: Logger,
|
2019-04-24 16:30:18 +00:00
|
|
|
system: boolean,
|
2019-05-28 15:56:39 +00:00
|
|
|
filterServices?: string[],
|
2019-04-24 13:59:07 +00:00
|
|
|
): void {
|
2019-04-24 10:31:45 +00:00
|
|
|
let toPrint: string;
|
|
|
|
if (obj.timestamp != null) {
|
|
|
|
toPrint = `[${new Date(obj.timestamp).toLocaleString()}]`;
|
|
|
|
} else {
|
|
|
|
toPrint = `[${new Date().toLocaleString()}]`;
|
|
|
|
}
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2019-04-24 10:31:45 +00:00
|
|
|
if (obj.serviceName != null) {
|
2019-05-28 15:56:39 +00:00
|
|
|
if (filterServices) {
|
|
|
|
if (!_.includes(filterServices, obj.serviceName)) {
|
2019-04-24 16:30:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (system) {
|
2019-04-24 13:59:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-04-24 16:30:18 +00:00
|
|
|
|
2019-04-24 10:31:45 +00:00
|
|
|
const colourFn = getServiceColourFn(obj.serviceName);
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2019-04-24 10:31:45 +00:00
|
|
|
toPrint += ` ${colourFn(`[${obj.serviceName}]`)}`;
|
2019-05-28 15:56:39 +00:00
|
|
|
} else if (filterServices != null && !system) {
|
2019-04-24 13:59:07 +00:00
|
|
|
// We have a system log here but we are filtering based
|
|
|
|
// on a service, so drop this too
|
|
|
|
return;
|
2019-04-24 10:31:45 +00:00
|
|
|
}
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2019-04-24 10:31:45 +00:00
|
|
|
toPrint += ` ${obj.message}`;
|
2018-10-16 10:25:37 +00:00
|
|
|
|
2019-04-24 10:31:45 +00:00
|
|
|
logger.logLogs(toPrint);
|
2018-10-16 10:25:37 +00:00
|
|
|
}
|
|
|
|
|
2019-04-30 14:55:58 +00:00
|
|
|
export const getServiceColourFn = _.memoize(_getServiceColourFn);
|
2018-10-16 10:25:37 +00:00
|
|
|
|
|
|
|
const colorHash = new ColorHash();
|
|
|
|
function _getServiceColourFn(serviceName: string): (msg: string) => string {
|
|
|
|
const [r, g, b] = colorHash.rgb(serviceName);
|
|
|
|
|
2020-02-28 15:25:12 +00:00
|
|
|
return getChalk().rgb(r, g, b);
|
2018-10-16 10:25:37 +00:00
|
|
|
}
|