String line;
ParseInformation parsePosition = new ParseInformation(0);
Matcher gcPauseMatcher = PATTERN_GC_PAUSE.matcher("");
Matcher linesMixedMatcher = PATTERN_LINES_MIXED.matcher("");
Matcher ergonomicsMatcher = PATTERN_G1_ERGONOMICS.matcher("");
GCEvent gcEvent = null;
int lineNumber = 0;
String beginningOfLine = null;
while ((line = in.readLine()) != null) {
++lineNumber;
parsePosition.setLineNumber(lineNumber);
parsePosition.setIndex(0);
if ("".equals(line)) {
continue;
}
try {
// filter out lines that don't need to be parsed
if (startsWith(line, EXCLUDE_STRINGS, false)) {
continue;
}
else if (line.indexOf(APPLICATION_TIME) > 0) {
continue;
}
else if (startsWith(line, LOG_INFORMATION_STRINGS, false)) {
LOG.info(line);
continue;
}
// remove G1 ergonomics pieces
if (line.indexOf(G1_ERGONOMICS) >= 0) {
ergonomicsMatcher.reset(line);
if (ergonomicsMatcher.matches()) {
String firstMatch = (ergonomicsMatcher.group(1));
if (firstMatch.length() > 0 && line.indexOf(SOFT_REFERENCE) < 0) {
beginningOfLine = firstMatch;
}
continue;
}
}
// if a new timestamp occurs in the middle of a line, that should be treated as a new line
// -> the rest of the old line appears on the next line
linesMixedMatcher.reset(line);
if (linesMixedMatcher.matches()) {
if (line.indexOf("concurrent") > 0) {
// 1st pattern (complete concurrent collection follows)
beginningOfLine = linesMixedMatcher.group(1);
model.add(parseLine(linesMixedMatcher.group(2), parsePosition));
parsePosition.setIndex(0);
continue; // rest of collection is on the next line, so continue there
}
else if (line.indexOf(SOFT_REFERENCE) > 0 && line.indexOf(Type.FULL_GC.getName()) > 0) {
// for Full GCs, SoftReference entries are treated as unknown detail events
// -> parseLine can do this
}
else if (line.endsWith("secs]")) {
// all other patterns: some timestamps follow that are part of a concurrent collection
// but the rest of the line is the rest of the same collection
StringBuilder realLine = new StringBuilder();
realLine.append(linesMixedMatcher.group(1));
int toSpaceIndex = line.indexOf(TO_SPACE_OVERFLOW);
int initialMarkIndex = line.indexOf(INITIAL_MARK);
if (toSpaceIndex > 0 && realLine.length() < toSpaceIndex) {
realLine.append(" ").append(TO_SPACE_OVERFLOW);
}
if (initialMarkIndex > 0 && realLine.length() < initialMarkIndex) {
realLine.append(" ").append(INITIAL_MARK);
}
realLine.append(line.substring(line.lastIndexOf(",")));
line = realLine.toString();
}
else {
throw new ParseException("unexpected mixed line", line, parsePosition);
}
}
else if (beginningOfLine != null) {
// filter output of -XX:+PrintReferencePolicy away
if (line.indexOf(SOFT_REFERENCE) >= 0) {
line = line.substring(line.lastIndexOf(","));
}
// not detailed log but mixed line
line = beginningOfLine + line;
beginningOfLine = null;
}
if (line.endsWith(MARK_STACK_IS_FULL)) {
// "Mark stack is full" message is treated as part of the event name
beginningOfLine = line;
continue;
}
else if (isPrintTenuringDistribution(line)) {
beginningOfLine = line;
continue;
}
// the following case is special for -XX:+PrintGCDetails and must be treated
// different from the other cases occurring in G1 standard mode
// 0.356: [GC pause (young), 0.00219944 secs] -> GC_PAUSE pattern but GC_MEMORY_PAUSE
// event (has extensive details)
// all other GC types are the same as in standard G1 mode.
gcPauseMatcher.reset(line);
if (gcPauseMatcher.matches()) {
ExtendedType type = extractTypeFromParsedString(gcPauseMatcher.group(GC_PAUSE_GROUP_TYPE));
if (type != null && type.getPattern().compareTo(GcPattern.GC_MEMORY_PAUSE) == 0) {
// detailed G1 events start with GC_MEMORY pattern, but are of type GC_MEMORY_PAUSE
gcEvent = new G1GcEvent();
Date datestamp = parseDatestamp(gcPauseMatcher.group(GC_PAUSE_GROUP_DATESTAMP), parsePosition);
gcEvent.setDateStamp(datestamp);
double timestamp = 0;
if (gcPauseMatcher.group(GC_PAUSE_GROUP_TIMESTAMP) == null) {
timestamp = getTimestamp(line, parsePosition, datestamp);
}
else {
timestamp = NumberParser.parseDouble(gcPauseMatcher.group(GC_PAUSE_GROUP_TIMESTAMP));
}
gcEvent.setTimestamp(timestamp);
gcEvent.setExtendedType(type);
gcEvent.setPause(NumberParser.parseDouble(gcPauseMatcher.group(GC_PAUSE_GROUP_PAUSE)));
// now parse the details of this event
lineNumber = parseDetails(in, model, parsePosition, lineNumber, gcEvent, beginningOfLine);
beginningOfLine = null;
continue;
}
else {
// real GC_PAUSE events like some concurrent events
model.add(parseLine(line, parsePosition));
}
}
else if (line.indexOf(Type.FULL_GC.getName()) > 0) {
// since jdk 1.8 full gc events in G1 have detailed heap sizing information on the next line
GCEvent fullGcEvent = (GCEvent) parseLine(line, parsePosition);
if (!in.markSupported()) {
LOG.warning("input stream does not support marking!");
}
else {
in.mark(200);