Skip to content

Commit fa840b5

Browse files
committed
feat(satellite): add nsjail log parsing and level inference
1 parent bb4fbbc commit fa840b5

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

services/satellite/src/process/manager.ts

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,39 @@ interface BufferedLogEntry {
2727
timestamp: string;
2828
}
2929

30+
/**
31+
* nsjail log pattern: [I|W|E|F][timestamp] message
32+
* Example: [I][2026-01-17T21:02:01+0100] Mode: STANDALONE_ONCE
33+
*/
34+
const NSJAIL_LOG_REGEX = /^\[([IWEF])\]\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{4}\]\s*(.*)$/;
35+
36+
/**
37+
* Parse nsjail log line to extract level and message
38+
* Returns null if line is not an nsjail log
39+
*/
40+
function parseNsjailLog(line: string): { level: string; message: string } | null {
41+
const match = line.match(NSJAIL_LOG_REGEX);
42+
if (!match) return null;
43+
return { level: match[1], message: match[2] };
44+
}
45+
46+
/**
47+
* Infer log level from MCP server log message content
48+
*/
49+
function inferMcpLogLevel(message: string): 'info' | 'warn' | 'error' | 'debug' {
50+
const lower = message.toLowerCase();
51+
if (lower.includes('error') || lower.includes('fatal') || lower.includes('exception') || lower.includes('failed')) {
52+
return 'error';
53+
}
54+
if (lower.includes('warn')) {
55+
return 'warn';
56+
}
57+
if (lower.includes('debug') || lower.includes('trace')) {
58+
return 'debug';
59+
}
60+
return 'info';
61+
}
62+
3063
export class ProcessManager extends EventEmitter {
3164
private processes = new Map<string, ProcessInfo>();
3265
private processIdsByName = new Map<string, string>();
@@ -1062,13 +1095,36 @@ export class ProcessManager extends EventEmitter {
10621095
// Split by newlines in case there are multiple log lines
10631096
const lines = stderrOutput.split('\n');
10641097
for (const line of lines) {
1065-
if (line.trim()) {
1098+
const trimmedLine = line.trim();
1099+
if (!trimmedLine) continue;
1100+
1101+
// Check if this is an nsjail log
1102+
const nsjailLog = parseNsjailLog(trimmedLine);
1103+
1104+
if (nsjailLog) {
1105+
// nsjail log detected - filter out INFO level (infrastructure noise)
1106+
if (nsjailLog.level === 'I') {
1107+
// Skip nsjail INFO logs (Mount, Uid map, Jail parameters, etc.)
1108+
continue;
1109+
}
1110+
// Keep nsjail WARNING/ERROR/FATAL logs with correct level mapping
1111+
const level: 'warn' | 'error' = nsjailLog.level === 'W' ? 'warn' : 'error';
1112+
this.bufferLogEntry({
1113+
installation_id: config.installation_id,
1114+
team_id: config.team_id,
1115+
user_id: config.user_id,
1116+
level,
1117+
message: nsjailLog.message,
1118+
timestamp: new Date().toISOString()
1119+
});
1120+
} else {
1121+
// MCP server log - infer level from content
10661122
this.bufferLogEntry({
10671123
installation_id: config.installation_id,
10681124
team_id: config.team_id,
10691125
user_id: config.user_id,
1070-
level: 'error', // stderr typically contains errors/warnings
1071-
message: line.trim(),
1126+
level: inferMcpLogLevel(trimmedLine),
1127+
message: trimmedLine,
10721128
timestamp: new Date().toISOString()
10731129
});
10741130
}

0 commit comments

Comments
 (0)