@@ -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 = / ^ \[ ( [ I W E F ] ) \] \[ \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+
3063export 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