diff --git a/parser.js b/parser.js index c7fef26..d9e2518 100644 --- a/parser.js +++ b/parser.js @@ -6,8 +6,8 @@ const RXS = { "pri" : /^<\d+>/, "prinmr" : /^\d+ /, "prival" : /<(\d+)>/, - "month" : /^[A-Za-z][a-z]{2} /, - "day" : /^\d{1,2} /, + "month" : /^[A-Za-z]{3} /, + "day" : /^\d{1,2}/, "time" : /^\d+:\d+:\d+ /, "ts" : /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\S+ /, "invalid" : /[^a-zA-Z0-9\.\$\-_#%\/\[\]\(\)]/, @@ -24,7 +24,12 @@ const DOPS = { generateTimestamp: true } -function peek(arr) { +/** + * Removes the first non whitespace item from the array and returns the item + * @param {string[]} arr the array to shift the item from + * @returns the first non whitespace item of the array + */ +function shiftItem(arr) { do { var item = arr.shift(); if(item===undefined) return item; @@ -34,6 +39,21 @@ function peek(arr) { return item; } +/** + * Gets the first non whitespace item from the array without mutating the array + * @param {string[]} arr the array to peek for the first item + * @returns the first non whitespace item of the array + */ +function peekItem(arr) { + for (const item of arr) { + let trimmedItem = item.trim(); + if (trimmedItem) { + return trimmedItem; + } + } + return undefined; +} + function assign(entry,item) { if(!entry.host) entry.host = item.trim(); else if(!entry.appName) entry.appName = item.trim(); @@ -78,33 +98,34 @@ function parse(line,opts) { // Date search var endparse = false; while(line.length && !endparse) { - var item = peek(items)+" "; + var item = shiftItem(items)+" "; + var nextItem = peekItem(items); // RFC RFC5424 if(item.match(RXS.prinmr)) { entry.version = parseInt(item); entry.type = "RFC5424"; - item = peek(items)+" "; + item = shiftItem(items)+" "; if(item.match(RXS.ts)) { entry.ts = new Date(Date.parse(item.match(RXS.ts)[0].trim())); } } // BSD - else if(item.match(RXS.month)) { + else if(item.match(RXS.month) && nextItem && nextItem.match(RXS.day)) { entry.type = "BSD"; const month = item.trim(); - const day = peek(items); - let time = peek(items); + const day = shiftItem(items); + let time = shiftItem(items); let year = new Date().getYear() + 1900 let timezone = ""; // Check if the time is actually a year field and it is in the form "MMM dd yyyy HH:mm:ss" if (time.length === 4 && !Number.isNaN(+time)) { year = +time; - time = peek(items); + time = shiftItem(items); } // Check if we have a timezone if (isValidTimeZone(items[0].trim())) { - timezone = peek(items); + timezone = shiftItem(items); } entry.ts = new Date(Date.parse(`${year} ${month} ${day} ${time} ${timezone}`.trim())); @@ -130,7 +151,7 @@ function parse(line,opts) { } while(line.length && !endparse) { - var item = peek(items); + var item = shiftItem(items); if(!item) { endparse = true; } diff --git a/parser.test.js b/parser.test.js index c762804..d2e2d28 100644 --- a/parser.test.js +++ b/parser.test.js @@ -31,6 +31,24 @@ test.each([ fields: [], header: "<34>Oct 11 22:14:15 mymachine su: ", }, + { + originalMessage: + "<34>OCT 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8", + pri: "<34>", + prival: 34, + facilityval: 4, + levelval: 2, + facility: "auth", + level: "crit", + type: "BSD", + ts: dateAsCurrentYear("2019-10-11T21:14:15.000Z"), + host: "mymachine", + appName: "su", + message: "'su root' failed for lonvick on /dev/pts/8", + chain: [], + fields: [], + header: "<34>OCT 11 22:14:15 mymachine su: ", + }, { originalMessage: "<34>Oct 11 22:14:15.123 UTC mymachine su: 'su root' failed for lonvick on /dev/pts/8",