@Override
  public LogData parse(String line, ParsingContext parsingContext) throws ParseException {

    LogData logData = null;
    if (line.trim().equals("")) {
      parsingContext.getUnmatchedLog().append('\n');
      parsingContext.getUnmatchedLog().append(line);
      return null;
    }

    Matcher eventMatcher = regexpPattern.matcher(line);
    Matcher exceptionMatcher = exceptionPattern.matcher(line);
    HashMap<String, Object> logEventParsingProperties = (HashMap<String, Object>) parsingContext.getCustomConextProperties().get(PROPERTY_LOG_EVENT_PROPERTIES);
    if (eventMatcher.matches()) {
      // build an event from the previous match (held in current map)
      LoggingEvent event = buildEvent(parsingContext);
      if (event != null) {
        // doPost(event);
        logData = Log4jUtil.translateLog4j(event);
      }
      // Allow for optional capture fields.
      // This is used by rePattern now, but traditional patterns could be
      // enhanced to support optional fields too.
      // We never write null key
      ((Set<Map.Entry<String, Object>>)
        processEvent(eventMatcher.toMatchResult()).entrySet()).stream().filter(entry -> entry.getValue() != null).forEach(entry -> logEventParsingProperties.put(entry.getKey(), entry.getValue()));
    } else if (exceptionMatcher.matches()) {
      // an exception line
      if (parsingContext.getUnmatchedLog().length() > 0)
        parsingContext.getUnmatchedLog().append('\n');
      parsingContext.getUnmatchedLog().append(line);
    } else {
      // neither...either post an event with the line or append as
      // additional lines
      // if this was a logging event with multiple lines, each line
      // will show up as its own event instead of being
      // appended as multiple lines on the same event..
      // choice is to have each non-matching line show up as its own
      // line, or append them all to a previous event
      if (appendNonMatches) {
        // hold on to the previous time, so we can do our best to
        // preserve time-based ordering if the event is a non-match
        String lastTime = (String) logEventParsingProperties.get(TIMESTAMP);
        // build an event from the previous match (held in current
        // map)
        if (logEventParsingProperties.size() > 0) {
          LoggingEvent event = buildEvent(parsingContext);
          if (event != null) {
            logData = Log4jUtil.translateLog4j(event);
          }
        }
        if (lastTime != null) {
          logEventParsingProperties.put(TIMESTAMP, lastTime);
        }
        logEventParsingProperties.put(MESSAGE, line);
      } else {
        if (parsingContext.getUnmatchedLog().length() > 0) {
          parsingContext.getUnmatchedLog().append('\n');
        }
        if (trimUnmatchedLines)
          parsingContext.getUnmatchedLog().append(line.trim());
        else
          parsingContext.getUnmatchedLog().append(line);
      }
    }

    return logData;
  }
Convert a keyword-to-values map to a LoggingEvent

@param fieldMap
@param exception

@return logging event
olv-core/src/main/java/pl/otros/logview/parser/log4j/Log4jPatternMultilineLogParser.java