Skip to content

Instantly share code, notes, and snippets.

@joshhunt
Created April 23, 2024 09:38
Show Gist options
  • Save joshhunt/3b21c18412ff72c5ad4e281cbf734125 to your computer and use it in GitHub Desktop.
Save joshhunt/3b21c18412ff72c5ad4e281cbf734125 to your computer and use it in GitHub Desktop.
import readline from "node:readline";
import chalk from "chalk";
const rl = readline.createInterface({
input: process.stdin,
});
rl.on("line", (line) => {
const parsed = maybeJSON(line);
if (!parsed) {
process.stdout.write(line + "\n");
return;
}
const { level, logger, msg, t, ...rest } = parsed;
if (level === "info" && logger === "context" && msg === "Request Completed") {
process.stdout.write(formatHttpRequest(parsed) + "\n");
return;
}
const simpleProps: [string, string][] = [];
const multiLineProps: [string, string][] = [];
for (const [key, value] of Object.entries(rest)) {
if (typeof value === "string" && value.includes("\n")) {
multiLineProps.push([key, value]);
} else {
simpleProps.push([key, value]);
}
}
const simplePropsMessage = simpleProps
.map(([key, value]) => formatKeyValue(key, value))
.join(" ");
const fLevel = level ? formatLevel(level) : undefined;
const fLogger = logger ? formatLogger(logger) : undefined;
let rightFormattedLine = [msg, simplePropsMessage].filter(Boolean).join(" ");
if (
level === "info" &&
logger === "http.server" &&
msg === "HTTP Server Listen"
) {
rightFormattedLine = chalk.black.bgGreen(rightFormattedLine);
}
let formattedLine = [fLevel, fLogger, rightFormattedLine]
.filter(Boolean)
.join(" ");
process.stdout.write(formattedLine + "\n");
if (multiLineProps.length > 0) {
for (const [key, value] of multiLineProps) {
process.stdout.write(formatIndentedKeyValue(key, value) + "\n");
}
}
});
const maybeJSON = (line: string): Record<string, string> | undefined => {
try {
return JSON.parse(line);
} catch (e) {
return undefined;
}
};
function formatHttpRequest(log: Record<string, string>) {
const { level, duration, path, method, status, handler, ...rest } = log;
const fLevel = formatLevel(level === "info" ? "http" : level);
const fMethod = formatLogger(method);
return [
fLevel,
fMethod,
formatStatusCode(status),
path,
formatKeyValue("duration", duration),
formatKeyValue("handler", handler),
].join(" ");
}
function formatStatusCode(_status: string | number) {
const status = typeof _status === "string" ? parseInt(_status) : _status;
if (status >= 500) {
return chalk.red(status);
} else if (status >= 400) {
return chalk.yellow(status);
} else if (status >= 300) {
return chalk.cyan(status);
} else if (status >= 200) {
return chalk.green(status);
} else {
return status;
}
}
function formatLevel(level: string) {
const levelLower = level.toLowerCase();
switch (levelLower) {
case "http":
return chalk.black.bgBlueBright(" HTTP ");
case "debug":
return chalk.black.bgBlue(" DBUG ");
case "info":
return chalk.black.bgGreen(" INFO ");
case "warn":
return chalk.black.bgYellow(" WARN ");
case "error":
return chalk.black.bgRed(" ERRR ");
default:
return level;
}
}
function formatKeyValue(key: string, value: string) {
const fKey = chalk.dim(`${key}`);
const fEqual = chalk.dim("=");
const fValue = chalk.dim(value);
return fKey + fEqual + fValue;
}
function formatIndentedKeyValue(key: string, value: string) {
const firstIndent = 6;
const subsequentIndents = firstIndent + key.length + 1;
const fKey = chalk.grey(`${key}`);
const fEqual = chalk.grey("=");
const [firstLine, ...lines] = value.split("\n");
let output =
" ".repeat(firstIndent) + fKey + fEqual + chalk.dim(firstLine) + "\n";
for (const line of lines) {
output += " ".repeat(subsequentIndents) + chalk.dim(line) + "\n";
}
// process.stdout.write(` ${formatKeyValue(key, value)}\n`);
return output;
}
const LOGGER_COLORS = ["magenta", "cyan", "blue", "yellow"] as const;
function formatLogger(logger: string) {
const hash = hashCode(logger);
const index = hash % LOGGER_COLORS.length;
return chalk[LOGGER_COLORS[index]](`[${logger}]`);
}
function hashCode(str: string) {
let hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
return Math.abs(hash);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment