From 6940be095958b4786fbd2e0cfe74511512a9049a Mon Sep 17 00:00:00 2001
From: MaysWind
Date: Wed, 26 Apr 2023 00:54:18 +0800
Subject: [PATCH 1/2] support all of ujl decorators, allow log only contains
time or uptime
---
.../imp/DataReaderUnifiedJvmLogging.java | 110 ++++-
.../imp/TestDataReaderUJLDecorations.java | 387 ++++++++++++++++++
2 files changed, 476 insertions(+), 21 deletions(-)
create mode 100644 src/test/java/com/tagtraum/perf/gcviewer/imp/TestDataReaderUJLDecorations.java
diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
index 5ebeed0c..62a321fe 100644
--- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
+++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
@@ -3,6 +3,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -29,13 +32,13 @@
/**
* DataReaderUnifiedJvmLogging can parse all gc events of unified jvm logs with default decorations.
*
- * Currently needs the "gc" selector with "info" level and "uptime,level,tags" decorators (Java 9.0.1).
+ * Currently needs the "gc" selector with "info" level and "uptime,level,tags" (or "time,level,tags") decorators (Java 9.0.1).
* Also supports "gc*" selector with "trace" level and "time,uptime,level,tags" decorators, but will ignore some of
* the debug and all trace level info (evaluates the following tags: "gc", "gc,start", "gc,heap", "gc,metaspace".
*
* minimum configuration with defaults supported: -Xlog:gc:file="path-to-file"
- * explicit minimum configuration needed: -Xlog:gc=info:file="path-to-file":tags,uptime,level
- * maximum detail configuration this parser is able to work with: -Xlog:gc*=trace:file="path-to-file":tags,time,uptime,level
+ * explicit minimum configuration needed: -Xlog:gc=info:file="path-to-file":uptime,level,tags
or -Xlog:gc=info:file="path-to-file":time,level,tags
+ * maximum detail configuration this parser is able to work with: -Xlog:gc*=trace:file="path-to-file":time,uptime,timemillis,uptimemillis,timenanos,uptimenanos,pid,tid,level,tags
*
* Only processes the following information format for Serial, Parallel, CMS, G1 and Shenandoah algorithms, everything else is ignored:
*
@@ -51,28 +54,56 @@ public class DataReaderUnifiedJvmLogging extends AbstractDataReader {
// TODO also parse "Allocation Stall (main)" events
// matches the whole line and extracts decorators from it (decorators always appear between [] and are independent of the gc algorithm being logged)
- // Input: [0.693s][info][gc ] GC(0) Pause Init Mark 1.070ms
- // Group 1 / time: (optional group, no full timestamp present)
- // Group 2 / uptime: 0.693 (optional group, present in this example)
- // Group 3 / level: info
- // Group 4 / tags: gc
- // Group 5 / gcnumber: 0
- // Group 6 / tail: Pause Init Mark 1.070ms
- // Regex: ^(?:\[(?[0-9-T:.+]*)])?(?:\[(?[^s]*)s])?\[(?[^]]+)]\[(?:(?[^] ]+)[ ]*)][ ]GC\((?[0-9]+)\)[ ](?([-.a-zA-Z ()]+|[a-zA-Z1 ()]+))(?:(?:[ ](?[0-9]{1}.*))|$)
+ // Input: [2023-01-01T00:00:14.206+0000][14.206s][1672531214206ms][14205ms][1000014205707082ns][14205707082ns][6000][6008][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 4115M->103M(8192M) 28.115ms
+ // reference: https://openjdk.org/jeps/158
+ // Group 1 / time: 2023-01-01T00:00:14.206+0800 (Current time and date in ISO-8601 format)
+ // Group 2 / uptime: 14.206s (Time since the start of the JVM in seconds and milliseconds)
+ // Group 3 / timemillis: 1672531214206ms (The same value as generated by System.currentTimeMillis())
+ // Group 4 / uptimemillis: 14205ms (Milliseconds since the JVM started)
+ // Group 5 / timenanos: 1000014205707082ns (The same value as generated by System.nanoTime())
+ // Group 6 / uptimenanos: 14205707082ns (Nanoseconds since the JVM started)
+ // Group 7 / pid: 6000 (The process identifier)
+ // Group 8 / tid: 6008 (The thread identifier)
+ // Group 9 / level: info (The level associated with the log message)
+ // Group 10 / tags: gc (The tag-set associated with the log message)
+ // Group 11 / gcnumber: 0
+ // Group 12 / tail: Pause Init Mark 1.070ms
+ // Regex: (see the below)
// note for the part: easiest would have been to use [^0-9]+, but the G1 events don't fit there, because of the number in their name
// add sub regex "[a-zA-Z ]+\\(.+\\)" for Allocation Stall and Relocation Stall of ZGC
private static final Pattern PATTERN_DECORATORS = Pattern.compile(
- "^(?:\\[(?[0-9-T:.+]*)])?(?:\\[(?[^ms]*)(?m?s)])?\\[(?[^]]+)]\\[(?:(?[^] ]+)[ ]*)][ ](GC\\((?[0-9]+)\\)[ ])?(?(?:Phase [0-9]{1}: [a-zA-Z ]+)|[-.a-zA-Z: ()]+|[a-zA-Z1 ()]+|[a-zA-Z ]+\\(.+\\))(?:(?:[ ](?[0-9]{1}.*))|$)"
+ "^" +
+ "(?:\\[(?[0-9-T:.+]*)])?" +
+ "(?:\\[(?[0-9.,]+)s[ ]*])?" +
+ "(?:\\[(?[0-9]+)ms[ ]*])?" +
+ "(?:\\[(?[0-9]+)ms[ ]*])?" +
+ "(?:\\[(?[0-9]+)ns[ ]*])?" +
+ "(?:\\[(?[0-9]+)ns[ ]*])?" +
+ "(?:\\[(?[0-9]+)[ ]*])?" +
+ "(?:\\[(?[0-9]+)[ ]*])?" +
+ "\\[(?[^]]+)]" +
+ "\\[(?:(?[^] ]+)[ ]*)]" +
+ "[ ]" +
+ "(GC\\((?[0-9]+)\\)[ ])?" +
+ "(?(?:Phase [0-9]{1}: [a-zA-Z ]+)|[-.a-zA-Z: ()]+|[a-zA-Z1 ()]+|[a-zA-Z ]+\\(.+\\))" +
+ "(?:(?:[ ](?[0-9]{1}.*))|$)"
);
private static final String GROUP_DECORATORS_TIME = "time";
private static final String GROUP_DECORATORS_UPTIME = "uptime";
- private static final String GROUP_DECORATORS_UPTIME_UNIT = "uptimeunit";
+ private static final String GROUP_DECORATORS_TIME_MILLIS = "timemillis";
+ private static final String GROUP_DECORATORS_UPTIME_MILLIS = "uptimemillis";
+ private static final String GROUP_DECORATORS_TIME_NANOS = "timenanos";
+ private static final String GROUP_DECORATORS_UPTIME_NANOS = "uptimenanos";
+ private static final String GROUP_DECORATORS_PID = "pid";
+ private static final String GROUP_DECORATORS_TID = "tid";
private static final String GROUP_DECORATORS_LEVEL = "level";
private static final String GROUP_DECORATORS_TAGS = "tags";
private static final String GROUP_DECORATORS_GC_NUMBER = "gcnumber";
private static final String GROUP_DECORATORS_GC_TYPE = "type";
private static final String GROUP_DECORATORS_TAIL = "tail";
+ private static final long MIN_VALID_UNIX_TIME_MILLIS = 1000000000000L; // 2001-09-09 09:46:40
+
private static final Pattern PATTERN_HEAP_REGION_SIZE = Pattern.compile("^Heap [Rr]egion [Ss]ize: ([0-9]+)M$");
private static final int GROUP_HEAP_REGION_SIZE = 1;
@@ -267,7 +298,7 @@ private AbstractGCEvent> handleTail(ParseContext context, AbstractGCEvent> e
returnEvent = handleTagGcHeapTail(context, event, tail);
// ZGC heap capacity, break out and handle next event
if (returnEvent == null) {
- break;
+ break;
}
// fallthrough -> same handling as for METASPACE event
case TAG_GC_METASPACE:
@@ -277,8 +308,8 @@ private AbstractGCEvent> handleTail(ParseContext context, AbstractGCEvent> e
returnEvent = handleTagGcTail(context, event, tail);
break;
case TAG_GC_PHASES:
- returnEvent = handleTagGcPhasesTail(context, event, tail);
- break;
+ 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()));
}
@@ -485,7 +516,7 @@ private void parseGcMemoryPercentageTail(ParseContext context, AbstractGCEvent
// 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);
+ setMemoryWithPercentage(event, memoryPercentageMatcher);
} else {
getLogger().warning(String.format("Expected memory percentage in the end of line number %d (line=\"%s\")", in.getLineNumber(), context.getLine()));
}
@@ -518,8 +549,39 @@ private AbstractGCEvent> createGcEventWithStandardDecorators(Matcher decorator
if (decoratorsMatcher.group(GROUP_DECORATORS_GC_NUMBER) != null) {
event.setNumber(Integer.parseInt(decoratorsMatcher.group(GROUP_DECORATORS_GC_NUMBER)));
}
- setDateStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_TIME));
- setTimeStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_UPTIME), decoratorsMatcher.group(GROUP_DECORATORS_UPTIME_UNIT));
+
+ boolean hasTime = setDateStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_TIME));
+ boolean hasUptime = setTimeStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_UPTIME), "s");
+
+ // The second time is the uptime for sure when the text contains two pairs of millisecond time
+ if (decoratorsMatcher.group(GROUP_DECORATORS_TIME_MILLIS) != null && decoratorsMatcher.group(GROUP_DECORATORS_UPTIME_MILLIS) != null) {
+ if (!hasTime) {
+ long timeInMillisecond = Long.parseLong(decoratorsMatcher.group(GROUP_DECORATORS_TIME_MILLIS));
+ hasTime = setDateStampIfPresent(event, DateHelper.formatDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(timeInMillisecond), ZoneId.systemDefault()))) || hasTime;
+ }
+
+ hasUptime = setTimeStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_UPTIME_MILLIS), "ms") || hasUptime;
+ } else if (decoratorsMatcher.group(GROUP_DECORATORS_TIME_MILLIS) != null) {
+ // If the first millisecond time below the valid unix time, it may be uptime, otherwise it may be unix time
+ long millisecond = Long.parseLong(decoratorsMatcher.group(GROUP_DECORATORS_TIME_MILLIS));
+
+ if (millisecond < MIN_VALID_UNIX_TIME_MILLIS) {
+ hasUptime = setTimeStampIfPresent(event, String.valueOf(millisecond), "ms") || hasUptime;
+ } else {
+ hasTime = setDateStampIfPresent(event, DateHelper.formatDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(millisecond), ZoneId.systemDefault()))) || hasTime;
+ }
+ }
+
+ // The second time is the uptime for sure only if the text contains two pairs of nanosecond time
+ if (decoratorsMatcher.group(GROUP_DECORATORS_TIME_NANOS) != null && decoratorsMatcher.group(GROUP_DECORATORS_UPTIME_NANOS) != null) {
+ hasUptime = setTimeStampIfPresent(event, decoratorsMatcher.group(GROUP_DECORATORS_UPTIME_NANOS), "ns") || hasUptime;
+ }
+
+ if (!hasTime && !hasUptime) {
+ getLogger().warning(String.format("Failed to parse line number %d (no valid time or timestamp; line=\"%s\")", in.getLineNumber(), line));
+ return null;
+ }
+
return event;
} else {
getLogger().warning(String.format("Failed to parse line number %d (no match; line=\"%s\")", in.getLineNumber(), line));
@@ -576,21 +638,27 @@ private void setMemoryWithPercentage(AbstractGCEvent> event, Matcher matcher)
}
}
- private void setDateStampIfPresent(AbstractGCEvent> event, String dateStampAsString) {
+ private boolean setDateStampIfPresent(AbstractGCEvent> event, String dateStampAsString) {
// TODO remove code duplication with AbstractDataReaderSun -> move to DataReaderTools
if (dateStampAsString != null) {
event.setDateStamp(DateHelper.parseDate(dateStampAsString));
+ return true;
}
+ return false;
}
- private void setTimeStampIfPresent(AbstractGCEvent> event, String timeStampAsString, String timeUnit) {
+ private boolean setTimeStampIfPresent(AbstractGCEvent> event, String timeStampAsString, String timeUnit) {
if (timeStampAsString != null && timeStampAsString.length() > 0) {
double timestamp = NumberParser.parseDouble(timeStampAsString);
if ("ms".equals(timeUnit)) {
timestamp = timestamp / 1000;
+ } else if ("ns".equals(timeUnit)) {
+ timestamp = timestamp / 1000000000;
}
event.setTimestamp(timestamp);
+ return true;
}
+ return false;
}
private boolean isExcludedLine(String line) {
diff --git a/src/test/java/com/tagtraum/perf/gcviewer/imp/TestDataReaderUJLDecorations.java b/src/test/java/com/tagtraum/perf/gcviewer/imp/TestDataReaderUJLDecorations.java
new file mode 100644
index 00000000..7d97a410
--- /dev/null
+++ b/src/test/java/com/tagtraum/perf/gcviewer/imp/TestDataReaderUJLDecorations.java
@@ -0,0 +1,387 @@
+package com.tagtraum.perf.gcviewer.imp;
+
+import com.tagtraum.perf.gcviewer.model.GCEvent;
+import com.tagtraum.perf.gcviewer.model.GCModel;
+import com.tagtraum.perf.gcviewer.model.GCResource;
+import com.tagtraum.perf.gcviewer.model.GcResourceFile;
+import com.tagtraum.perf.gcviewer.util.DateHelper;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.logging.Level;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Test unified java logging with different decorations
+ */
+public class TestDataReaderUJLDecorations {
+ @Test
+ public void testUJLWithTimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[2022-04-19T19:34:40.899+0000][info][gc,init] Heap Region Size: 2M\n" +
+ "[2022-01-29T16:34:51.601+0000][info][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[2022-01-29T16:34:51.601+0000][info][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[2022-01-29T16:34:51.608+0000][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[2022-01-29T16:34:51.608+0000][info][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[2022-01-29T16:34:51.609+0000][info][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[2022-01-29T16:34:51.609+0000][info][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[2022-01-29T16:34:51.609+0000][info][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[2022-01-29T16:34:51.609+0000][info][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[2022-01-29T16:34:51.610+0000][info][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[2022-01-29T16:34:51.610+0000][info][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[2022-01-29T16:34:51.610+0000][info][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[2022-01-29T16:34:51.610+0000][info][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[2022-01-29T16:34:51.611+0000][info][gc,metaspace] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[2022-01-29T16:34:51.611+0000][info][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[2022-01-29T16:34:51.612+0000][info][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event time", "2022-01-29T16:34:51.610+0000", DateHelper.formatDate(tenuredEvent.getDatestamp()));
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithUptimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[0.023s][info][gc,init] Heap Region Size: 2M\n" +
+ "[0.192s][info][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[0.192s][info][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[0.199s][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[0.199s][info][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[0.200s][info][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[0.200s][info][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[0.200s][info][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[0.201s][info][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[0.201s][info][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[0.201s][info][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[0.201s][info][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[0.202s][info][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[0.202s][info][gc,metaspace] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[0.203s][info][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[0.203s][info][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event timestamp", 0.202, tenuredEvent.getTimestamp(), 0.001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithTimePidTidLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[2022-04-19T19:34:40.899+0000][11][44][info][gc,init] Heap Region Size: 2M\n" +
+ "[2022-01-29T16:34:51.601+0000][11][50][info][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[2022-01-29T16:34:51.601+0000][11][50][info][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[2022-01-29T16:34:51.608+0000][11][50][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[2022-01-29T16:34:51.608+0000][11][50][info][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[2022-01-29T16:34:51.609+0000][11][50][info][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[2022-01-29T16:34:51.609+0000][11][50][info][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[2022-01-29T16:34:51.609+0000][11][50][info][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[2022-01-29T16:34:51.609+0000][11][50][info][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[2022-01-29T16:34:51.610+0000][11][50][info][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[2022-01-29T16:34:51.610+0000][11][50][info][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[2022-01-29T16:34:51.610+0000][11][50][info][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[2022-01-29T16:34:51.610+0000][11][50][info][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[2022-01-29T16:34:51.611+0000][11][50][info][gc,metaspace] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[2022-01-29T16:34:51.611+0000][11][50][info][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[2022-01-29T16:34:51.612+0000][11][50][info][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event time", "2022-01-29T16:34:51.610+0000", DateHelper.formatDate(tenuredEvent.getDatestamp()));
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithUptimePidTidLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[0.023s][11][50][info][gc,init] Heap Region Size: 2M\n" +
+ "[0.192s][11][50][info][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[0.192s][11][50][info][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[0.199s][11][50][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[0.199s][11][50][info][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[0.200s][11][50][info][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[0.200s][11][50][info][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[0.200s][11][50][info][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[0.201s][11][50][info][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[0.201s][11][50][info][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[0.201s][11][50][info][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[0.201s][11][50][info][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[0.202s][11][50][info][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[0.202s][11][50][info][gc,metaspace] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[0.203s][11][50][info][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[0.203s][11][50][info][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event timestamp", 0.202, tenuredEvent.getTimestamp(), 0.001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithMillsTimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[1682424038948ms][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[1682424051450ms][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[1682424051451ms][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[1682424051479ms][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[1682424051479ms][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[1682424051479ms][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[1682424051479ms][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[1682424051479ms][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[1682424051479ms][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[1682424051479ms][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[1682424051479ms][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[1682424051479ms][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[1682424051479ms][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[1682424051479ms][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[1682424051480ms][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[1682424051480ms][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event time", 1682424051479L, tenuredEvent.getDatestamp().toInstant().toEpochMilli());
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithMillsUptimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[36ms][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[12538ms][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[12539ms][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[12567ms][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[12567ms][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[12567ms][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[12567ms][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[12567ms][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[12567ms][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[12567ms][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[12567ms][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[12567ms][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[12567ms][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[12567ms][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[12567ms][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[12568ms][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event timestamp", 12.567, tenuredEvent.getTimestamp(), 0.001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithMillsTimeMillsUptimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[1682424038948ms][36ms][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[1682424051450ms][12538ms][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[1682424051451ms][12539ms][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[1682424051479ms][12567ms][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[1682424051479ms][12567ms][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[1682424051479ms][12567ms][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[1682424051479ms][12567ms][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[1682424051479ms][12567ms][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[1682424051479ms][12567ms][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[1682424051479ms][12567ms][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[1682424051479ms][12567ms][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[1682424051479ms][12567ms][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[1682424051479ms][12567ms][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[1682424051479ms][12567ms][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[1682424051480ms][12567ms][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[1682424051480ms][12568ms][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event time", 1682424051479L, tenuredEvent.getDatestamp().toInstant().toEpochMilli());
+ assertEquals("tenured event timestamp", 12.567, tenuredEvent.getTimestamp(), 0.001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithNanoTimeNanoUptimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[3713267866602725ns][36215026ns][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[3713280368972030ns][12538584330ns][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[3713280369719424ns][12539331741ns][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[3713280397999190ns][12567611501ns][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[3713280398055938ns][12567668275ns][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[3713280398065376ns][12567677692ns][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[3713280398073261ns][12567685567ns][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[3713280398085351ns][12567697659ns][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[3713280398183418ns][12567795761ns][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[3713280398210215ns][12567822522ns][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[3713280398223704ns][12567836010ns][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[3713280398236252ns][12567848558ns][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[3713280398260137ns][12567872443ns][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[3713280398275986ns][12567888293ns][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[3713280398371361ns][12567983672ns][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[3713280398396786ns][12568009089ns][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event timestamp", 12.567872443, tenuredEvent.getTimestamp(), 0.000000001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+
+ @Test
+ public void testUJLWithOnlyOneNanoTimeLevelTagsDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[36215026ns][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[12538584330ns][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[12539331741ns][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[12567611501ns][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[12567668275ns][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[12567677692ns][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[12567685567ns][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[12567697659ns][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[12567795761ns][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[12567822522ns][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[12567836010ns][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[12567848558ns][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[12567872443ns][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[12567888293ns][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[12567983672ns][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[12568009089ns][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertNotEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 0, model.size());
+ }
+
+ @Test
+ public void testUJLWithAllDecorations() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ handler.setLevel(Level.WARNING);
+ GCResource gcResource = new GcResourceFile("byteArray");
+ gcResource.getLogger().addHandler(handler);
+ InputStream in = new ByteArrayInputStream(
+ ("[2023-04-25T20:00:38.948+0800][0.036s][1682424038948ms][36ms][3713267866602725ns][36215026ns][15][49][info ][gc,init ] Heap Region Size: 2M\n" +
+ "[2023-04-25T20:00:51.450+0800][12.539s][1682424051450ms][12538ms][3713280368972030ns][12538584330ns][15][55 ][info ][gc,start ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)\n" +
+ "[2023-04-25T20:00:51.451+0800][12.539s][1682424051451ms][12539ms][3713280369719424ns][12539331741ns][15][55 ][info ][gc,task ] GC(0) Using 1 workers of 1 for evacuation\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280397999190ns][12567611501ns][15][55 ][info ][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398055938ns][12567668275ns][15][55 ][info ][gc,phases ] GC(0) Merge Heap Roots: 0.2ms\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398065376ns][12567677692ns][15][55 ][info ][gc,phases ] GC(0) Evacuate Collection Set: 4.8ms\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398073261ns][12567685567ns][15][55 ][info ][gc,phases ] GC(0) Post Evacuate Collection Set: 1.0ms\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398085351ns][12567697659ns][15][55 ][info ][gc,phases ] GC(0) Other: 0.9ms\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398183418ns][12567795761ns][15][55 ][info ][gc,heap ] GC(0) Eden regions: 2->0(1)\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398210215ns][12567822522ns][15][55 ][info ][gc,heap ] GC(0) Survivor regions: 0->1(1)\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398223704ns][12567836010ns][15][55 ][info ][gc,heap ] GC(0) Old regions: 0->1\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398236252ns][12567848558ns][15][55 ][info ][gc,heap ] GC(0) Archive regions: 2->2\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398260137ns][12567872443ns][15][55 ][info ][gc,heap ] GC(0) Humongous regions: 0->0\n" +
+ "[2023-04-25T20:00:51.479+0800][12.568s][1682424051479ms][12567ms][3713280398275986ns][12567888293ns][15][55 ][info ][gc,metaspace ] GC(0) Metaspace: 257K(448K)->257K(448K) NonClass: 242K(320K)->242K(320K) Class: 15K(128K)->15K(128K)\n" +
+ "[2023-04-25T20:00:51.480+0800][12.568s][1682424051480ms][12567ms][3713280398371361ns][12567983672ns][15][55 ][info ][gc ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 2M->2M(18M) 10.669ms\n" +
+ "[2023-04-25T20:00:51.480+0800][12.568s][1682424051480ms][12568ms][3713280398396786ns][12568009089ns][15][55 ][info ][gc,cpu ] GC(0) User=0.00s Sys=0.00s Real=0.01s\n")
+ .getBytes());
+
+ DataReader reader = new DataReaderUnifiedJvmLogging(gcResource, in);
+ GCModel model = reader.read();
+ assertEquals("number of warnings", 0, handler.getCount());
+ assertEquals("number of events", 1, model.size());
+
+ GCEvent tenuredEvent = ((GCEvent)model.get(0)).getTenured();
+ assertNotNull("tenured event", tenuredEvent);
+ assertEquals("tenured event time", "2023-04-25T20:00:51.479+0800", DateHelper.formatDate(tenuredEvent.getDatestamp()));
+ assertEquals("tenured event timestamp", 12.567872443, tenuredEvent.getTimestamp(), 0.000000001);
+ assertEquals("tenured event pre", 2 * 2048, tenuredEvent.getPreUsed());
+ assertEquals("tenured event post", 3 * 2048, tenuredEvent.getPostUsed());
+ }
+}
From ba5c9b84a3db7aecf731b2dcd822caa8f8b8ab41 Mon Sep 17 00:00:00 2001
From: MaysWind
Date: Fri, 9 Jun 2023 23:00:08 +0800
Subject: [PATCH 2/2] exclude oom log
---
.../tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
index 62a321fe..6a98cdc4 100644
--- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
+++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderUnifiedJvmLogging.java
@@ -205,6 +205,7 @@ public class DataReaderUnifiedJvmLogging extends AbstractDataReader {
"[trace",
"gc,heap,coops",
"gc,heap,exit",
+ "gc,metaspace,freelist,oom",
"[gc,phases,start",
"Trigger: ",
"Failed to allocate",