kui-shell
Version:
This is the monorepo for Kui, the hybrid command-line/GUI electron-based Kubernetes tool
341 lines • 13.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const debug_1 = require("debug");
const commands_1 = require("@kui-shell/core/api/commands");
const pretty_print_1 = require("@kui-shell/core/api/pretty-print");
const debug = debug_1.default('k8s/util/log-parser');
const timestampFormat = 'short';
const squashLogRuns = (isNotCloudLens, options) => (soFar, logLine) => {
let current;
if (!isNotCloudLens) {
const columns = logLine.split(/\s+/);
const logType = columns[0];
const timestamp = columns[1];
const origin = columns[3];
const rawRest = columns.slice(4).join(' ');
const runLength = 1;
let rest = rawRest;
try {
if (options.asJSON) {
rest = JSON.parse(rawRest);
}
}
catch (err) {
console.error(err);
}
current = {
logType,
timestamp,
origin,
rest,
runLength,
rawTimestamp: timestamp,
provider: ''
};
}
else {
try {
const match = logLine.match(/^([^\s]+)\s+({.*})\s*$/);
if (match) {
const origin = match[1];
const record = match[2];
current = {
logType: 'pair',
origin,
rest: options.asJSON ? JSON.parse(record) : record,
runLength: 1,
timestamp: '',
rawTimestamp: '',
provider: ''
};
}
else {
current = {
logType: 'raw',
rest: logLine,
runLength: 1,
timestamp: '',
rawTimestamp: '',
provider: '',
origin: ''
};
}
}
catch (err) {
current = {
logType: 'raw',
rest: logLine,
runLength: 1,
timestamp: '',
rawTimestamp: '',
provider: '',
origin: ''
};
}
}
const previous = soFar[soFar.length - 1];
if (previous &&
previous.logType &&
previous.logType === current.logType &&
previous.origin === current.origin &&
previous.rest === current.rest) {
previous.runLength++;
}
else {
soFar.push(current);
}
return soFar;
};
function findIndex(A, pattern, startIdx) {
for (let idx = startIdx; idx < A.length; idx++) {
if (A[idx].match(pattern)) {
return idx;
}
}
return -1;
}
const parseZapr = (raw) => {
const pattern = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+Z)\s+(DEBUG|INFO|ERROR)\s+([^\s]+)\s+([^\s]+)\s+(.*)$/m;
const records = raw.split(pattern).filter(x => x !== '\n');
const lines = [];
let idx = 0;
while (true) {
const nextIdx = findIndex(records, /(DEBUG|INFO|ERROR)/, idx);
if (nextIdx >= idx + 1) {
const startIdx = nextIdx - 1;
for (let preIdx = idx; preIdx < startIdx; preIdx++) {
const maybe = records[preIdx].match(/^\n?(\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2})\s+(.*)\n$/);
if (maybe) {
lines.push({
timestamp: maybe[1],
logType: 'INFO',
provider: '',
origin: '',
rest: maybe[2]
});
}
else {
lines.push({
timestamp: '',
logType: 'INFO',
provider: '',
origin: '',
rest: records[preIdx].replace(/^\n(.*)\n$/, '$1')
});
}
}
lines.push({
timestamp: records[startIdx],
logType: records[startIdx + 1],
provider: records[startIdx + 2],
origin: records[startIdx + 3],
rest: records[startIdx + 4]
});
idx = startIdx + 5;
}
else {
break;
}
}
debug('zapr?', lines.length > 0, lines);
return lines.length > 0 && lines;
};
const parseCloudLens = (raw, execOptions, options) => {
const pattern = /^(?=[IEF][0-9]+)/m;
const linesByCloudLens = raw.split(pattern);
return linesByCloudLens
.slice(Math.max(0, linesByCloudLens.length - 1000))
.filter(x => x)
.filter(x => x.indexOf('Watch close') < 0)
.reverse()
.reduce(squashLogRuns(false, options), []);
};
const parseIstio = (raw, execOptions) => {
let prevTimestamp;
return raw
.split(/[\n\r]/)
.map(line => {
try {
const record = JSON.parse(line);
const timestamp = record.time || record.timestamp || record.date;
const logType = record.level || record.logType || '';
const origin = record.instance || record.provider || record.caller || '';
const zapr = {
timestamp: timestamp
? pretty_print_1.prettyPrintTime(timestamp, timestampFormat, prevTimestamp, commands_1.default.withLanguage(execOptions))
: '',
rawTimestamp: timestamp,
logType,
provider: record.logger,
origin,
rest: record.msg || record
};
if (timestamp) {
prevTimestamp = timestamp;
}
return zapr;
}
catch (err) {
const pattern1 = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\s+([^\s]+)\s+([\s\S]*)$/;
let match = line.split(pattern1);
const timestampIndex = 1;
let logTypeIndex = 2;
let restIndex = 3;
let originIndex;
let providerIndex;
if (!match || match.length === 1) {
const pattern2 = /^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\]\[(\d+)\]\[(.*)\]\[(.*)\]\s+(.*:\d+)\]\s+(.*)$/;
match = line.split(pattern2);
if (match && match.length > 1) {
logTypeIndex = 3;
originIndex = 5;
providerIndex = 4;
restIndex = 6;
}
else {
const pattern3 = /^\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\]\s+"([^"]+)"\s+(\d+)\s+(.*)$/;
match = line.split(pattern3);
logTypeIndex = -1;
originIndex = 2;
providerIndex = 3;
restIndex = 4;
}
}
const timestamp = (match && match[timestampIndex]) || '';
const logType = (match && match[logTypeIndex]) || 'info';
const origin = (match && match[originIndex]) || '';
const provider = (match && match[providerIndex]) || '';
const rest = (match && match[restIndex]) || line;
const zapr = {
timestamp: timestamp && pretty_print_1.prettyPrintTime(timestamp, timestampFormat, prevTimestamp, commands_1.default.withLanguage(execOptions)),
rawTimestamp: timestamp,
logType,
provider,
origin,
rest
};
if (timestamp) {
prevTimestamp = timestamp;
}
return zapr;
}
})
.reduce((lines, line, idx) => {
if (idx > 0) {
const prevLine = lines[lines.length - 1];
if (line.origin === prevLine.origin &&
line.provider === prevLine.provider &&
line.rawTimestamp !== undefined &&
line.rawTimestamp === prevLine.rawTimestamp) {
debug('concat');
prevLine.rest = `${prevLine.rest}\n${line.rest}`;
}
else {
lines.push(line);
}
}
else {
lines.push(line);
}
return lines;
}, []);
};
const notEmpty = (_) => _.timestamp || _.rest || _.origin || _.provider;
exports.formatLogs = (raw, execOptions, options = { asHTML: true }) => {
const logEntries = parseZapr(raw) || parseIstio(raw, execOptions) || parseCloudLens(raw, execOptions, options);
debug('logEntries', logEntries);
if (!options.asHTML) {
return logEntries;
}
else {
const container = document.createElement('div');
container.classList.add('log-lines');
const doWeHaveAnyFirstColumns = logEntries.findIndex(_ => !!(_.timestamp || _.origin || _.provider || _.runLength > 1)) >= 0;
logEntries
.filter(notEmpty)
.forEach(({ logType = '', timestamp = '', origin = '', provider = '', rest, runLength = 1 }) => {
const logLine = document.createElement('div');
logLine.classList.add('log-line');
container.appendChild(logLine);
if (logType.match(/^I/) || logType.match(/^INFO$/i)) {
logLine.classList.add('logged-to-stdout');
}
else if (logType.match(/^[EF]/) || logType.match(/^(ERROR|WARN)/i)) {
logLine.classList.add('logged-to-stderr');
}
if (doWeHaveAnyFirstColumns) {
const timestampDom = document.createElement('td');
timestampDom.className = 'log-field log-date entity-name-group hljs-attribute';
if (typeof timestamp === 'string') {
const inner = document.createElement('span');
inner.innerText = timestamp;
timestampDom.appendChild(inner);
}
else {
timestampDom.appendChild(timestamp);
}
logLine.appendChild(timestampDom);
if (origin) {
const originDom = document.createElement('span');
originDom.className = 'entity-name';
originDom.innerText = origin ? origin.replace(/]$/, '') : '';
timestampDom.appendChild(originDom);
}
if (provider) {
const providerDom = document.createElement('span');
providerDom.className = 'entity-name provider-name';
providerDom.innerText = provider ? provider.replace(/]$/, '') : '';
timestampDom.appendChild(providerDom);
}
if (runLength > 1) {
const runLengthDom = document.createElement('div');
runLengthDom.innerText = `(${runLength} times)`;
runLengthDom.classList.add('small-top-pad');
runLengthDom.classList.add('red-text');
timestampDom.appendChild(runLengthDom);
}
}
const restDom = document.createElement('td');
restDom.className = 'log-field log-message slightly-smaller-text';
if (typeof rest === 'object') {
const pre = document.createElement('pre');
const code = document.createElement('code');
code.innerText = JSON.stringify(rest, undefined, 2);
pre.appendChild(code);
restDom.appendChild(pre);
}
else {
const pre = document.createElement('pre');
pre.classList.add('pre-wrap');
pre.classList.add('break-all');
restDom.appendChild(pre);
const trySplit = rest.split(/^(.*:)(\s+.*)?$/);
if (trySplit && trySplit.length > 1) {
const a = document.createElement('span');
a.classList.add('map-key');
a.innerText = trySplit[1];
pre.appendChild(a);
if (trySplit[2]) {
const b = document.createElement('span');
b.classList.add('map-value');
b.innerText = trySplit[2];
pre.appendChild(b);
}
}
else {
pre.innerText = rest;
}
}
logLine.appendChild(restDom);
});
const wrapper = document.createElement('div');
wrapper.classList.add('padding-content');
wrapper.classList.add('scrollable');
wrapper.classList.add('scrollable-auto');
wrapper.classList.add('monospace');
wrapper.classList.add('smaller-text');
wrapper.appendChild(container);
return wrapper;
}
};
//# sourceMappingURL=log-parser.js.map