/*---------------------------------------------------------------------------- * %%Function: CreateFromConfig * %%Qualified: AzLog.TextLogConverter.CreateFromConfig * %%Contact: rlittle * * Config language: * * This config defines how to parse a text line into an AzLogEntry, which * has a set of predefined columns, as well as custom columns. See * AzLogEntry.LogColummn for the set of constants we are mapping to. * * Column definition: * * [0-9]+ this is the column we are mapping to * ["+"] an optional "+" character, which means this column is copied to * another builtin column: * [0-9]+ the other column we are mapping to * [,:t?] what is the separator character * , means its a comma * : means its a colon * t means its \t * ? means we have a fixed width, with the width following: * [0-9]+ the fixed width, followed by a space (to terminate the * width) * ----------------------------------------------------------------------------*/ public static TextLogConverter CreateFromConfig(string sConfig) { TextLogConverter tlc = new TextLogConverter(); int ich, ichNext; int ichMac = sConfig.Length; ich = 0; while (ich < ichMac) { ichNext = ich; int nCol = -1; nCol = ParseColumn(sConfig, ich, ref ichNext, ichMac); int nColCopy = -1; if (sConfig[ichNext] == '+') // this means they want to copy this field to another column too { int ichFirstCopy = ++ichNext; nColCopy = ParseColumn(sConfig, ichFirstCopy, ref ichNext, ichMac); #if no while (ichNext < ichMac && char.IsDigit(sConfig[ichNext])) { ichNext++; } if (ichNext >= ichMac) { throw new Exception("bad config format -- no terminating separator after column copy"); } nColCopy = int.Parse(sConfig.Substring(ichFirstCopy, ichNext - ichFirstCopy)); #endif // no } char chSep = sConfig[ichNext]; TextLogColumn tlcc = new TextLogColumn(); tlcc.Column = (AzLogEntry.LogColumn)nCol; if (nColCopy != -1) { tlcc.ColumnCopy = (AzLogEntry.LogColumn)nColCopy; } if (chSep == ',') { tlcc.Separator = TextLogColumn.Sep.Comma; } else if (chSep == ':') { tlcc.Separator = TextLogColumn.Sep.Colon; } else if (chSep == 't') { tlcc.Separator = TextLogColumn.Sep.Tab; } else if (chSep == '?') { tlcc.Separator = TextLogColumn.Sep.FixedWidth; int ichFirst = ++ichNext; // the next digits are the cch while (ichNext < ichMac && char.IsDigit(sConfig[ichNext])) { ichNext++; } if (ichFirst >= ichNext) { throw new Exception("bad config format -- no length for fixed width column"); } if (sConfig[ichNext] != ' ') { throw new Exception("bad config format -- fixed width column width was not terminated with a space"); } tlcc.Cch = int.Parse(sConfig.Substring(ichFirst, ichNext - ichFirst)); } else { throw new Exception("bad config format. unknown separator"); } tlc.m_pltlc.Add(tlcc); ich = ichNext + 1; } return(tlc); }
/* P A R S E L I N E */ /*---------------------------------------------------------------------------- * %%Function: ParseLine * %%Qualified: AzLog.AzLogFile.TextLogConverter.ParseLine * %%Contact: rlittle * * ----------------------------------------------------------------------------*/ public AzLogEntry ParseLine(string sLine, int nLine) { AzLogEntry azle = new AzLogEntry(); azle.InitMessageParts(10); int ilc = 0; int ich = 0; int ichLast = 0; int ichMac = sLine.Length; while (ilc < m_pltlc.Count) { ichLast = 0; TextLogColumn tlc = m_pltlc[ilc]; // by definition we are already positioned at the beginning of this column except for possible whitespace // skip leading whitespace exc while (ich < ichMac && sLine[ich] == ' ') { ich++; } if (ich >= ichMac) { if (ilc < m_pltlc.Count) { return(null); } break; } int ichEnd = 0; // look for the separator if (tlc.Separator == TextLogColumn.Sep.Comma) { if (!FParseQuotedCommaColumn(sLine, ich, ref ichLast, ref ichEnd, ichMac, ilc + 1 == m_pltlc.Count)) { return(null); } // else, we'll calculate ichLim below } else if (tlc.Separator == TextLogColumn.Sep.FixedWidth) { if (!FParseFixedWidthColumn(sLine, tlc.Cch, ich, ref ichLast, ref ichEnd, ichMac, ilc + 1 == m_pltlc.Count)) { return(null); } } if (ichLast == 0) { if (ilc + 1 == m_pltlc.Count) { ichEnd = ichLast = sLine.Length - 1; } else { char chSep = TextLogColumn.CharFromSep(tlc.Separator); ichLast = sLine.IndexOf(chSep, ich); if (ichLast == -1) { return(null); // couldn't find the separator for this column } ichLast--; // we want this to point to the last char, not to the separator ichEnd = ichLast; } } // at this point we have ich pointing to start of string; ichEnd pointing to last char before the separator (maybe a quote), // at ichLast pointing to just before the separator (never a quote) //, lets trim the string int ichFirst = ich; if (sLine[ichFirst] == '"' && sLine[ichEnd] == '"') { ichFirst++; ichEnd--; } while (ichEnd > ichFirst && sLine[ichEnd] == ' ') { ichEnd--; } // now we have the string if (tlc.Column == AzLogEntry.LogColumn.EventTickCount) { DateTime dttm = DateTime.Parse(sLine.Substring(ichFirst, ichEnd - ichFirst + 1)); dttm = dttm.ToUniversalTime(); azle.SetColumn(AzLogEntry.LogColumn.Partition, dttm.ToString("yyyyMMddHH")); azle.EventTickCount = dttm.Ticks + nLine; if (tlc.ColumnCopy != AzLogEntry.LogColumn.Nil) { azle.SetColumn(tlc.ColumnCopy, dttm.ToString("MM/dd/yyyy HH:mm:ss")); } // and manufacture a partition as well azle.SetColumn(AzLogEntry.LogColumn.Partition, AzLogModel.SPartitionFromDate(dttm, dttm.Hour)); } else { azle.SetColumn(tlc.Column, sLine.Substring(ichFirst, ichEnd - ichFirst + 1)); } if (tlc.Separator == TextLogColumn.Sep.FixedWidth) { ich = ichLast; } else { ich = ichLast + 2; } ilc++; if (ich >= ichMac) { // if (ilc < m_pltlc.Count) // return null; break; } } // return(azle); }