LineProcessingResult processLine(String line) {
    LineProcessingResult result = new LineProcessingResult(line);

    Matcher matcher = null;

    result.line = replaceHandler.processLine(result.line);

    if (fsType == FsType.ENCRYPTED_HDFS) {
      for (Pattern pattern : partialReservedPlanMask) {
        matcher = pattern.matcher(result.line);
        if (matcher.find()) {
          result.line = PARTIAL_MASK_PATTERN + " " + matcher.group(0);
          result.partialMaskWasMatched = true;
          break;
        }
      }
    }
    else {
      for (PatternReplacementPair prp : partialPlanMask) {
        matcher = prp.pattern.matcher(result.line);
        if (matcher.find()) {
          result.line = result.line.replaceAll(prp.pattern.pattern(), prp.replacement);
          result.partialMaskWasMatched = true;
        }
      }
    }

    if (!result.partialMaskWasMatched) {
      for (Pair<Pattern, String> pair : patternsWithMaskComments) {
        Pattern pattern = pair.getLeft();
        String maskComment = pair.getRight();

        matcher = pattern.matcher(result.line);
        if (matcher.find()) {
          result.line = matcher.replaceAll(maskComment);
          result.partialMaskWasMatched = true;
          break;
        }
      }

      maskPattern(result, Mask.STATS, MASK_STATS);
      maskPattern(result, Mask.DATASIZE, MASK_DATA_SIZE);
      maskPattern(result, Mask.LINEAGE,  MASK_LINEAGE);
      maskPattern(result, Mask.TIMESTAMP, MASK_TIMESTAMP);

      for (String prefix : maskIfStartsWith) {
        if (result.line.startsWith(prefix)) {
          result.line = MASK_PATTERN;
        }
      }

      for (String word : maskIfContains) {
        if (result.line.contains(word)) {
          result.line = MASK_PATTERN;
        }
      }

      for (String[] words : maskIfContainsMultiple) {
        int pos = 0;
        boolean containsAllInOrder = true;
        for (String word : words) {
          int wordPos = result.line.substring(pos).indexOf(word);
          if (wordPos == -1) {
            containsAllInOrder = false;
            break;
          } else {
            pos += wordPos + word.length();
          }
        }
        if (containsAllInOrder) {
          result.line = MASK_PATTERN;
        }
      }

      for (Pattern pattern : planMask) {
        result.line = pattern.matcher(result.line).replaceAll(MASK_PATTERN);
      }
    }

    return result;
  }
QOutProcessor: produces the final q.out from original q.out by postprocessing (e.g. masks)
itests/util/src/main/java/org/apache/hadoop/hive/ql/QOutProcessor.java