Skip to content

Commit 1b8b77c

Browse files
HeeManSuviferga
andauthored
Workers coloring implementation. (#47)
* added asni color to deployment name * Code refractored * Log Queue implemented * refractoring * used PID as identifier --------- Co-authored-by: Vicente Eduardo Ferrer Garcia <[email protected]>
1 parent 29b50ff commit 1b8b77c

File tree

5 files changed

+126
-15
lines changed

5 files changed

+126
-15
lines changed

src/api.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,8 @@ export const deploy = catchAsync(
246246
currentFile
247247
});
248248

249-
logProcessOutput(proc.stdout, 'green');
250-
logProcessOutput(proc.stderr, 'red');
249+
logProcessOutput(proc.stdout, proc.pid, currentFile.id);
250+
logProcessOutput(proc.stderr, proc.pid, currentFile.id);
251251

252252
proc.on('message', (data: childProcessResponse) => {
253253
if (data.type === protocol.g) {

src/constants.ts

+23
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,26 @@ export interface childProcessResponse {
118118
export interface InspectObject {
119119
[key: string]: Array<{ name: string }>;
120120
}
121+
export interface LogMessage {
122+
deploymentName: string;
123+
workerPID: number;
124+
message: string;
125+
}
126+
127+
export const asniCode: number[] = [
128+
166, 154, 142, 118, 203, 202, 190, 215, 214, 32, 6, 4, 220, 208, 184, 172
129+
];
130+
131+
export interface PIDToColorCodeMapType {
132+
[key: string]: number;
133+
}
134+
135+
export interface AssignedColorCodesType {
136+
[key: string]: boolean;
137+
}
138+
139+
// Maps a PID to a color code
140+
export const PIDToColorCodeMap: PIDToColorCodeMapType = {};
141+
142+
// Tracks whether a color code is assigned
143+
export const assignedColorCodes: AssignedColorCodesType = {};

src/utils/autoDeploy.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export const findJsonFilesRecursively = async (
3636
currentFile
3737
});
3838

39-
logProcessOutput(proc.stdout, 'green');
40-
logProcessOutput(proc.stderr, 'red');
39+
logProcessOutput(proc.stdout, proc.pid, currentFile.id);
40+
logProcessOutput(proc.stderr, proc.pid, currentFile.id);
4141

4242
proc.on('message', (data: childProcessResponse) => {
4343
if (data.type === protocol.g) {

src/utils/logger.ts

+61-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,75 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3+
import { LogMessage } from '../constants';
4+
import { assignColorToWorker } from './utils';
35

46
const logFilePath = path.join(__dirname, '../../logs/');
57
const logFileName = 'app.log';
68
const logFileFullPath = path.join(logFilePath, logFileName);
79

8-
export const logger = {
9-
log: (message: string): void => {
10+
class Logger {
11+
private logQueue: LogMessage[] = [];
12+
private isProcessing = false;
13+
14+
private async processQueue(): Promise<void> {
15+
if (this.isProcessing || this.logQueue.length === 0) return;
16+
this.isProcessing = true;
17+
18+
while (this.logQueue.length > 0) {
19+
const logEntry = this.logQueue.shift();
20+
if (logEntry) {
21+
const { deploymentName, workerPID, message } = logEntry;
22+
this.store(deploymentName, message);
23+
this.present(deploymentName, workerPID, message);
24+
await new Promise(resolve => setTimeout(resolve, 0));
25+
}
26+
}
27+
28+
this.isProcessing = false;
29+
}
30+
31+
public enqueueLog(
32+
deploymentName: string,
33+
workerPID: number,
34+
message: string
35+
): void {
36+
this.logQueue.push({ deploymentName, workerPID, message });
37+
this.processQueue().catch(console.error);
38+
}
39+
40+
private store(deploymentName: string, message: string): void {
1041
const timeStamp = new Date().toISOString();
11-
const logMessage = `${timeStamp} - ${message}\n`;
12-
console.log(message);
42+
const logMessage = `${timeStamp} - ${deploymentName} | ${message}\n`;
1343

1444
if (!fs.existsSync(logFilePath)) {
1545
fs.mkdirSync(logFilePath, { recursive: true });
1646
}
1747
fs.appendFileSync(logFileFullPath, logMessage, { encoding: 'utf-8' });
1848
}
19-
};
49+
50+
private present(
51+
deploymentName: string,
52+
workerPID: number,
53+
message: string
54+
): void {
55+
message = message.trim();
56+
const fixedWidth = 24;
57+
58+
let paddedName = deploymentName.padEnd(fixedWidth, ' ');
59+
if (deploymentName.length > fixedWidth) {
60+
paddedName = deploymentName.substring(0, fixedWidth - 2) + '_1';
61+
}
62+
63+
// Regular expression for splitting by '\n', '. ', or ' /'
64+
const messageLines = message.split(/(?:\n|\. | \/)/);
65+
const coloredName = assignColorToWorker(`${paddedName} |`, workerPID);
66+
const formattedMessageLines = messageLines.map(
67+
line => `${coloredName} ${line}`
68+
);
69+
const logMessage = formattedMessageLines.join('\n');
70+
71+
console.log(logMessage);
72+
}
73+
}
74+
75+
export const logger = new Logger();

src/utils/utils.ts

+38-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import { platform } from 'os';
44
import { join } from 'path';
55

66
import { LanguageId, MetaCallJSON } from '@metacall/protocol/deployment';
7-
import { generatePackage, PackageError } from '@metacall/protocol/package';
7+
import { PackageError, generatePackage } from '@metacall/protocol/package';
88
import { NextFunction, Request, RequestHandler, Response } from 'express';
99

1010
import {
11-
createInstallDependenciesScript,
12-
currentFile,
1311
IAllApps,
14-
InspectObject
12+
InspectObject,
13+
PIDToColorCodeMap,
14+
allApplications,
15+
asniCode,
16+
assignedColorCodes,
17+
createInstallDependenciesScript,
18+
currentFile
1519
} from '../constants';
1620
import { logger } from './logger';
1721

@@ -147,9 +151,37 @@ export function isIAllApps(data: unknown): data is IAllApps {
147151

148152
export function logProcessOutput(
149153
proc: NodeJS.ReadableStream | null,
150-
color: 'green' | 'red'
154+
workerPID: number | undefined,
155+
deploymentName: string
151156
): void {
152157
proc?.on('data', (data: Buffer) => {
153-
logger.log(data.toString()[color]);
158+
logger.enqueueLog(deploymentName, workerPID || 0, data.toString());
154159
});
155160
}
161+
162+
export const maxWorkerWidth = (maxIndexWidth = 3): number => {
163+
const workerLengths = Object.keys(allApplications).map(
164+
worker => worker.length
165+
);
166+
return Math.max(...workerLengths) + maxIndexWidth;
167+
};
168+
169+
export const assignColorToWorker = (
170+
deploymentName: string,
171+
workerPID: number
172+
): string => {
173+
if (!PIDToColorCodeMap[workerPID]) {
174+
let colorCode: number;
175+
176+
// Keep looking for unique code
177+
do {
178+
colorCode = asniCode[Math.floor(Math.random() * asniCode.length)];
179+
} while (assignedColorCodes[colorCode]);
180+
181+
// Assign the unique code and mark it as used
182+
PIDToColorCodeMap[workerPID] = colorCode;
183+
assignedColorCodes[colorCode] = true;
184+
}
185+
const assignColorCode = PIDToColorCodeMap[workerPID];
186+
return `\x1b[38;5;${assignColorCode}m${deploymentName}\x1b[0m`;
187+
};

0 commit comments

Comments
 (0)