@Test
  public void testOptionalFields() throws IOException, InitializationException, ParseException {
    Properties p = new Properties();
    // Mixing sequence on purpose to test that sequence does not matter.
    p.put("LINE.group", "4");
    p.put("LEVEL.group", "2");
    p.put("TIMESTAMP.group", "1");
    p.put("FILE.group", "3");
    p.put("type", "log4j");
    p.put("rePattern", "(\\S+ \\d+ \\d+ [\\d.:]+)\\d +(\\S+) +\\(\\s*([^?]+)?\\??:\\??\\s*([^ )]+)? *\\) +-(?: +User +([^,]+),)?(?: +<TID: +([^>]+)> +:)? +(.*)");
    p.put("dateFormat", "MMM dd yyyy HH:mm:ss.SSS");
    p.put("NDC.group", "5");
    p.put("THREAD.group", "6");
    p.put("MESSAGE.group", "7");

    LogImporterUsingParser importerUsingParser =
            new LogImporterUsingParser(new Log4jPatternMultilineLogParser());
    ParsingContext context = new ParsingContext();
    importerUsingParser.init(p);
    importerUsingParser.initParsingContext(context);

    // when
    ProxyLogDataCollector dataCollector = new ProxyLogDataCollector();
    importerUsingParser.importLogs(loadLog("log4j/log4j_optionals_pattern.txt"),
            dataCollector, context);

    // then
    LogData[] logDatas = dataCollector.getLogData();
    assertEquals(5, logDatas.length);

    assertEquals("CMDBInstance.findObjects()-Done", logDatas[0].getMessage());
    assertEquals("Number of instances found in this chunk: <5>, Instances per thread: <2>", logDatas[1].getMessage());
    assertEquals("Thread Task = <2>", logDatas[2].getMessage());
    assertEquals("<null>:doBatchNormalization()-Begin", logDatas[3].getMessage());
    assertEquals("<null>:doBatchNormalization()-Begin", logDatas[4].getMessage());

    assertEquals(Level.FINE, logDatas[0].getLevel());
    assertEquals(Level.SEVERE, logDatas[1].getLevel());
    assertEquals(Level.SEVERE, logDatas[2].getLevel());
    assertEquals(Level.INFO, logDatas[3].getLevel());
    assertEquals(Level.WARNING, logDatas[4].getLevel());

    final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMM dd yyyy HH:mm:ss.SSS", Locale.ENGLISH);
    assertEquals(simpleDateFormat.parse("Nov 23 2013 21:50:45.755").getTime(), logDatas[0].getDate().getTime());
    assertEquals(simpleDateFormat.parse("Nov 23 2013 21:50:45.791").getTime(), logDatas[1].getDate().getTime());
    assertEquals(simpleDateFormat.parse("Nov 23 2013 21:50:45.798").getTime(), logDatas[2].getDate().getTime());
    assertEquals(simpleDateFormat.parse("Nov 23 2013 21:50:45.805").getTime(), logDatas[3].getDate().getTime());
    assertEquals(simpleDateFormat.parse("Nov 23 2013 21:50:45.817").getTime(), logDatas[4].getDate().getTime());

    // org.apache.log4j.spi.LocationInfo converts null location fields to "?"s
    assertEquals("?", logDatas[0].getFile());
    assertEquals("?", logDatas[1].getFile());
    assertEquals("AISFilter.java", logDatas[2].getFile());
    assertEquals("?", logDatas[3].getFile());
    assertEquals("?", logDatas[4].getFile());

    // org.apache.log4j.spi.LocationInfo converts null location fields to "?"s
    assertEquals("?", logDatas[0].getLine());
    assertEquals("?", logDatas[1].getLine());
    assertEquals("135", logDatas[2].getLine());
    assertEquals("?", logDatas[3].getLine());
    assertEquals("?", logDatas[4].getLine());

    // Log4jPatternMultilineLogParser.convertToEvent() converts
    // thread null value to "".
    assertEquals("", logDatas[0].getThread());
    assertEquals("000000029", logDatas[1].getThread());
    assertEquals("000000029", logDatas[2].getThread());
    assertEquals("000000030", logDatas[3].getThread());
    assertEquals("000000031", logDatas[4].getThread());

    assertEquals(null, logDatas[0].getNDC());
    assertEquals(null, logDatas[1].getNDC());
    assertEquals(null, logDatas[2].getNDC());
    assertEquals("blaine", logDatas[3].getNDC());
    assertEquals("<No Context>", logDatas[4].getNDC());
  }
This class tests the "rePattern" alternative of Log4jPatternMultilineLogParser.
(As opposed to the more simple "pattern" system).
olv-core/src/test/java/pl/otros/logview/parser/log4j/Log4jPatternRegexParserTest.java