/ ProjectPlugins / CodexClient / CodexLogLine.cs
CodexLogLine.cs
  1  using System.Globalization;
  2  
  3  namespace CodexClient
  4  {
  5      public class CodexLogLine
  6      {
  7          public static CodexLogLine? Parse(string line)
  8          {
  9              try
 10              {
 11                  if (string.IsNullOrEmpty(line) ||
 12                      line.Length < 34 ||
 13                      line[3] != ' ' ||
 14                      line[33] != ' ') return null;
 15  
 16                  line = line.Replace(Environment.NewLine, string.Empty);
 17  
 18                  var level = line.Substring(0, 3);
 19                  var dtLine = line.Substring(4, 23);
 20  
 21                  var firstEqualSign = line.IndexOf('=');
 22                  var msgStart = 34;
 23                  var msgEnd = line.Substring(0, firstEqualSign).LastIndexOf(' ');
 24                  var msg = line.Substring(msgStart, msgEnd - msgStart).Trim();
 25                  var attrsLine = line.Substring(msgEnd);
 26  
 27                  var attrs = SplitAttrs(attrsLine);
 28  
 29                  var format = "yyyy-MM-dd HH:mm:ss.fff";
 30                  var dt = DateTime.ParseExact(dtLine, format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToUniversalTime();
 31  
 32                  return new CodexLogLine()
 33                  {
 34                      LogLevel = level,
 35                      TimestampUtc = dt,
 36                      Message = msg,
 37                      Attributes = attrs
 38                  };
 39              }
 40              catch
 41              {
 42                  return null;
 43              }
 44          }
 45  
 46          public string LogLevel { get; set; } = string.Empty;
 47          public DateTime TimestampUtc { get; set; }
 48          public string Message { get; set; } = string.Empty;
 49          public Dictionary<string, string> Attributes { get; private set; } = new Dictionary<string, string>();
 50  
 51          /// <summary>
 52          /// After too much time spent cursing at regexes, here's what I got:
 53          /// Parses input string into 'key=value' pair, considerate of quoted (") values.
 54          /// </summary>
 55          private static Dictionary<string, string> SplitAttrs(string input)
 56          {
 57              input += " ";
 58              var result = new Dictionary<string, string>();
 59  
 60              var key = string.Empty;
 61              var value = string.Empty;
 62              var mode = 1;
 63              var inQuote = false;
 64  
 65              foreach (var c in input)
 66              {
 67                  if (mode == 1)
 68                  {
 69                      if (c == '=') mode = 2;
 70                      else if (c == ' ')
 71                      {
 72                          if (string.IsNullOrEmpty(key)) continue;
 73                          else
 74                          {
 75                              result.Add(key, string.Empty);
 76                              key = string.Empty;
 77                              value = string.Empty;
 78                          }
 79                      }
 80                      else key += c;
 81                  }
 82                  else if (mode == 2)
 83                  {
 84                      if (c == ' ' && !inQuote)
 85                      {
 86                          result.Add(key, value);
 87                          key = string.Empty;
 88                          value = string.Empty;
 89                          mode = 1;
 90                      }
 91                      else if (c == '\"')
 92                      {
 93                          inQuote = !inQuote;
 94                      }
 95                      else
 96                      {
 97                          value += c;
 98                      }
 99                  }
100              }
101  
102              return result;
103          }
104      }
105  }