@@ -70,7 +70,7 @@ export function parseErrorLogLine(line: string, index: number): ParsedLogEntry |
7070
7171 if ( ! match ) return null ;
7272
73- const [ , timeStr , levelStr , message ] = match ;
73+ const [ , timeStr , levelStr , fullMessageText ] = match ;
7474
7575 // Parse time: 2025/03/29 14:35:18
7676 const timestamp = timeStr . replace ( / \/ / g, '-' ) . replace ( ' ' , 'T' ) + 'Z' ;
@@ -89,16 +89,23 @@ export function parseErrorLogLine(line: string, index: number): ParsedLogEntry |
8989 const level = levelMap [ levelStr ] || 'error' ;
9090
9191 // Extract IP if present
92- const ipMatch = message . match ( / c l i e n t : ( [ \d . ] + ) / ) ;
92+ const ipMatch = fullMessageText . match ( / c l i e n t : ( [ \d . ] + ) / ) ;
9393 const ip = ipMatch ? ipMatch [ 1 ] : undefined ;
9494
95+ // Check if this is a ModSecurity error log entry
96+ if ( fullMessageText . includes ( 'ModSecurity:' ) ) {
97+ // Use ModSecurity parser for better extraction
98+ return parseModSecLogLine ( line , index ) ;
99+ }
100+
95101 return {
96102 id : `error_${ Date . now ( ) } _${ index } ` ,
97103 timestamp,
98104 level,
99105 type : 'error' ,
100106 source : 'nginx' ,
101- message : message . substring ( 0 , 200 ) , // Truncate long messages
107+ message : fullMessageText . substring ( 0 , 500 ) , // Show more context but still truncate for display
108+ fullMessage : fullMessageText , // Store complete message
102109 ip
103110 } ;
104111 } catch ( error ) {
@@ -109,7 +116,7 @@ export function parseErrorLogLine(line: string, index: number): ParsedLogEntry |
109116
110117/**
111118 * Parse ModSecurity audit log line
112- * Format varies, look for key patterns
119+ * Format varies, look for key patterns and extract all relevant fields
113120 */
114121export function parseModSecLogLine ( line : string , index : number ) : ParsedLogEntry | null {
115122 try {
@@ -134,36 +141,91 @@ export function parseModSecLogLine(line: string, index: number): ParsedLogEntry
134141 }
135142 }
136143
137- // Extract message
144+ // Extract Rule ID - [id "942100"]
145+ const ruleIdMatch = line . match ( / \[ i d " ( [ ^ " ] + ) " \] / ) ;
146+ const ruleId = ruleIdMatch ? ruleIdMatch [ 1 ] : undefined ;
147+
148+ // Extract message (msg) - [msg "SQL Injection Attack Detected via libinjection"]
138149 const msgMatch = line . match ( / \[ m s g " ( [ ^ " ] + ) " \] / ) ;
139- const message = msgMatch ? msgMatch [ 1 ] : line . substring ( 0 , 200 ) ;
150+ const message = msgMatch ? msgMatch [ 1 ] : 'ModSecurity Alert' ;
140151
141- // Extract IP
142- const ipMatch = line . match ( / \[ c l i e n t ( [ \d . ] + ) \] / ) || line . match ( / \[ h o s t n a m e " ( [ \d . ] + ) " \] / ) ;
143- const ip = ipMatch ? ipMatch [ 1 ] : undefined ;
152+ // Extract severity - [severity "2"]
153+ const severityMatch = line . match ( / \[ s e v e r i t y " ( [ ^ " ] + ) " \] / ) ;
154+ const severity = severityMatch ? severityMatch [ 1 ] : undefined ;
155+
156+ // Extract all tags - [tag "application-multi"] [tag "language-multi"] ...
157+ const tagMatches = line . matchAll ( / \[ t a g " ( [ ^ " ] + ) " \] / g) ;
158+ const tags : string [ ] = [ ] ;
159+ for ( const match of tagMatches ) {
160+ tags . push ( match [ 1 ] ) ;
161+ }
162+
163+ // Extract IP - from [client 52.186.182.85] or [hostname "10.0.0.203"]
164+ const clientIpMatch = line . match ( / \[ c l i e n t ( [ \d . ] + ) \] / ) ;
165+ const hostnameMatch = line . match ( / \[ h o s t n a m e " ( [ ^ " ] + ) " \] / ) ;
166+ const ip = clientIpMatch ? clientIpMatch [ 1 ] : ( hostnameMatch ? hostnameMatch [ 1 ] : undefined ) ;
144167
145- // Extract request info
168+ // Extract URI - [uri "/device.rsp"]
169+ const uriMatch = line . match ( / \[ u r i " ( [ ^ " ] + ) " \] / ) ;
170+ const uri = uriMatch ? uriMatch [ 1 ] : undefined ;
171+
172+ // Extract unique ID - [unique_id "176094161071.529267"]
173+ const uniqueIdMatch = line . match ( / \[ u n i q u e _ i d " ( [ ^ " ] + ) " \] / ) ;
174+ const uniqueId = uniqueIdMatch ? uniqueIdMatch [ 1 ] : undefined ;
175+
176+ // Extract file - [file "/etc/nginx/modsec/coreruleset/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"]
177+ const fileMatch = line . match ( / \[ f i l e " ( [ ^ " ] + ) " \] / ) ;
178+ const file = fileMatch ? fileMatch [ 1 ] : undefined ;
179+
180+ // Extract line number - [line "46"]
181+ const lineMatch = line . match ( / \[ l i n e " ( [ ^ " ] + ) " \] / ) ;
182+ const lineNumber = lineMatch ? lineMatch [ 1 ] : undefined ;
183+
184+ // Extract data field if present - [data "..."]
185+ const dataMatch = line . match ( / \[ d a t a " ( [ ^ " ] + ) " \] / ) ;
186+ const data = dataMatch ? dataMatch [ 1 ] : undefined ;
187+
188+ // Extract request info from log line
146189 const methodMatch = line . match ( / " ( G E T | P O S T | P U T | D E L E T E | P A T C H | H E A D | O P T I O N S ) ( [ ^ " ] + ) " / ) ;
147190 const method = methodMatch ? methodMatch [ 1 ] : undefined ;
148- const path = methodMatch ? methodMatch [ 2 ] : undefined ;
191+ const path = methodMatch ? methodMatch [ 2 ] : ( uri || undefined ) ;
149192
150- // Determine level
193+ // Determine level based on content
151194 let level : 'info' | 'warning' | 'error' = 'warning' ;
152195 if ( line . includes ( 'Access denied' ) || line . includes ( 'blocked' ) ) {
153196 level = 'error' ;
197+ } else if ( line . includes ( 'Warning' ) ) {
198+ level = 'warning' ;
154199 }
155200
201+ // Extract status code
202+ const statusMatch = line . match ( / w i t h c o d e ( \d + ) / ) ;
203+ const statusCode = statusMatch ? parseInt ( statusMatch [ 1 ] ) : undefined ;
204+
205+ // Store full message without truncation
206+ const fullMessage = line ;
207+
156208 return {
157209 id : `modsec_${ Date . now ( ) } _${ index } ` ,
158210 timestamp,
159211 level,
160212 type : 'error' ,
161213 source : 'modsecurity' ,
162214 message : `ModSecurity: ${ message } ` ,
215+ fullMessage, // Complete log without truncation
163216 ip,
164217 method,
165218 path,
166- statusCode : line . includes ( '403' ) ? 403 : undefined
219+ statusCode,
220+ // ModSecurity specific fields
221+ ruleId,
222+ severity,
223+ tags,
224+ uri,
225+ uniqueId,
226+ file,
227+ line : lineNumber ,
228+ data
167229 } ;
168230 } catch ( error ) {
169231 logger . warn ( `Failed to parse ModSecurity log line: ${ line } ` ) ;
0 commit comments