Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ZGC logging #216

Merged
merged 34 commits into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
81dcfcf
Include GC Phases from ZGC for parsing
Marysunithajoseph Jan 13, 2019
dda185a
Corrected phase name
Marysunithajoseph Jan 14, 2019
9643bd8
Parsing Phases for ZGC
Marysunithajoseph Jan 15, 2019
84205d6
Removed unnecessary print outs
Marysunithajoseph Jan 15, 2019
1a05f67
Added test cases for default and memory matchers
yanqilee Jan 15, 2019
d7e2405
Added tests for gc all logging
yanqilee Jan 15, 2019
66e9c1b
fixed formatting
yanqilee Jan 15, 2019
75f83bb
Fixed a typo
yanqilee Jan 15, 2019
1256031
Seperating GC Causes and its memory info
Marysunithajoseph Jan 16, 2019
238050f
Merge branch 'feature/fullstackZGCintegration' of https://github.com/…
yanqilee Jan 18, 2019
9b7aad5
Gc causes no longer show total sum percentage
yanqilee Jan 21, 2019
8b00e90
Fixed up gc causes model
yanqilee Jan 21, 2019
b3fc7f6
Fixed some formatting
yanqilee Jan 21, 2019
5a9b562
Fixed up comment for build
yanqilee Jan 21, 2019
1f681bd
Fixed maven javadoc plugin failing on jdk 11.0.2
yanqilee Jan 21, 2019
1fdb0a0
initial code refactor
yanqilee Jan 22, 2019
52b4111
refactored addGcEvent
yanqilee Jan 22, 2019
ba10ced
Remove unused imports
yanqilee Jan 22, 2019
03284fc
Fixed Codacy issues
yanqilee Jan 22, 2019
70598e9
No longer alter event parameter in method
yanqilee Jan 22, 2019
2576e5d
Added missed null check on isParseablePhaseEvent
yanqilee Jan 23, 2019
18d4275
Refactored tests and updated method params
yanqilee Jan 23, 2019
8925464
update method naming
yanqilee Jan 23, 2019
d29aa3c
Added percentage assertions to test cases
yanqilee Jan 23, 2019
2cb14fb
Removed ZGC phase parsing rule and commented out warning assertion
yanqilee Mar 1, 2019
75c7f6e
Fixed parentheses variable names
yanqilee Mar 1, 2019
e8ea44e
Removed memory capture and added phases start exclusion
yanqilee Mar 1, 2019
ad1ca4b
Fixed comments and code style
yanqilee Mar 1, 2019
0eb52d4
Added notion of phases in AbstractGcEvent
yanqilee Mar 1, 2019
53355b4
Changed test names to be more general
yanqilee Mar 1, 2019
3ecd294
Added phases to parser, model and UI
yanqilee Mar 4, 2019
ac4f08b
Minor changes for styles, etc
yanqilee Mar 4, 2019
907a3be
Single line import on TestGCEventUJL
yanqilee Mar 4, 2019
4793b3d
Made GCEventUJL private in test class
yanqilee Mar 4, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@
<links>
<link>http://docs.oracle.com/javase/8/docs/api/</link>
</links>
<source>${jdk.source.version}</source>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this fixes the build failure on the develop branch - thank you very much!

</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ public ExtendedType parseTypeWithCause(String typeName) {
typeName = typeName.trim();
ExtendedType extendedType = null;
String lookupTypeName = getLookupTypeName(typeName);

AbstractGCEvent.Type gcType = AbstractGCEvent.Type.lookup(lookupTypeName);
// the gcType may be null because there was a PrintGCCause flag enabled - if so, reparse it with the first paren set stripped
// the gcType may be null because there was a PrintGCCause flag enabled - if so, reparse it with the first parentheses set stripped
if (gcType == null) {
// try to parse it again with the parens removed
Matcher parenMatcher = parenthesesPattern.matcher(lookupTypeName);
if (parenMatcher.find()) {
gcType = AbstractGCEvent.Type.lookup(parenMatcher.replaceFirst(""));
// try to parse it again with the parentheses removed
Matcher parenthesesMatcher = parenthesesPattern.matcher(lookupTypeName);
if (parenthesesMatcher.find()) {
gcType = AbstractGCEvent.Type.lookup(parenthesesMatcher.replaceFirst(""));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ public class DataReaderUnifiedJvmLogging extends AbstractDataReader {
private static final String PATTERN_PAUSE_STRING = "([0-9]+[.,][0-9]+)ms";
private static final String PATTERN_MEMORY_STRING = "(([0-9]+)([BKMG])->([0-9]+)([BKMG])\\(([0-9]+)([BKMG])\\))";

private static final String PATTERN_HEAP_MEMORY_PERCENTAGE_STRING = "(([0-9]+)([BKMG])[ ](\\([0-9]+%\\)))";
private static final String PATTERN_MEMORY_PERCENTAGE_STRING = "(([0-9]+)([BKMG])\\([0-9]+%\\)->([0-9]+)([BKMG])\\([0-9]+%\\))";

// Input: 1.070ms
// Group 1: 1.070
private static final Pattern PATTERN_PAUSE = Pattern.compile("^" + PATTERN_PAUSE_STRING);
Expand All @@ -96,7 +99,7 @@ public class DataReaderUnifiedJvmLogging extends AbstractDataReader {
// Group 4: M
// Group 5: 4998
// Group 6: M
// Group 7: 1.070 (optional group)
// Group 7: 2.872 (optional group)
private static final Pattern PATTERN_MEMORY_PAUSE = Pattern.compile("^" + PATTERN_MEMORY_STRING + "(?:(?:[ ]" + PATTERN_PAUSE_STRING + ")|$)");

private static final int GROUP_MEMORY = 1;
Expand All @@ -118,19 +121,46 @@ public class DataReaderUnifiedJvmLogging extends AbstractDataReader {
private static final int GROUP_REGION_AFTER = 2;
private static final int GROUP_REGION_TOTAL = 3;

// Input: 106M(0%)->88M(0%)
// Group 1: 106M(0%)->88M(0%)
// Group 2: 106
// Group 3: M
// Group 4: 0%
// Group 5: 88
// Group 6: M
// Group 7: 0%
private static final Pattern PATTERN_MEMORY_PERCENTAGE = Pattern.compile("^" + PATTERN_MEMORY_PERCENTAGE_STRING);

private static final int GROUP_MEMORY_PERCENTAGE = 1;
private static final int GROUP_MEMORY_PERCENTAGE_BEFORE = 2;
private static final int GROUP_MEMORY_PERCENTAGE_BEFORE_UNIT = 3;
private static final int GROUP_MEMORY_PERCENTAGE_AFTER = 4;
private static final int GROUP_MEMORY_PERCENTAGE_AFTER_UNIT = 5;

// Input: 300M (1%)
// Group 1: 300M (1%)
// Group 2: 300
// Group 3: M
// Group 4: (1%)
private static final Pattern PATTERN_HEAP_MEMORY_PERCENTAGE = Pattern.compile("^" + PATTERN_HEAP_MEMORY_PERCENTAGE_STRING);

private static final int GROUP_HEAP_MEMORY_PERCENTAGE = 1;
private static final int GROUP_HEAP_MEMORY_PERCENTAGE_VALUE = 2;
private static final int GROUP_HEAP_MEMORY_PERCENTAGE_UNIT = 3;

private static final String TAG_GC = "gc";
private static final String TAG_GC_START = "gc,start";
private static final String TAG_GC_HEAP = "gc,heap";
private static final String TAG_GC_METASPACE = "gc,metaspace";

private static final String TAG_GC_PHASES = "gc,phases";

/** list of strings, that must be part of the gc log line to be considered for parsing */
private static final List<String> INCLUDE_STRINGS = Arrays.asList("[gc ", "[gc]", "[" + TAG_GC_START, "[" + TAG_GC_HEAP, "[" + TAG_GC_METASPACE);
private static final List<String> INCLUDE_STRINGS = Arrays.asList("[gc ", "[gc]", "[" + TAG_GC_START, "[" + TAG_GC_HEAP, "[" + TAG_GC_METASPACE, "[" + TAG_GC_PHASES);
/** list of strings, that target gc log lines, that - although part of INCLUDE_STRINGS - are not considered a gc event */
private static final List<String> EXCLUDE_STRINGS = Arrays.asList("Cancelling concurrent GC", "[debug", "[trace", "gc,heap,coops", "gc,heap,exit");
private static final List<String> EXCLUDE_STRINGS = Arrays.asList("Cancelling concurrent GC", "[debug", "[trace", "gc,heap,coops", "gc,heap,exit", "[gc,phases,start");
/** list of strings, that are gc log lines, but not a gc event -&gt; should be logged only */
private static final List<String> LOG_ONLY_STRINGS = Arrays.asList("Using", "Heap region size");


protected DataReaderUnifiedJvmLogging(GCResource gcResource, InputStream in) throws UnsupportedEncodingException {
super(gcResource, in);
}
Expand All @@ -140,7 +170,7 @@ public GCModel read() throws IOException {
getLogger().info("Reading Oracle / OpenJDK unified jvm logging format...");

try {
// some information shared accross several lines of parsing...
// some information shared across several lines of parsing...
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks :-)!

Map<String, AbstractGCEvent<?>> partialEventsMap = new HashMap<>();
Map<String, Object> infoMap = new HashMap<>();

Expand All @@ -162,7 +192,6 @@ public GCModel read() throws IOException {

private ParseContext parseEvent(ParseContext context) {
AbstractGCEvent<?> event = null;

Matcher decoratorsMatcher = PATTERN_DECORATORS.matcher(context.getLine());
try {
event = createGcEventWithStandardDecorators(decoratorsMatcher, context.getLine());
Expand All @@ -185,46 +214,96 @@ private AbstractGCEvent<?> handleTail(ParseContext context, AbstractGCEvent<?> e
AbstractGCEvent<?> returnEvent = event;
switch (tags) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks nice to have this switch shortened and the code moved to separate methods!

case TAG_GC_START:
// here, the gc type is known, and the partial events will need to be added later
context.getPartialEventsMap().put(event.getNumber() + "", event);
returnEvent = null;
returnEvent = handleTagGcStartTail(context, event);
break;
case TAG_GC_HEAP:
returnEvent = handleTagGcHeapTail(context, event, tail);
// ZGC heap capacity, break out and handle next event
if (returnEvent == null) {
break;
}
// fallthrough -> same handling as for METASPACE event
case TAG_GC_METASPACE:
event = parseTail(context, event, tail);
// the UJL "Old" event occurs often after the next STW events have taken place; ignore it for now
// size after concurrent collection will be calculated by GCModel#add()
if (!event.getExtendedType().getType().equals(Type.UJL_CMS_CONCURRENT_OLD)) {
updateEventDetails(context, event);
}
returnEvent = null;
returnEvent = handleTagGcMetaspaceTail(context, event, tail);
break;
case TAG_GC:
AbstractGCEvent<?> parentEvent = context.getPartialEventsMap().get(event.getNumber() + "");
if (parentEvent != null) {
if (parentEvent.getExtendedType().equals(returnEvent.getExtendedType())) {
// date- and timestamp are always end of event -> adjust the parent event
parentEvent.setDateStamp(event.getDatestamp());
parentEvent.setTimestamp(event.getTimestamp());
returnEvent = parseTail(context, parentEvent, tail);
context.partialEventsMap.remove(event.getNumber() + "");
} else {
// more detail information is provided for the parent event
updateEventDetails(context, returnEvent);
returnEvent = null;
}
} else {
returnEvent = parseTail(context, event, tail);
}
returnEvent = handleTagGcTail(context, event, tail);
break;
case TAG_GC_PHASES:
returnEvent = handleTagGcPhasesTail(context, event, tail);
break;
default:
getLogger().warning(String.format("Unexpected tail present in the end of line number %d (tail=\"%s\"; line=\"%s\")", in.getLineNumber(), tail, context.getLine()));
}

return returnEvent;
}

private AbstractGCEvent<?> handleTagGcStartTail(ParseContext context, AbstractGCEvent<?> event) {
// here, the gc type is known, and the partial events will need to be added later
context.getPartialEventsMap().put(event.getNumber() + "", event);
return null;
}

private AbstractGCEvent<?> handleTagGcPhasesTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
AbstractGCEvent<?> returnEvent = event;

AbstractGCEvent<?> parentEvent = context.getPartialEventsMap().get(event.getNumber() + "");
if (parentEvent instanceof GCEventUJL) {
returnEvent = parseTail(context, returnEvent, tail);
parentEvent.addPhase(returnEvent);
}

return null;
}

private AbstractGCEvent<?> handleTagGcMetaspaceTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
AbstractGCEvent<?> returnEvent = event;
returnEvent = parseTail(context, returnEvent, tail);
// the UJL "Old" event occurs often after the next STW events have taken place; ignore it for now
// size after concurrent collection will be calculated by GCModel#add()
if (!returnEvent.getExtendedType().getType().equals(Type.UJL_CMS_CONCURRENT_OLD)) {
updateEventDetails(context, returnEvent);
}
return null;
}

private AbstractGCEvent<?> handleTagGcTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
AbstractGCEvent<?> returnEvent = event;
AbstractGCEvent<?> parentEvent = context.getPartialEventsMap().get(event.getNumber() + "");
if (parentEvent != null) {
if (parentEvent.getExtendedType().equals(returnEvent.getExtendedType())) {
// date- and timestamp are always end of event -> adjust the parent event
parentEvent.setDateStamp(event.getDatestamp());
parentEvent.setTimestamp(event.getTimestamp());
returnEvent = parseTail(context, parentEvent, tail);
context.partialEventsMap.remove(event.getNumber() + "");
} else {
// more detail information is provided for the parent event
updateEventDetails(context, returnEvent);
returnEvent = null;
}
} else {
returnEvent = parseTail(context, event, tail);
}

return returnEvent;
}

private AbstractGCEvent<?> handleTagGcHeapTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
AbstractGCEvent<?> returnEvent = event;
AbstractGCEvent<?> parentEvent = context.getPartialEventsMap().get(event.getNumber() + "");
// if ZGC heap capacity, record total heap for this event, then pass it on to record pre and post used heap
if (event.getExtendedType().getType().equals(Type.UJL_ZGC_HEAP_CAPACITY) && parentEvent != null) {
// Parse with correct pattern and match the total memory
returnEvent = parseTail(context, event, tail);
parentEvent.setTotal(returnEvent.getTotal());
context.partialEventsMap.put(event.getNumber() + "", parentEvent);
returnEvent = null;
}
return returnEvent;
}

private void updateEventDetails(ParseContext context, AbstractGCEvent<?> event) {
AbstractGCEvent<?> parentEvent = context.getPartialEventsMap().get(event.getNumber() + "");
if (parentEvent == null) {
Expand All @@ -249,13 +328,17 @@ private AbstractGCEvent<?> parseTail(ParseContext context, AbstractGCEvent<?> ev
parseGcMemoryPauseTail(context, event, tail);
} else if (event.getExtendedType().getPattern().equals(GcPattern.GC) || event.getExtendedType().getPattern().equals(GcPattern.GC_PAUSE_DURATION)) {
parseGcTail(context, tail);
} else if (event.getExtendedType().getPattern().equals(GcPattern.GC_MEMORY_PERCENTAGE)) {
parseGcMemoryPercentageTail(context, event, tail);
} else if (event.getExtendedType().getPattern().equals(GcPattern.GC_HEAP_MEMORY_PERCENTAGE)) {
parseGcHeapMemoryPercentageTail(context, event, tail);
}

return event;
}

private void parseGcTail(ParseContext context, String tail) {
if (!(tail == null)) {
if (tail != null) {
getLogger().warning(String.format("Unexpected tail present in the end of line number %d (expected nothing to be present, tail=\"%s\"; line=\"%s\")", in.getLineNumber(), tail, context.getLine()));
}
}
Expand Down Expand Up @@ -317,6 +400,29 @@ private void parseGcRegionTail(ParseContext context, AbstractGCEvent<?> event, S
getLogger().warning(String.format("Expected region information in the end of line number %d (line=\"%s\")", in.getLineNumber(), context.getLine()));
}
}

private void parseGcMemoryPercentageTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
Matcher memoryPercentageMatcher = tail != null ? PATTERN_MEMORY_PERCENTAGE.matcher(tail) : null;
if (memoryPercentageMatcher != null && memoryPercentageMatcher.find()) {
// the end Garbage Collection tags in ZGC contain details of memory cleaned up
// and the percentage of memory used before and after clean. The details can be used to
// determine Allocation rate.
setMemoryWithPercentage(event, memoryPercentageMatcher);
} else {
getLogger().warning(String.format("Expected memory percentage in the end of line number %d (line=\"%s\")", in.getLineNumber(), context.getLine()));
}
}

private void parseGcHeapMemoryPercentageTail(ParseContext context, AbstractGCEvent<?> event, String tail) {
Matcher memoryPercentageMatcher = tail != null ? PATTERN_HEAP_MEMORY_PERCENTAGE.matcher(tail) : null;
if (memoryPercentageMatcher != null && memoryPercentageMatcher.find()) {
// Heap section in ZGC logs provide heap stats during the GC cycle
// Currently using to get total heap size, percentage for total heap is not useful
setMemoryHeapWithPercentage(event, memoryPercentageMatcher);
} else {
getLogger().warning(String.format("Expected heap memory percentage in the end of line number %d (line=\"%s\")", in.getLineNumber(), context.getLine()));
}
}

/**
* Returns an instance of AbstractGcEvent (GCEvent or ConcurrentGcEvent) with all decorators present filled in
Expand Down Expand Up @@ -362,6 +468,18 @@ private void setMemory(AbstractGCEvent event, Matcher matcher) {
Integer.parseInt(matcher.group(GROUP_MEMORY_CURRENT_TOTAL)), matcher.group(GROUP_MEMORY_CURRENT_TOTAL_UNIT).charAt(0), matcher.group(GROUP_MEMORY)));
}

private void setMemoryHeapWithPercentage(AbstractGCEvent<?> event, Matcher matcher) {
event.setTotal(getDataReaderTools().getMemoryInKiloByte(
Integer.parseInt(matcher.group(GROUP_HEAP_MEMORY_PERCENTAGE_VALUE)), matcher.group(GROUP_HEAP_MEMORY_PERCENTAGE_UNIT).charAt(0), matcher.group(GROUP_HEAP_MEMORY_PERCENTAGE)));
}

private void setMemoryWithPercentage(AbstractGCEvent<?> event, Matcher matcher) {
event.setPreUsed(getDataReaderTools().getMemoryInKiloByte(
Integer.parseInt(matcher.group(GROUP_MEMORY_PERCENTAGE_BEFORE)), matcher.group(GROUP_MEMORY_PERCENTAGE_BEFORE_UNIT).charAt(0), matcher.group(GROUP_MEMORY_PERCENTAGE)));
event.setPostUsed(getDataReaderTools().getMemoryInKiloByte(
Integer.parseInt(matcher.group(GROUP_MEMORY_PERCENTAGE_AFTER)), matcher.group(GROUP_MEMORY_PERCENTAGE_AFTER_UNIT).charAt(0), matcher.group(GROUP_MEMORY_PERCENTAGE)));
}

private void setDateStampIfPresent(AbstractGCEvent<?> event, String dateStampAsString) {
// TODO remove code duplication with AbstractDataReaderSun -> move to DataReaderTools
if (dateStampAsString != null) {
Expand Down
Loading