private Tuple <string, List <NameValuePair> > ParseElement(ParserContext ctx) { if (ctx.Current != SyslogChars.Lbr) { return(null); } ctx.Position++; var elemName = ctx.ReadWord(); ctx.SkipSpaces(); var paramList = new List <NameValuePair>(); var elem = new Tuple <string, List <NameValuePair> >(elemName, paramList); while (ctx.Current != SyslogChars.Rbr) { var paramName = ctx.ReadWord(); ctx.ReadSymbol('='); var paramValue = ctx.ReadQuotedString(); var prm = new NameValuePair() { Name = paramName, Value = paramValue }; paramList.Add(prm); ctx.SkipSpaces(); } ctx.ReadSymbol(SyslogChars.Rbr); return(elem); }
} //method private List <NameValuePair> ReadKeyValuePairs(ParserContext ctx) { var prmList = new List <NameValuePair>(); NameValuePair lastPrm = null; /* * 2 troubles here: */ while (!ctx.Eof()) { ctx.SkipSpaces(); var name = ctx.ReadWord(); if (!ctx.ReadSymbol('=', throwIfMismatch: false)) { // Some entries are malformed: double quoted strings // the result is that we do not find '=' after closing the quote. So we just add the rest to a separate param and exit var text = ctx.Text.Substring(ctx.Position); prmList.Add(new NameValuePair() { Name = "Message", Value = text }); return(prmList); } ctx.SkipSpaces(); string value; if (ctx.Current == SyslogChars.DQuote) { // For double-quoted values, some values are malformed - they contain nested d-quoted strings that are not escaped. value = ctx.ReadQuotedString(); } else { // Special case: non quoted empty values, ex: ' a= b=234 '; value of 'a' is Empty. We check the char after we read the value, // and if it is '=', we back off, set value to empty. var saveP = ctx.Position; value = ctx.ReadWord(); if (ctx.Current == '=') { ctx.Position = saveP; value = string.Empty; } } lastPrm = new NameValuePair() { Name = name, Value = value }; prmList.Add(lastPrm); } return(prmList); }
private void ParseStructuredData(ParserContext ctx) { ctx.SkipSpaces(); if (ctx.Current == SyslogChars.NilChar) { ctx.Position++; return; } var data = ctx.Entry.StructuredData; try { if (ctx.Current != SyslogChars.Lbr) { // do not report it as an error, some messages out there are a bit malformed // ctx.AddError("Expected [ for structured data."); return; } // start parsing elements while (!ctx.Eof()) { var elem = ParseElement(ctx); if (elem == null) { return; } data[elem.Item1] = elem.Item2; } } catch (Exception ex) { ctx.AddError(ex.Message); } }
public bool TryParse(ParserContext ctx) { ctx.SkipSpaces(); ctx.Entry.PayloadType = Model.PayloadType.PlainText; ctx.Entry.Message = ctx.Text.Substring(ctx.Position); ctx.Entry.Header.Timestamp = DateTime.UtcNow; return(true); }
// let try to match any key, like <120> abc = def private bool TryMatchAnyKey(ParserContext ctx) { if (!char.IsLetter(ctx.Current)) { return(false); } var savePos = ctx.Position; var word = ctx.ReadWord(); ctx.SkipSpaces(); var result = ctx.Match("="); ctx.Position = savePos; return(result); }
public bool TryParse(ParserContext ctx) { if (ctx.Current == SyslogChars.Space) { ctx.SkipSpaces(); } // typically entries start with 'device=' or 'date=' var match = ctx.Match("device=") || ctx.Match("date="); if (!match) { match = TryMatchAnyKey(ctx); } if (!match) { return(false); } // It is the format for this parser ctx.Reset(); // Match(...) moved the position, so return to the start ctx.Entry.PayloadType = PayloadType.KeyValuePairs; var kvList = ReadKeyValuePairs(ctx); ctx.Entry.ExtractedData.AddRange(kvList); // try some known values and put them in the header var hdr = ctx.Entry.Header; hdr.HostName = kvList.GetValue("device_id"); var date = kvList.GetValue("date"); var time = kvList.GetValue("time"); if (date != null) { var dateTimeStr = $"{date}T{time}"; if (DateTime.TryParse(dateTimeStr, out var dt)) { hdr.Timestamp = dt; } } return(true); } //method
public static string ReadWord(this ParserContext ctx) { if (ctx.Current == SyslogChars.Space) { ctx.SkipSpaces(); } var separatorPos = ctx.Text.IndexOfAny(SyslogChars.WordSeparators, ctx.Position); if (separatorPos < 0) { separatorPos = ctx.Text.Length; } var word = ctx.Text.Substring(ctx.Position, separatorPos - ctx.Position); ctx.Position = separatorPos; return(word); }
public static bool TryParseTimestamp(ParserContext ctx) { // sometimes there's starting space if (ctx.Current == SyslogChars.Space) { ctx.SkipSpaces(); } // some messages start with some numeric Id: // <139>36177473: Mar 4 17:21:18 UTC: if (char.IsDigit(ctx.Current)) { // make sure it's not a year and at least 5 chars var fiveDigits = ctx.Text.Substring(ctx.Position, 5).All(ch => char.IsDigit(ch)); if (fiveDigits) { var savePos = ctx.Position; var digits = ctx.ReadDigits(20); if (ctx.Match(": ")) { // we swallowed this numeric prefix and ': ' after that, nothing to do } else { ctx.Position = savePos; // rollback, timestamp evaluation will go from string start } } } try { // quick guess - if it contains current month name if (TryParseIfStartsWithYear(ctx) || TryParseTimestampWithMonthName(ctx) || TryParseIfStartsWithColonThenYear(ctx) || TryParseIfStartsWithSpace(ctx)) { return(true); } } catch (Exception ex) { ctx.ErrorMessages.Add(ex.ToString()); } return(false); }
public static bool ReadSymbol(this ParserContext ctx, char symbol, bool throwIfMismatch = true) { if (ctx.Current == SyslogChars.Space) { ctx.SkipSpaces(); } if (ctx.Current == symbol) { ctx.Position++; return(true); } if (throwIfMismatch) { throw new Exception($"Invalid input, expected '{symbol}' "); } else { return(false); } }