UNPKG

kui-shell

Version:

This is the monorepo for Kui, the hybrid command-line/GUI electron-based Kubernetes tool

341 lines 13.1 kB
"use strict"; 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