public static boolean mergeLogFiles(final Map<String, DisplayNameAndFileStream> logFiles,
        final PrintWriter mergedFile, final boolean tabOut, final boolean suppressBlanks,
        final boolean multithreaded, final Iterable<String> patterns) {
      List<Pattern> compiledPatterns = new LinkedList<>();
      for (String pattern : patterns) {
        compiledPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
      }

      // First start the Reader threads
      ReaderGroup group =
          new ReaderGroup("Reader threads");
      Collection<Reader> readers = new ArrayList<>(logFiles.size());
      for (DisplayNameAndFileStream nameAndFileStream : logFiles.values()) {
        if (multithreaded) {
          readers.add(new ThreadedReader(nameAndFileStream.getInputStream(),
              nameAndFileStream.getDisplayName(), group, tabOut,
              suppressBlanks, compiledPatterns));
        } else {
          readers.add(new NonThreadedReader(nameAndFileStream.getInputStream(),
              nameAndFileStream.getDisplayName(), group, tabOut,
              suppressBlanks, compiledPatterns));
        }
      }

      // Merge the log files together
      Reader lastOldest = null;

      // sort readers by their next time-stamp
      Set<Reader> sorted = sortReaders(readers);

      while (!readers.isEmpty()) {
        Iterator sortedIt = sorted.iterator();
        if (!sortedIt.hasNext()) {
          break;
        }
        Reader oldest = (Reader) sortedIt.next();
        sortedIt.remove();

        String nextReaderTimestamp = null;
        if (sortedIt.hasNext()) {
          Reader nextInLine = (Reader) sortedIt.next();
          nextReaderTimestamp = nextInLine.peek().getTimestamp();
        }

        // if we've switched to a different reader, emit a blank line
        // for readability
        if (oldest != lastOldest) {
          mergedFile.println();
          lastOldest = oldest;
        }

        LogEntry entry;
        // write until we hit the next file's time-stamp
        do {
          entry = oldest.peek();
          String timestamp = entry.getTimestamp();

          if (nextReaderTimestamp != null) {
            if (nextReaderTimestamp.compareTo(timestamp) < 0) {
              sorted.add(oldest);
              entry = null;
              break;
            }
          }

          entry = oldest.poll();
          entry.writeTo(mergedFile);

        } while (!entry.isLast());

        if (entry != null && entry.isLast()) {
          readers.remove(oldest);
        }
      }

      return group.exceptionOccurred();
    }
Merges the log files from a given set of {@code InputStream}s into a
{@code PrintWriter}.

@param logFiles The log files to be merged
@param mergedFile Where the merged logs are printed to
@param tabOut Whether to align non-timestamped lines with others
@param suppressBlanks Whether to suppress output of blank lines

@return Whether or not problems occurred while merging the log files.

@throws IllegalArgumentException If the length of {@code logFiles} is not the same as
        the length of {@code logFileNames}
geode-core/src/main/java/org/apache/geode/internal/logging/MergeLogFiles.java