Repository URL to install this package:
|
Version:
0.0.0-2ff56cc5f81b9d ▾
|
#!/usr/bin/env node
const readline = require('readline');
const level = require('./level');
const options = require('./options');
const genericFormatter = require('./component/background-text');
const severityComp = require('./component/severity');
const messageComp = require('./component/message');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
const printDefaultLayout = (log, normalizedSeverity) => {
const separator = genericFormatter.format('-', normalizedSeverity);
const severity = severityComp.format(normalizedSeverity);
const instant = genericFormatter.format(log.apptime, normalizedSeverity);
const message = messageComp.format(log.message, normalizedSeverity);
const clazz = genericFormatter.format(log.class, normalizedSeverity);
const thread = genericFormatter.format(log.thread, normalizedSeverity);
const pod = genericFormatter.format(log.pod, normalizedSeverity);
const container = genericFormatter.format(log.container, normalizedSeverity);
let prettyLog = log.pod ? `${pod} ${separator} ${container}\n` : ``;
prettyLog += `${instant} ${separator} ${clazz} ${separator} ${thread}\n`;
prettyLog += `${severity} ${message}\n`;
if (log.exceptionMessage) {
prettyLog += `${genericFormatter.format(log.exceptionMessage, normalizedSeverity)}\n`;
}
if (log.exceptionCausedBy) {
prettyLog += `${genericFormatter.format(`Caused by: ${log.exceptionCausedBy}`, normalizedSeverity)}\n`;
}
if (log.exceptionClassMethodLine) {
prettyLog += `${genericFormatter.format(log.exceptionClassMethodLine, normalizedSeverity)}\n`
}
prettyLog += `\n`;
console.log(prettyLog)
}
/**
* Normalize the log values to support multiple logging formats.
*
* @param {Object} logObj - The JSON object returned from the logger
* @param {String} podName - The name of the K8 pod, if available
* @param {String} containerName - The name of the K8 container, if available
* @returns {Object}
*/
const normalizeLog = (logObj, podName, containerName) => {
const { message, hostName, apptime, loggerName, thread, threadName, ex, exception, severity, level } = logObj;
const log = {
/** @type {String} - The timestamt string */
apptime: apptime || logObj['@timestamp'],
/** @type {String} - The class, caller or logger name */
class: logObj.class || loggerName,
/** @type {String} - The thread name */
thread: thread || threadName,
/** @type {String} - The log level, i.e., error|info|trace|debug */
severity: severity || level,
/** @type {String} - The name of the pod where the logs are running */
pod: podName || hostName || '',
/** @type {String} - The name of the container where the logs are running */
container: containerName || '',
/** @type {Object} - The raw exception object */
exception: ex || exception,
/** @type {String} - The exception.message string */
exceptionMessage: null,
/** @type {String} - The exception.causedBy.exception.message string */
exceptionCausedBy: null,
/** @type {String} - A string consisting of the class:method:line where the exception occured */
exceptionClassMethodLine: null,
/** @type {String} - The message string */
message,
}
// Pull the exception message out of the exception object, if it exists
if (log.exception && log.exception.message) {
log.exceptionMessage = log.exception.message;
}
// Pull the exception stack trace and causedBy reasons out of the exception, if present
if (log.exception && log.exception.causedBy && log.exception.causedBy.exception) {
const firstStackTraceFrame = Array.isArray(log.exception.causedBy.exception.frames) && log.exception.causedBy.exception.frames.length > 0 && log.exception.causedBy.exception.frames.shift();
if (firstStackTraceFrame) {
const { method, line } = firstStackTraceFrame;
log.exceptionClassMethodLine = `${firstStackTraceFrame.class}:${method}:${line}`;
}
log.exceptionCausedBy = log.exception.causedBy.exception.message;
}
// Normalize the severity, if it exists
if (log.severity) {
log.severity = log.severity.trim().toLowerCase();
}
return log;
}
rl.on('line', function (line) {
let log;
try {
// stern default pattern: {pod-name} {container-name} {log-message}
const matches = line.match(/^([\w\d-_]+) ([\w\d-_]+) (\{.+\})$/);
const pod = matches ? matches[1] : undefined;
const container = matches ? matches[2] : undefined;
const json = matches ? line.replace(pod, '').replace(container, '').trim() : line;
log = normalizeLog(JSON.parse(json), pod, container);
// If include is set, only show messages that match the patterns supplied.
// For example dlog --include="foo" --include="bar"
if (options.include) {
if (!log || !log.message) return;
const messageContainsKeys = options.include.some(key => log.message.search(key) > -1)
if (!messageContainsKeys) {
return;
}
}
if (options.local) {
log.apptime = new Date(log.apptime).toLocaleString();
} else if (options.utc) {
log.apptime = new Date(log.apptime).toUTCString();
}
} catch (e) {
// the SpringBoot banner is not a valid JSON, but we can ignore it here
// console.log(e);
return;
}
const normalizedSeverity = log.severity;
if (!level.shouldDisplay(normalizedSeverity, options.minimumSeverityToDisplay)) {
return;
}
printDefaultLayout(log, normalizedSeverity);
});