ui/src/main/java/thredds/logs/ServletLogParser.java
public LogReader.Log nextLog(BufferedReader dataIS) throws IOException {

    ServletLog log = new ServletLog();
    boolean haveLog = false;

    while (true) {
      dataIS.mark(20 * 1000); // track where we are
      String line = dataIS.readLine();
      if (line == null) {
        return haveLog ? log : null;
      }
      // if (count++ < limit) System.out.println("\n" + line);                      nTest reqe

      try {
        Matcher m = commonPattern.matcher(line);
        if (m.matches()) {
          if (haveLog) { // have a log, next one matches, proceed
            try {
              dataIS.reset();
              return log;

            } catch (Throwable t) {
              System.out.println("Cant reset " + line);              
            }
          }
          haveLog = true; // next match will return the current log

          log.date = convertDate( m.group(1));
          log.reqTime = parseLong(m.group(2));
          log.reqSeq = parseLong(m.group(3));
          log.level = m.group(4).intern();
          log.where = m.group(5);

          String rest = m.group(6);
          if (rest.contains("Request Completed")) {
            int pos = rest.indexOf("Request Completed");
            Matcher m2 = donePattern.matcher(rest.substring(pos));
            if (m2.matches()) {
              log.returnCode = parse(m2.group(1));
              log.sizeBytes = parseLong(m2.group(2));
              log.msecs = parseLong(m2.group(3));
              log.isDone = true;

            } else {
              System.out.println("Cant parse donePattern= " + rest);
              System.out.println(" line= " + line);
              log.addExtra(rest);
            }

          } else if (rest.contains("Remote host")) {
            int pos = rest.indexOf("Remote host");
            Matcher m2 = startPattern.matcher(rest.substring(pos));
            if (m2.matches()) {
              log.ip = m2.group(1);
              log.verb = m2.group(2).intern();
              log.path = EscapeStrings.urlDecode(m2.group(3)); //old  URLDecoder.decode(m2.group(3));
              if (m2.groupCount() > 4)
                log.http = m2.group(4).intern();
              log.isStart = true;

            } else {
              System.out.println("Cant parse startPattern= " + rest);
              System.out.println(" line= " + line);
              log.addExtra(rest);
            }

          } else { // a non-start, non-done log
            log.addExtra(rest);
          }

        } else { // the true extra line
          //System.out.println("No match on " + line);
          log.addExtra(line);
        }

      } catch (Exception e) {
        e.printStackTrace();
        System.out.println("Cant parse " + line);
        log.addExtra(line);
      }
    }

  }
public LogReader.Log nextLog(BufferedReader dataIS) throws IOException {

    ServletLog log = new ServletLog();
    boolean haveLog = false;

    while (true) {
      dataIS.mark(20 * 1000); // track where we are
      String line = dataIS.readLine();
      if (line == null) {
        return haveLog ? log : null;
      }
      // if (count++ < limit) System.out.println("\n" + line);                      nTest reqe

      try {
        Matcher m = commonPattern.matcher(line);
        if (m.matches()) {
          if (haveLog) { // have a log, next one matches, proceed
            try {
              dataIS.reset();
              return log;

            } catch (Throwable t) {
              System.out.println("Cant reset " + line);              
            }
          }
          haveLog = true; // next match will return the current log

          log.date = convertDate( m.group(1));
          log.reqTime = parseLong(m.group(2));
          log.reqSeq = parseLong(m.group(3));
          log.level = m.group(4).intern();
          log.where = m.group(5);

          String rest = m.group(6);
          if (rest.contains("Request Completed")) {
            int pos = rest.indexOf("Request Completed");
            Matcher m2 = donePattern.matcher(rest.substring(pos));
            if (m2.matches()) {
              log.returnCode = parse(m2.group(1));
              log.sizeBytes = parseLong(m2.group(2));
              log.msecs = parseLong(m2.group(3));
              log.isDone = true;

            } else {
              System.out.println("Cant parse donePattern= " + rest);
              System.out.println(" line= " + line);
              log.addExtra(rest);
            }

          } else if (rest.contains("Remote host")) {
            int pos = rest.indexOf("Remote host");
            Matcher m2 = startPattern.matcher(rest.substring(pos));
            if (m2.matches()) {
              log.ip = m2.group(1);
              log.verb = m2.group(2).intern();
              log.path = EscapeStrings.urlDecode(m2.group(3)); //old  URLDecoder.decode(m2.group(3));
              if (m2.groupCount() > 4)
                log.http = m2.group(4).intern();
              log.isStart = true;

            } else {
              System.out.println("Cant parse startPattern= " + rest);
              System.out.println(" line= " + line);
              log.addExtra(rest);
            }

          } else { // a non-start, non-done log
            log.addExtra(rest);
          }

        } else { // the true extra line
          //System.out.println("No match on " + line);
          log.addExtra(line);
        }

      } catch (Exception e) {
        e.printStackTrace();
        System.out.println("Cant parse " + line);
        log.addExtra(line);
      }
    }

  }
/*
Difficult thing is to return the extra line assocated with the previous good log
We do this by not returning until we get a match on the next log. We have to rewind.