protected virtual void ProcessLevelLoggerAndChildren(LevelLogger levelLogger, LogLine.LogType[] logTypes, ref StringBuilder sb, int level)
 {
     var children = levelLogger.GetChildren();
     if (children != null)
     {
         var prefix = GetPrefixIndent(level);
         foreach (var child in children)
         {
             var logLine = child as LogLine;
             if (logLine != null)
             {
                 if (logTypes == null || logTypes.Contains(logLine.Type))
                 {
                     sb.AppendLine(String.Format("{0} {1}", prefix, OutputLogLine(logLine)));
                     continue;
                 }
             }
             var childLevelLogger = child as LevelLogger;
             if (childLevelLogger != null)
             {
                 if (childLevelLogger.HasErrorsOrInfos())
                 {
                     var keys = childLevelLogger.HasKeys() ? GetKeys(childLevelLogger) : "";
                     var name = GetCategoryName(childLevelLogger);
                     if (!String.IsNullOrEmpty(name))
                     {
                         sb.AppendLine(String.Format("{0} {1} {2}", prefix, name, keys));
                     }
                     ProcessLevelLoggerAndChildren(childLevelLogger, logTypes, ref sb, level + 1);
                 }
             }
         }
     }
 }
 protected virtual void OutputGroupedCategories(Builder.Logger logger, LogLine.LogType[] logTypes, ref StringBuilder sb)
 {
     var fatalSb = new StringBuilder();
     var errorSb = new StringBuilder();
     var infoSb = new StringBuilder();
     foreach (var categoryLogLines in logger.LogLineByCategory)
     {
         var currentSb = infoSb;
         var category = categoryLogLines.Key;
         var loglineList = categoryLogLines.Value;
         if (loglineList != null && loglineList.Any())
         {
             int totalLines = loglineList.Count;
             var firstLogLine = loglineList.FirstOrDefault();
             if (firstLogLine != null)
             {
                 if (firstLogLine.Type == LogLine.LogType.Fatal && (logTypes == null || logTypes.Contains(firstLogLine.Type)))
                 {
                     currentSb = fatalSb;
                 }
                 else if (firstLogLine.Type == LogLine.LogType.Error && (logTypes == null || logTypes.Contains(firstLogLine.Type)))
                 {
                     currentSb = errorSb;
                 }
                 else if (firstLogLine.Type == LogLine.LogType.Info && (logTypes == null || logTypes.Contains(firstLogLine.Type)))
                 {
                     currentSb = infoSb;
                 }
                 else
                 {
                     continue;
                 }
             }
             currentSb.AppendLine(String.Format("* {0} ({1}) ", category, totalLines));
             foreach (var logLine in loglineList)
             {
                 if (logTypes == null || logTypes.Contains(logLine.Type))
                 {
                     currentSb.AppendLine(String.Format("** {0}", OutputLogLine(logLine)));
                 }
             }
         }
     }
     var fatal = fatalSb.ToString();
     var error = errorSb.ToString();
     var info = infoSb.ToString();
     if (!String.IsNullOrEmpty(fatal))
     {
         sb.AppendLine("Fatals by type:");
         sb.AppendLine(fatal + "\r\n\r\n");
     }
     if (!String.IsNullOrEmpty(error))
     {
         sb.AppendLine("Errors by type:");
         sb.AppendLine(error + "\r\n\r\n");
     }
     if (!String.IsNullOrEmpty(info))
     {
         sb.AppendLine("Info by type:");
         sb.AppendLine(info + "\r\n\r\n");
     }
 }