@metacall/faas
Version:
Reimplementation of MetaCall FaaS platform written in TypeScript.
116 lines (115 loc) • 4.82 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.logProcessOutput = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ANSICode = [
166, 154, 142, 118, 203, 202, 190, 215, 214, 32, 6, 4, 220, 208, 184, 172
];
// Maps a PID to a color code
const PIDToColorCodeMap = {};
// Tracks whether a color code is assigned
const assignedColorCodes = {};
const logFilePath = path.join(__dirname, '../../logs/');
const logFileName = 'app.log';
const logFileFullPath = path.resolve(path.join(logFilePath, logFileName));
// TODO: Implement this properly?
// const maxWorkerWidth = (maxIndexWidth = 3): number => {
// const workerLengths = Object.keys(Applications).map(
// worker => worker.length
// );
// return Math.max(...workerLengths) + maxIndexWidth;
// };
// TODO: There is a problem with this code, looking randomly for an unique code
// will end in an endless loop whenever all color codes are allocated, we should
// use a better way of managing this
const assignColorToWorker = (deploymentName, workerPID) => {
if (!PIDToColorCodeMap[workerPID]) {
let colorCode;
// Keep looking for unique code
do {
colorCode = ANSICode[Math.floor(Math.random() * ANSICode.length)];
} while (assignedColorCodes[colorCode]);
// Assign the unique code and mark it as used
PIDToColorCodeMap[workerPID] = colorCode;
assignedColorCodes[colorCode] = true;
}
const assignColorCode = PIDToColorCodeMap[workerPID];
return `\x1b[38;5;${assignColorCode}m${deploymentName}\x1b[0m`;
};
class Logger {
constructor() {
this.logQueue = [];
this.isProcessing = false;
}
async processQueue() {
if (this.isProcessing || this.logQueue.length === 0)
return;
this.isProcessing = true;
while (this.logQueue.length > 0) {
const logEntry = this.logQueue.shift();
if (logEntry) {
const { deploymentName, workerPID, message } = logEntry;
this.store(deploymentName, message);
this.present(deploymentName, workerPID, message);
await new Promise(resolve => setTimeout(resolve, 0));
}
}
this.isProcessing = false;
}
enqueueLog(deploymentName, workerPID, message) {
this.logQueue.push({ deploymentName, workerPID, message });
this.processQueue().catch(console.error);
}
store(deploymentName, message) {
const timeStamp = new Date().toISOString();
const logMessage = `${timeStamp} - ${deploymentName} | ${message}\n`;
if (!fs.existsSync(logFilePath)) {
fs.mkdirSync(logFilePath, { recursive: true });
}
fs.appendFileSync(logFileFullPath, logMessage, { encoding: 'utf-8' });
}
present(deploymentName, workerPID, message) {
message = message.trim();
const fixedWidth = 24;
let paddedName = deploymentName.padEnd(fixedWidth, ' ');
if (deploymentName.length > fixedWidth) {
paddedName = deploymentName.substring(0, fixedWidth - 2) + '_1';
}
// Regular expression for splitting by '\n', '. ', or ' /'
const messageLines = message.split(/(?:\n|\. | \/)/);
const coloredName = assignColorToWorker(`${paddedName} |`, workerPID);
const formattedMessageLines = messageLines.map(line => `${coloredName} ${line}`);
const logMessage = formattedMessageLines.join('\n');
console.log(logMessage);
}
}
const logger = new Logger();
function logProcessOutput(proc, deploymentName) {
proc.stdout?.on('data', (data) => {
logger.enqueueLog(deploymentName, proc.pid || 0, data.toString());
});
proc.stderr?.on('data', (data) => {
logger.enqueueLog(deploymentName, proc.pid || 0, data.toString());
});
}
exports.logProcessOutput = logProcessOutput;