diff --git a/.bettercodehub.yml b/.bettercodehub.yml deleted file mode 100644 index 6a8c6cc9..00000000 --- a/.bettercodehub.yml +++ /dev/null @@ -1,3 +0,0 @@ -component_depth: 8 -languages: -- java diff --git a/.github/workflows/pullrequest.yaml b/.github/workflows/pullrequest.yaml new file mode 100644 index 00000000..e880289b --- /dev/null +++ b/.github/workflows/pullrequest.yaml @@ -0,0 +1,35 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: pull request build + +on: + pull_request: + branches: [ "develop" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + java: [ '8' , '11', '17' , '21'] + name: build with Java ${{ matrix.Java }} + steps: + - uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.Java }} + distribution: 'temurin' + cache: maven + - name: run headless maven build + uses: coactions/setup-xvfb@v1 + with: + run: mvn -B clean verify javadoc:javadoc + options: -screen 0 1280x1024x16 diff --git a/.travis.yml b/.travis.yml index 3e4d1eb6..3d33cc6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,8 @@ env: - GPG_DIR="`pwd`/cicd/gpg" - secure: arRS4YHFdZWyl7KmduSdzOF1JGm1qOWDLp1fwtzCkGUx58G3RrhhBIynK3TuSnnUTYsmS+DyxR/R+v3QhaEjschR4Aeolq9StJGvUBssTS+oCqcLe3qLiHyy9YClCb8xSPebYNgrxEox0MuEGG73TFRUrGLHxesBo9OfLgIiGpV+kez2cBD+iFWEfNA9oeO3x3fa7Ry/YBrRfUkA5gKR41Bw/oOf+5T0HAKMpfMMmCneu7EtA3z7cWHhEEBwydwUI+szS3ozsbyUcleLwTlwabLXEB3rF3c/rU2Zy/1CLfWzJwCmy47HfclTalj/ckNxh5pK9aQwVqFM3B8ECPBUOksYm28oREgcRFbLqrtRnrKMM5tvqHXsb3r7VyJkNzFenV8e3WES8kCL7z5yuCstac395AlLRBCWTEWbHiiKTIYfx4awY5lK2CxptCf+8mzzkfltQp6HOViLw+X9c/G4MNTUWlDeMnw3JB81Rm5qaKv4gNjq9G0cPS9rzRN6SwksIEZ2i2JmVzCOoU7tWgH6ahcBDU3jJI3bwODzkzND5j0y9jKtooYEKPAH2v5b/uB/6KIlCLa/jZQcCzuTrOlKT6/Zcxl4aDUonuJ8vUDl3gMj72iqZpNosqOWIL0YVy8wlmxCaai3MK2H1647Mw5DXWzIciSN/TLwCjF3344fxHc= - secure: L2mbuVWefCqtdy9qNcVtxW5nI2/kLY6vTXasQ19mevfxCHcyN23d8zDvCU0lRT9k9k9znXrF3JppzLwW2wkZo72XADQj+hfCSCB8axu1NQPPi3IMkFe4/c/mEXRVHYvukEjTX10BmZUfjL2H2XRiLM2eOunbRxyE6DfmIz6HuW5LS3iNi9BZQce6iHm/jG0Li+SxCgqetwZ3/Gowl1vo5vfg+xVnqTalYuSfvlJAAKfZdkw47/5T0np7ooD4W0TfFohFpq2DlVK1m27qSc0tDe9CT7YkAXid7giVfe+RC5rEoJhKf87wuKC/hitUS+OJb6hJg3IVGhsiA44w57eK6g7Gm+nDrJzId8XOYugy7VaIaVMJjoqWG8AnhbFzh2/ioWq4jI7xmjzBnKSak+DpxPvEs26WEE12m3nJVQvFpvoTTusnJuS2zUYk6ZSupdv8rw3fsIKHYepNyiCHau0WGgs1kqApA6bY3V42FFakC57x5dL5RNi54MBOzS9JBoQ6BsUewtarIdxsKUawA9TKC2M1IRI2poS0Zex9BslV08KBfzSvSI1h06kRaR6S35CwqlWnVcC+ZK4l3vOtpPYOGAo8F8OLONcUYuGMMQH+Eycvnd7yyLSbDEaEkNEBYL1uBSw6ZbRQzlFIS8v2t6BDed37WWLDD+TGnODcVJ7lhG8= - - secure: UunPp8yEYLSgQez5CUk9qdi1QQGidDQlojrScsKtz/ixhm+dv1aqu+SeqVEVFjRvCeqghB+TGufw1mxkjNwsOL+hZDmsnfex+ZR6c1swk19BarlhKVc6+lAJ/2KsOaXjdAnS5w0Xyhqp+BMJxjYfhLaaSZj1+AUiXsG4dhRzl8jylx5caJu3jG3DN0wYVM54wHpx3Vz0Rx8oDLpr6Clh8dctvxJz88cT3OH2zDiMOfSMbrfOE4ENbRDCrX/ktQl2w6L8VBu29srIUqv862Pia9F6mjsZNuWJZu/yidnX/q+ctQawT0BQJJ1U9BhWKEKhOeS5AwSiBISxtvXU4gChSqOSrSe87Zt00ndlL+LkanSbehvGEaoRmi1AKxTh/jPvkiiiYj/yH3Rh+gLvkIxDQk0tvMvT42X1GblRS4aPAxGwYb/1Sx/3VThOpGSNRyH5xC8Ccr7AmOjcZUTUm0ZV45XX2QUiAlTJvrsbW1yvWyCdsYh36fxWgLdaokhbb4APkwDQTnQZ3zMyNSMqb4v/3gTWmZmMDtXrQ6/YHdufhuDJeCt3ibFdd5BX6GFS3zQ+GKPE4lHtexR8BnFA1hLfH0jIDnAduA5mgX4w6G/dSw7Bf7HGROwB2jBSRAVgruF3kTT3M9S+0rOgceuZTTeUvfl/KLAFeS5j2mO5qmdOPQE= - - secure: hfbgSnGViHzpZBIUehTm0na8CPBGXTASeOwgxzH2fiJuTQtp/hGO3bNo5zhPW+wMWj5or5EgmcTbRVQUu6zfOmaECi1Vf1Ul42qimlR8NLCBLSoPIcBgO2re/jQFZNUe6NTAoZsVAtMaBplmeOydrjFFb1NqufbSqVX2H7IrjwIFjc/E7vG+pgjBaPh6SMWrhZHUK+aID9Ssssr9KZc2lzq1rqSC1U2M/SQf9EbVEAxkyuR77aZhnkjZlUo97gmVBscStso4bUEgU54gYL0NiSiOrRhH+8N/mb/AJMyn/KGgyNJMai0wMn4WW381iVf4huG95C/RcQOYG/OEGBuR7N1yQEVhtV3SAJPBWXp3fQcL6CnWkn4N2Tc66sjbhAD06p5fSY2YWd5uGCzG9qvw3GABcHLx5q1rpBiwgHKHF+79subsYkhhUhXHSikh8ySeniXcS1LWVpUBe6Y2hDBGh2g3zru/Rkdvv7lHZgu6BNyb1tETCCU5TvpHJVd7YxoR7cGEWHQQcycmpVL6OYwhXG52nv/r2fPBICDfyzhPDyY6uei0p3/p0t3Qgby65phmaTPbqDM5FPy43iRp4zCJ5hKgmHlhXeGS7y2AavTSMk6Da4jz7bLZkIXM90MWcIh4saXU61cJKkPz2cuzovU07WaFwCo9rapbzfbuSSfrYvQ= + - secure: "Q1uubVVyKl9WActtY2nquhEdxsnaBdG79+QKTkLwNap3/Eioii8bLpGQTVsI4860lIbUmankD+5mfw3jl0lpeTtLPYXlewKN6eYXE/IpaWfJon4x3DxeSSSjvLYGh5CPbsnnFyygFb+TrIirTX1LJfT8nmlqUiSFsGmc7TcB+dU8+hBCbQl4wOJ9Rw0Ctzz8JSinl+nHiQyfqztc/RHmQOwATbbWK0QtAWst3hyupPPkFBWL1AXvoWJAWcLhxe5ZLtkZb3ZrPdxl6U6dZJQaAKDf+i4OlacWoS6Nzg4mDIKCiOBM6ad2/EjBmPDW9XXi7hbvhDp/T3Nn9xAolMewxni/vWM8is28a0cO7KfsHMab+UMV545lRxvyVEUn2ZFmZ+banKyrmXS0ezBYoDk2+BsLF00p63IZ++7v2PsCo9VMjIaUnYUntt5sxL9gs+TRQyx8HnN50aIP4WpGALJ9hfJxdBkpnfyTBcck2hOJfJduPPCbI03eccE+QUJ8antoyaAbn5LkciQef8y6PNbcVwTxdVF9JeUkhjyIqsez37gi0XeoDPvZN62G+q6XUv3TUGcC4y92v7cY51amNoYhgbxdx2o3Vezl9TbZurqoWQ1cbIdQiSjzIoBCvbjk9gPOotLWMVMxej+3DKjHB8CwkV/nRpzCCDegV0q1TFPthk0=" + - secure: "I4rNPKkzz3faTxlRxlCpQhMsogHRVnfxaSAvR9eNq7QGx+YKsqcTZ0LEmzjWiuiZ3iylFA12BkuULRNahaNQC5kNKdGK8Aqm8LQO1us4QdVOGPFpz+ieK21Zgz1mesWKp0ES4rwVkTIsGM+netS7q2DLQpka1gqRP7zmoa3WkeXlXLiHbXlA9rtZYbUhLqpMm2+GjeMGEiPI/EFuSfjDztbaEtbixJC+5OTL7YbJztD3TqvI4d3QtX3RbSdLv5Xn8pGFLHHix9lL4uVEvrK6AZQtl/0k6gqXjuyxSs2qMtChLk95Z0mw5KliYL3XUu2+SZOe7C+VSr3eXBzHqY0FmEZ6NINVWmeUuN715eCSiGUbsZe+NbdONouPsi4N6Vc+9cg+QE8ve5PXZbZattbI1SOB0xjZVj95n26LhuYMa3v5wjF9U6maOBtuvuy6WxNuP2h8qkWgw2ggdJZCAtPfnNzUsSa4ZpxoTncSiDK22EJOHwJxbuJpmqCNrN0DPOVnPN4QKHGaZ2G9lo6KOvsny7QKdYXJDivoaHEeRhKlCenElexpP8eF2bnn2zoOplL27xOsHPfUSWPPdDg+IfTfocSqkwXpXtUyFLUQY2jUkVwq650n/s8pVDpVB0VqkwDKeeLh+C/zSNTBBBEuWJe+bsmJ8VJ5Ag6QjICB54DTC4g=" - secure: "o8U8fTK6YwArlxxlpAPhPh2GV+Dl63R9K/Oq3jN4mjrrS+jvf905EqeQSEquC1uZ/ZwbD34kaFj/a50qX23axZFf09Sy9kPFNHgSNPXURZtshCNn2IimsU3eCKb6lM1MyKRa5Ue81sZVT+3Q673q9ndorHbjINb/iCg7wzx+DBNeuG5R8DXFM8ddxf19fKKkQSbzwa64lgZ8gH19TWShg2pYgLCxJxfYrt2acIJEshYyCbJxGrMVdkPztCaXqePV17saNUkbuYcVdAe3KkK/GsPe52FucbiVed705CDIJ3ODpWrx4Nsj9uFg9wuiCWWjBYIwpT+svV1lmvT9X5ViSMnazV+sNY1vpq5zDItU/lg9RsiVGVns4EEYAoJ4J4ky7KB6CC/9Nx7+oWoCNDfC80i61eEXNqg+TuKeBYKmOs/l5GnAyE7voxXUoyqBak7yu97Wp9iTRg6AoXSWiMeWnYBS5yRS/8gAaPUvfvp42ahZkiRli3R18E3s9LG1x/LowZhhGDDHum3QklJzPJlMm8BWSBJkhOgLApNWELZAtwS5yiEw4QIEQyZNEaoH9ENnpAfJIsPv1dX4nBHUlD8AhERGyUWHY95bL8GPzboBhM08pQdH+caYDRx3Fj3jICkuwYHz7RpDPAdpLMHCYoMQCjxhUy0br9GRRW0/he1Tdbw=" - secure: "bUq1LIA4FurrzaYPYg3RRKg5aaENIQTOFVCQEH+J81N4h+3O86l8pDM8RVv84M1TvsTpitUD1Agdg6qOK4IG61AVFGh6XHOMc3i/o2X0z03LCjW+J2k0ETPA1DwundgfdBitzEGedO6XQvlhVlVDg7QVEHeA3FxWPWy4+fvGEqDNEHCYPr4Q2Q/59hEXDtMIMvsHA8VOCMTuA+NRY8SkyyewXWSarNrlM+wyhIO8RcZxOEsHPKI+tIWyYInMd5mv2RZX6cs+Ia37c4ajpNXPViAe7oQHI99aFUWsUEfSydqMfVY/iDWig4bs5i/k7mln13RALyqsBFkNB+dSi36FJV2CgqnY9+YjNo4FRarXDlLwaGGPsVCgjN1xxeD+MOSqJaCM2aNiNPgB5KsGDLDTLQbcGJr4frjtGG0x1mTBD+n3GyxYcum6dWlUNGJ7IN1rShQFC+e//oHAEDNmNGkKzVVbBLJZTyirm5GJYpUq4vWDmFJsEb2CK1C2W4qVX/NSmixD2/S0x2+osWgPitkIlyKQwOjSFag6hEpqQNwuNv7HCO2JtCjfg25Ur4itZkon5oICRgznhfWuDGf9UbBc+SI3vPGlhkjH3oUqa4RCn/W5BVeug/xrfRB6AJ9k1mg8g1xCvECG2ZA9epA40PDdDqcsS6WyYcEPPvnk2wpqZY0=" - secure: "lUTaoCHgQk0xYpEtRFPJXn1Eduf5WVCyAa6/cWECGcYfrhW3kYXDHKtHwhUwi/HPGyLg0ZFi1DBaiv7QareW/D1GwlPV+UTgmc1TY02XwLz7kFPb4A9896nCVOwR5xMuTL7TFzuB8/5bFGf6GGvrGnlGKWZCIOw3d8OLaiUib+BzezMsMJjouJwUiPpg9LzdhRORK4aj+uwCD+27o3i1u2yXiv4ljY/j4rMFdNAYWup5m2QPESGXJR4aTuf2uFYUEAURkUcOhtH9Uq6XQqUbW1IJqD9UVbtLGo6qCN813UXlt17DoqkPWjvsRiC7JBLFqZpT9+wrGcfSuF4HZJJOZrWxfnD/uzL4M485eUwePKCaA1M5EfYu+wpmcz5z00O59PJISAEMrmIvJTj0T87tOdKzI/TzO1ifAUMjs2z0fJOTD4O83PvQ56oppc9fsNo2jkO74DDauoSFXNo9IRHqj/ZBoklGxSA8MWjqu5mFxwEqFVca5IfUXgqI0fiBDqU81lHqsxEKiMO0C4LYD6w3yVtm3clCyMAvYIpU1owPUnA5F3V7JkhlUh8RPOViZ3xIgCZTU4lfA+jTjvC0L4nP2/xKIQMlJlUokDjqn7S2rD6Ujb0kxcxhj9d5s1dlLrJJfaqJKeE+S0yfiG8CHEEwmOlq5yEzHdt5XuKcgR5lMgY=" diff --git a/LICENSE.txt b/LICENSE.txt index 1367045d..83035f03 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ GCViewer helps you to analyse java garbage collection log files. Copyright (c) 2002-2008 tagtraum industries incorporated. -Copyright (c) 2011-2021 Joerg Wuethrich and contributors +Copyright (c) 2011-2023 Joerg Wuethrich and contributors LGPL ==== diff --git a/README.md b/README.md index ff6ace87..fb29385a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ GCViewer 1.36 [![Build Status](https://app.travis-ci.com/chewiebug/GCViewer.svg?branch=develop)](https://app.travis-ci.com/chewiebug/GCViewer) [![codecov.io](https://codecov.io/github/chewiebug/GCViewer/coverage.svg?branch=develop)](https://codecov.io/github/chewiebug/GCViewer?branch=develop) +[![Download gcviewer](https://img.shields.io/sourceforge/dm/gcviewer.svg)](https://sourceforge.net/projects/gcviewer/files) GCViewer is a little tool that visualizes verbose GC output generated by Sun / Oracle, IBM, HP and BEA Java Virtual Machines. It diff --git a/cicd/Dockerfile b/cicd/Dockerfile deleted file mode 100644 index 84e5d933..00000000 --- a/cicd/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ruby:latest - -RUN gem install travis - -CMD /bin/bash \ No newline at end of file diff --git a/cicd/docker-build.bat b/cicd/docker-build.bat new file mode 100644 index 00000000..91ef354b --- /dev/null +++ b/cicd/docker-build.bat @@ -0,0 +1 @@ +docker build --tag ruby/travis travis-docker-image \ No newline at end of file diff --git a/pom.xml b/pom.xml index 60c13dae..48e0064b 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,10 @@ Ryan Gardner + + Matt Foulks + https://github.com/mfoulks3200 + Martin Geldmacher https://github.com/geld0r @@ -107,6 +111,10 @@ Tony Mancill https://github.com/tmancill + + mayswind + https://github.com/mayswind + Auston McReynolds https://github.com/amcrn @@ -180,9 +188,17 @@ Pierre Viret https://github.com/pierre-viret + + Cui Weiloong + https://github.com/CuiWeiloong + Yin Xunjun + + Leslie Zhai + https://github.com/xiangzhai + Eugene Zimichev https://github.com/undefz @@ -209,7 +225,7 @@ 3.0.1 1.6 3.1.0 - 1.8 + 3.1.0 3.8.0 1.4 3.1.0 diff --git a/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCDocumentController.java b/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCDocumentController.java index 1d7f9bcc..baba18c2 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCDocumentController.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCDocumentController.java @@ -1,17 +1,18 @@ package com.tagtraum.perf.gcviewer.ctrl.impl; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.logging.Logger; +import javax.swing.SwingWorker; + import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader; import com.tagtraum.perf.gcviewer.log.TextAreaLogHandler; import com.tagtraum.perf.gcviewer.view.ChartPanelView; import com.tagtraum.perf.gcviewer.view.GCDocument; import com.tagtraum.perf.gcviewer.view.GCModelLoaderView; +import com.tagtraum.perf.gcviewer.view.GCViewerGuiToolBar; import com.tagtraum.perf.gcviewer.view.ModelChartImpl; -import javax.swing.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.logging.Logger; - /** * Controller for {@link GCDocument}. * @@ -29,9 +30,11 @@ public GCDocumentController(GCDocument gcDocument) { gcDocument.addPropertyChangeListener(this); } - public void addGCResource(GCModelLoader loader, ViewMenuController viewMenuController) { + public void addGCResource(GCModelLoader loader, ViewMenuController viewMenuController, GCViewerGuiToolBar gcViewerGuiToolBar) { ChartPanelView chartPanelView = new ChartPanelView(gcDocument.getPreferences(), loader.getGcResource()); + ((ModelChartImpl)chartPanelView.getModelChart()).addPropertyChangeListener(gcDocument); ((ModelChartImpl)chartPanelView.getModelChart()).addPropertyChangeListener(viewMenuController); + ((ModelChartImpl)chartPanelView.getModelChart()).addPropertyChangeListener(gcViewerGuiToolBar); ((ModelChartImpl)chartPanelView.getModelChart()).addTimeOffsetChangeListener(new TimeOffsetPanelController(gcDocument)); gcDocument.addChartPanelView(chartPanelView); loader.addPropertyChangeListener(this); diff --git a/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCModelLoaderControllerImpl.java b/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCModelLoaderControllerImpl.java index 8d98ba27..dcc279bd 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCModelLoaderControllerImpl.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCModelLoaderControllerImpl.java @@ -1,25 +1,29 @@ package com.tagtraum.perf.gcviewer.ctrl.impl; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.swing.JCheckBoxMenuItem; + import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader; import com.tagtraum.perf.gcviewer.ctrl.GCModelLoaderController; import com.tagtraum.perf.gcviewer.ctrl.GCModelLoaderGroupTracker; import com.tagtraum.perf.gcviewer.ctrl.impl.FileDropTargetListener.DropFlavor; -import com.tagtraum.perf.gcviewer.model.GcResourceFile; import com.tagtraum.perf.gcviewer.model.GCResource; +import com.tagtraum.perf.gcviewer.model.GcResourceFile; import com.tagtraum.perf.gcviewer.model.GcResourceSeries; import com.tagtraum.perf.gcviewer.view.GCDocument; import com.tagtraum.perf.gcviewer.view.GCViewerGui; import com.tagtraum.perf.gcviewer.view.GCViewerGuiMenuBar; import com.tagtraum.perf.gcviewer.view.model.RecentGCResourcesModel; -import javax.swing.*; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTarget; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.util.*; - /** * Controller class for {@link GCModelLoader}. * @@ -70,7 +74,7 @@ public void add(List gcResourceList) { private void addGCResource(GCResource gcResource) { GCModelLoader loader = GCModelLoaderFactory.createFor(gcResource); GCDocumentController docController = getDocumentController(gcViewerGui.getSelectedGCDocument()); - docController.addGCResource(loader, getViewMenuController()); + docController.addGCResource(loader, getViewMenuController(), gcViewerGui.getToolBar()); loader.execute(); } @@ -125,7 +129,7 @@ private void openGCResource(GCResource gcResource, GCModelLoader loader) { gcViewerGui.addDocument(document); GCDocumentController docController = new GCDocumentController(document); - docController.addGCResource(loader, getViewMenuController()); + docController.addGCResource(loader, getViewMenuController(), gcViewerGui.getToolBar()); loader.execute(); } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/exp/impl/SummaryDataWriter.java b/src/main/java/com/tagtraum/perf/gcviewer/exp/impl/SummaryDataWriter.java index 06dcdd6d..aefb295c 100755 --- a/src/main/java/com/tagtraum/perf/gcviewer/exp/impl/SummaryDataWriter.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/exp/impl/SummaryDataWriter.java @@ -6,9 +6,13 @@ import java.io.PrintWriter; import java.text.NumberFormat; import java.util.Date; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import com.tagtraum.perf.gcviewer.exp.AbstractDataWriter; +import com.tagtraum.perf.gcviewer.math.DoubleData; +import com.tagtraum.perf.gcviewer.math.DoubleDataPercentile; import com.tagtraum.perf.gcviewer.model.GCModel; import com.tagtraum.perf.gcviewer.util.FormattedValue; import com.tagtraum.perf.gcviewer.util.MemoryFormat; @@ -69,7 +73,7 @@ public SummaryDataWriter(OutputStream out, Map configuration) { private void initialiseFormatters() { pauseFormatter = NumberFormat.getInstance(); - pauseFormatter.setMaximumFractionDigits(5); + pauseFormatter.setMaximumFractionDigits(6); totalTimeFormatter = new TimeFormat(); @@ -227,6 +231,74 @@ private void exportPauseSummary(PrintWriter out, GCModel model) { exportValue(out, "fullGCPausePc", percentFormatter.format(model.getFullGCPause().getSum()*100.0/model.getPause().getSum()), "%"); exportValue(out, "gcPause", gcTimeFormatter.format(model.getGCPause().getSum()), "s"); exportValue(out, "gcPausePc", percentFormatter.format(model.getGCPause().getSum()*100.0/model.getPause().getSum()), "%"); + + // Add extra statistical data: sum, count, min, max, average, standardDeviation, median, 75th percentile, 95, 99, 99.5, 99.9 + // All Pause stats + if (pauseDataAvailable) { + exportValue(out, "pauseSum", pauseFormatter.format(model.getPause().getSum()), "s"); + // exportValue(out, "pauseCount", "" + model.getPause().getN(), "-"); + exportValue(out, "pauseMin", pauseFormatter.format(model.getPause().getMin()), "s"); + exportValue(out, "pauseMax", pauseFormatter.format(model.getPause().getMax()), "s"); + exportValue(out, "pauseAverage", pauseFormatter.format(model.getPause().average()), "s"); + exportValue(out, "pauseStandardDeviation", pauseFormatter.format(model.getPause().standardDeviation()), "s"); + exportValue(out, "pauseMedian", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(50)), "s"); + exportValue(out, "pausePercentile75th", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(50)), "s"); + exportValue(out, "pausePercentile95th", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(75)), "s"); + exportValue(out, "pausePercentile99th", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(95)), "s"); + exportValue(out, "pausePercentile99.5th", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(99)), "s"); + exportValue(out, "pausePercentile99.9th", pauseFormatter.format(((DoubleDataPercentile)model.getPause()).getPercentile(99.9)), "s"); + } + // GC Pause stats + if (gcDataAvailable) { + exportValue(out, "gcPauseSum", pauseFormatter.format(model.getGCPause().getSum()), "s"); + // exportValue(out, "gcPauseCount", "" + model.getGCPause().getN(), "-"); + exportValue(out, "gcPauseMin", pauseFormatter.format(model.getGCPause().getMin()), "s"); + exportValue(out, "gcPauseMax", pauseFormatter.format(model.getGCPause().getMax()), "s"); + exportValue(out, "gcPauseAverage", pauseFormatter.format(model.getGCPause().average()), "s"); + exportValue(out, "gcPauseStandardDeviation", pauseFormatter.format(model.getGCPause().standardDeviation()), "s"); + exportValue(out, "gcPauseMedian", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(50)), "s"); + exportValue(out, "gcPausePercentile75th", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(50)), "s"); + exportValue(out, "gcPausePercentile95th", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(75)), "s"); + exportValue(out, "gcPausePercentile99th", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(95)), "s"); + exportValue(out, "gcPausePercentile99.5th", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(99)), "s"); + exportValue(out, "gcPausePercentile99.9th", pauseFormatter.format(((DoubleDataPercentile)model.getGCPause()).getPercentile(99.9)), "s"); + } + // Full GC Pause stats + if (fullGCDataAvailable) { + exportValue(out, "fullGCPauseSum", pauseFormatter.format(model.getFullGCPause().getSum()), "s"); + // exportValue(out, "fullGCPauseCount", "" + model.getFullGCPause().getN(), "-"); + exportValue(out, "fullGCPauseMin", pauseFormatter.format(model.getFullGCPause().getMin()), "s"); + exportValue(out, "fullGCPauseMax", pauseFormatter.format(model.getFullGCPause().getMax()), "s"); + exportValue(out, "fullGCPauseAverage", pauseFormatter.format(model.getFullGCPause().average()), "s"); + exportValue(out, "fullGCPauseStandardDeviation", pauseFormatter.format(model.getFullGCPause().standardDeviation()), "s"); + exportValue(out, "fullGCPauseMedian", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(50)), "s"); + exportValue(out, "fullGCPausePercentile75th", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(50)), "s"); + exportValue(out, "fullGCPausePercentile95th", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(75)), "s"); + exportValue(out, "fullGCPausePercentile99th", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(95)), "s"); + exportValue(out, "fullGCPausePercentile99.5th", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(99)), "s"); + exportValue(out, "fullGCPausePercentile99.9th", pauseFormatter.format(((DoubleDataPercentile)model.getFullGCPause()).getPercentile(99.9)), "s"); + } + // ZGC stats: [gc,phases] + if (model.size() > 1 && model.getGcEventPhases().size() > 0) { + DoubleData gcPhases = new DoubleDataPercentile(); + for (Entry entry : model.getGcEventPhases().entrySet()) { + List phaseList = ((DoubleDataPercentile)entry.getValue()).getDoubleData(); + for (Double d : phaseList) + gcPhases.add(d); + } + exportValue(out, "gcPhaseSum", pauseFormatter.format(gcPhases.getSum()), "s"); + exportValue(out, "gcPhaseCount", "" + gcPhases.getN(), "-"); + exportValue(out, "gcPhaseMin", pauseFormatter.format(gcPhases.getMin()), "s"); + exportValue(out, "gcPhaseMax", pauseFormatter.format(gcPhases.getMax()), "s"); + exportValue(out, "gcPhaseAverage", pauseFormatter.format(gcPhases.average()), "s"); + exportValue(out, "gcPhaseStandardDeviation", pauseFormatter.format(gcPhases.standardDeviation()), "s"); + exportValue(out, "gcPhaseMedian", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(50)), "s"); + exportValue(out, "gcPhasePercentile75th", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(50)), "s"); + exportValue(out, "gcPhasePercentile95th", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(75)), "s"); + exportValue(out, "gcPhasePercentile99th", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(95)), "s"); + exportValue(out, "gcPhasePercentile99.5th", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(99)), "s"); + exportValue(out, "gcPhasePercentile99.9th", pauseFormatter.format(((DoubleDataPercentile)gcPhases).getPercentile(99.9)), "s"); + } } private boolean isSignificant(final double average, final double standardDeviation) { diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java index 44c6e450..30c6d4d2 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java @@ -62,7 +62,7 @@ protected DataReaderTools getDataReaderTools() { */ protected boolean shouldContinue() { if (getLogger().isLoggable(Level.FINE)) { - getLogger().fine(gcResource.getResourceName() + " read cancelled"); + getLogger().fine(gcResource.getResourceName() + " read cancelled=" + gcResource.isReadCancelled()); } return !gcResource.isReadCancelled(); } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java index 8d0004af..ffedc2c7 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java @@ -256,7 +256,7 @@ protected String parseTypeString(String line, ParseInformation pos) throws Parse int i = pos.getIndex(); try { // consume all leading spaces and [ - final int lineLength = line.length(); + final int lineLength = line.length() - 1; final char[] lineChars = line.toCharArray(); char c = lineChars[i]; for (; i= lineLength) + throw new ParseException("Unexpected end of line.", line); + // check whether the Id starts with a number + // -> skip number + for (; Character.isDigit(c) && i < lineLength; c = lineChars[++i]); + // -> skip ':' + for (; i 0) { private int skipUntilNextDigit(String line, ParseInformation pos) throws ParseException { int begin = pos.getIndex(); - while (!Character.isDigit(line.charAt(begin)) && begin < line.length()) { + while (!Character.isDigit(line.charAt(begin)) && begin+1 < line.length()) { ++begin; } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM_J9_R28.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM_J9_R28.java index 489dd487..1b5b53c1 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM_J9_R28.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM_J9_R28.java @@ -20,6 +20,7 @@ import javax.xml.stream.events.XMLEvent; import com.tagtraum.perf.gcviewer.model.AbstractGCEvent; +import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.ExtendedType; import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.Type; import com.tagtraum.perf.gcviewer.model.GCEvent; import com.tagtraum.perf.gcviewer.model.GCModel; @@ -92,7 +93,7 @@ public GCModel read() throws IOException { break; case EXCLUSIVE_END: handleExclusiveEnd(startElement, currentGcEvent); - if (currentGcEvent.getExtendedType() == null) { + if (currentGcEvent.getExtendedType() == null || currentGcEvent.getExtendedType() == ExtendedType.UNDEFINED) { if (getLogger().isLoggable(Level.FINE)) getLogger().fine("event at " + in.getLineNumber() + " doesn't contain any information, the parser can handle"); } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0.java index 8a41a8d0..3b3385af 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0.java @@ -58,6 +58,7 @@ *
  • -XX:+PrintReferenceGC (output ignored)
  • *
  • -XX:+PrintCMSInitiationStatistics (output ignored)
  • *
  • -XX:+PrintFLSStatistics (output ignored)
  • + *
  • -XX:+PrintGCID (output ignored)
  • * * * @author Hendrik Schreiber @@ -117,6 +118,7 @@ public class DataReaderSun1_6_0 extends AbstractDataReaderSun { EXCLUDE_STRINGS_LINE_START.add("/proc/meminfo"); // apple vms seem to print this out in the beginning of the logs EXCLUDE_STRINGS_LINE_START.add("Uncommitted"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Cancelling concurrent GC"); // -XX:+UseShenandoahGC + EXCLUDE_STRINGS_LINE_START.add("Cancelling GC"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Capacity"); // -XX:+UseShenandoahGC -XX:+PrintGCDetails EXCLUDE_STRINGS_LINE_START.add("Periodic GC triggered"); // -XX:+UseShenandoahGC -XX:+PrintGCDetails EXCLUDE_STRINGS_LINE_START.add("Immediate Garbage"); // -XX:+UseShenandoahGC -XX:+PrintGCDetails @@ -125,7 +127,6 @@ public class DataReaderSun1_6_0 extends AbstractDataReaderSun { EXCLUDE_STRINGS_LINE_START.add("Concurrent marking triggered"); // -XX:+UseShenandoahGC -XX:+PrintGCDetails EXCLUDE_STRINGS_LINE_START.add("Adjusting free threshold"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Predicted cset threshold"); // -XX:+UseShenandoahGC - EXCLUDE_STRINGS_LINE_START.add("Trigger"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Free"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Evacuation Reserve"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add("Pacer for "); // -XX:+UseShenandoahGC @@ -134,6 +135,9 @@ public class DataReaderSun1_6_0 extends AbstractDataReaderSun { EXCLUDE_STRINGS_LINE_START.add(" Adaptive CSet Selection"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add(" Collectable Garbage"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_START.add(" Immediate Garbage"); // -XX:+UseShenandoahGC + EXCLUDE_STRINGS_LINE_START.add(" Good progress for"); // -XX:+UseShenandoahGC + EXCLUDE_STRINGS_LINE_START.add(" Failed to"); // -XX:+UseShenandoahGC + EXCLUDE_STRINGS_LINE_START.add(" Cancelling GC"); // -XX:+UseShenandoahGC EXCLUDE_STRINGS_LINE_CONTAIN.add(LOGFILE_ROLLING_BEGIN); EXCLUDE_STRINGS_LINE_CONTAIN.add(LOGFILE_ROLLING_END); @@ -154,6 +158,8 @@ public class DataReaderSun1_6_0 extends AbstractDataReaderSun { LOG_INFORMATION_STRINGS.add("Reference processing"); // -XX:+UseShenandoahGC LOG_INFORMATION_STRINGS.add("Heuristics ergonomically sets"); // -XX:+UseShenandoahGC LOG_INFORMATION_STRINGS.add("Initialize Shenandoah heap"); // -XX:+UseShenandoahGC + LOG_INFORMATION_STRINGS.add("Shenandoah GC mode"); // -XX:+UseShenandoahGC + LOG_INFORMATION_STRINGS.add("Soft Max Heap Size"); // -XX:+UseShenandoahGC } private static final String EVENT_YG_OCCUPANCY = "YG occupancy"; @@ -252,6 +258,8 @@ public class DataReaderSun1_6_0 extends AbstractDataReaderSun { private static final String SHENANDOAH_DETAILS_FINAL_MARK_SPLIT_START = "Total"; private static final String SHENANDOAH_INTRODUCTION_TO_GC_STATISTICS = "Shenandoah Heap"; + private static final String SHENANDOAH_GC_CYCLE_DETAILS_START = "All times are wall-clock times"; + private static final String SHENANDOAH_GC_CYCLE_START = "Trigger: "; // -XX:+PrintReferenceGC private static final String PRINT_REFERENCE_GC_INDICATOR = "Reference"; @@ -308,9 +316,17 @@ else if (startsWith(line, LOG_INFORMATION_STRINGS, false)) { continue; } else if (line.startsWith(SHENANDOAH_INTRODUCTION_TO_GC_STATISTICS)) { // Assumption: As soon as the shenandoah gc statistics block starts, the vm is shutting down - skipAndLogToEndOfFile(in); + skipAndLogToEndOfFile(in, line); + continue; + } else if (line.startsWith(SHENANDOAH_GC_CYCLE_START)) { + // skip the start string of the first gc cycle + continue; + } else if (line.startsWith(SHENANDOAH_GC_CYCLE_DETAILS_START)) { + // ignore details of each gc cycle + skipGcCycleDetails(in); continue; } + if (line.indexOf(CMS_ABORT_PRECLEAN) >= 0) { // line contains like " CMS: abort preclean due to time " // -> remove the text @@ -484,13 +500,27 @@ else if (beginningOfLine.size() > 0) { } } - private void skipAndLogToEndOfFile(LineNumberReader in) throws IOException { - String line; + private void skipAndLogToEndOfFile(LineNumberReader in, String line) throws IOException { + getLogger().info(line); while ((line = in.readLine()) != null) { getLogger().info(line); } } + private void skipGcCycleDetails(LineNumberReader in) throws IOException { + String line; + while ((line = in.readLine()) != null) { + // parse the events for the next GC cycle + if (line.startsWith(SHENANDOAH_GC_CYCLE_START)) { + break; + } + // the vm is shutting down + if (line.startsWith(SHENANDOAH_INTRODUCTION_TO_GC_STATISTICS)) { + skipAndLogToEndOfFile(in, line); + } + } + } + private boolean isPrintHeapAtGcStarting(String line) { return line.startsWith(HEAP) // jdk 6 and before || line.indexOf(HEAP_SIZING_BEFORE) >= 0 // jdk 7 and after @@ -620,6 +650,7 @@ protected AbstractGCEvent parseLine(String line, ParseInformation pos) throws // pre-used->post-used, total, time ZonedDateTime datestamp = parseDatestamp(line, pos); double timestamp = getTimestamp(line, pos, datestamp); + parseGcId(line, pos); ExtendedType type = parseType(line, pos); AbstractGCEvent ae; if (type.getConcurrency() == Concurrency.CONCURRENT) { diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0G1.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0G1.java index 267385ab..898cea02 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0G1.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderSun1_6_0G1.java @@ -48,6 +48,7 @@ *
  • -XX:+PrintAdaptiveSizePolicy (output ignored)
  • *
  • -XX:+PrintReferenceGC (output ignored)
  • *
  • -XX:+PrintStringDeduplicationStatistics (output ignored)
  • + *
  • -XX:+PrintGCID (output ignored)
  • * * * @author Joerg Wuethrich @@ -131,7 +132,7 @@ public class DataReaderSun1_6_0G1 extends AbstractDataReaderSun { // the following pattern is specific for G1 with -XX:+PrintGCDetails // "[: ]0.295: [GC pause (young), 0.00594747 secs]" - private static final Pattern PATTERN_GC_PAUSE = Pattern.compile("^([0-9-T:.+]{29})?[ ]?([0-9.,]+)?[: \\[]{2,3}([A-Z0-9a-z- ().]+)[, ]+([0-9.,]+)[ sec\\]]+$"); + private static final Pattern PATTERN_GC_PAUSE = Pattern.compile("^([0-9-T:.+]{29})?[ ]?([0-9.,]+)?(?:[ #0-9:]+)?[: \\[]{2,3}([A-Z0-9a-z- ().]+)[, ]+([0-9.,]+)[ sec\\]]+$"); private static final int GC_PAUSE_GROUP_DATESTAMP = 1; private static final int GC_PAUSE_GROUP_TIMESTAMP = 2; private static final int GC_PAUSE_GROUP_TYPE = 3; @@ -551,6 +552,7 @@ protected AbstractGCEvent parseLine(String line, ParseInformation pos) throws // pre-used->post-used, total, time ZonedDateTime datestamp = parseDatestamp(line, pos); double timestamp = getTimestamp(line, pos, datestamp); + parseGcId(line, pos); ExtendedType type = parseType(line, pos); // special provision for concurrent events if (type.getConcurrency() == Concurrency.CONCURRENT) { @@ -579,8 +581,7 @@ else if (type.getCollectionType().equals(CollectionType.VM_OPERATION)) { if (event.getExtendedType().getPattern() == GcPattern.GC_MEMORY_PAUSE) { setMemoryAndPauses(event, line, pos); - } - else { + } else { event.setPause(parsePause(line, pos)); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderTools.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderTools.java index 883b9d61..e7d2085f 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderTools.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderTools.java @@ -69,7 +69,7 @@ public ExtendedType parseType(String typeString) throws UnknownGcTypeException { } /** - * Same as @{link {@link #parseType(String)}}, but returns null instead of exception, if no type could + * Same as {@link #parseType(String)}, but returns null instead of exception, if no type could * be found. * * @param typeName string representation of the gc event 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 1e48f014..6a98cdc4 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,27 +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: ^(?:\[(?