Skip to content

Commit 262dfed

Browse files
committed
Support for logfile rotation (chewiebug#61)
Support for rotated logfiles has been added. This allows to open a series of consecutive logfiles and treat them as one (merged) gc log. This allows to analyze logfiles that have been created over a longer period in a production environment.
1 parent 12070b2 commit 262dfed

34 files changed

+2413
-255
lines changed

src/main/java/com/tagtraum/perf/gcviewer/ctrl/GCModelLoaderController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ public interface GCModelLoaderController {
3030

3131
void open(List<GCResource> gcResourceList);
3232

33+
/**
34+
* Opens the given {@link GCResource}s as a series of rotated logfiles.
35+
*
36+
* @param gcResourceList a list of rotated gc logfiles. Ordering is not required.
37+
*/
38+
void openAsSeries(List<GCResource> gcResourceList);
39+
3340
/**
3441
* Reload all models of <code>gcDocument</code> and provide tracker. The tracker will
3542
* fire a propertyChangeEvent, as soon as all GCModelLoaders have finished loading.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.tagtraum.perf.gcviewer.ctrl.action;
2+
3+
import com.tagtraum.perf.gcviewer.ctrl.GCModelLoaderController;
4+
import com.tagtraum.perf.gcviewer.model.GCResource;
5+
import com.tagtraum.perf.gcviewer.model.GcResourceFile;
6+
import com.tagtraum.perf.gcviewer.util.LocalisationHelper;
7+
import com.tagtraum.perf.gcviewer.view.ActionCommands;
8+
import com.tagtraum.perf.gcviewer.view.GCViewerGui;
9+
import com.tagtraum.perf.gcviewer.view.OpenFileView;
10+
import com.tagtraum.perf.gcviewer.view.util.ImageHelper;
11+
12+
import javax.swing.*;
13+
import java.awt.*;
14+
import java.awt.event.ActionEvent;
15+
import java.io.File;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
import java.util.logging.Logger;
19+
20+
/**
21+
* Allows to open a series of log files, treating them as a consecutive log.
22+
*
23+
* @author martin.geldmacher
24+
*/
25+
public class OpenSeries extends AbstractAction {
26+
private static final Logger logger = Logger.getLogger(OpenSeries.class.getName());
27+
28+
private GCModelLoaderController controller;
29+
private GCViewerGui gcViewer;
30+
private OpenFileView openFileView;
31+
32+
public OpenSeries(GCModelLoaderController controller, final GCViewerGui gcViewer) {
33+
this.controller = controller;
34+
this.gcViewer = gcViewer;
35+
36+
putValue(NAME, LocalisationHelper.getString("main_frame_menuitem_open_series"));
37+
putValue(SHORT_DESCRIPTION, LocalisationHelper.getString("main_frame_menuitem_hint_open_series"));
38+
putValue(MNEMONIC_KEY, Integer.valueOf(LocalisationHelper.getString("main_frame_menuitem_mnemonic_open_series").charAt(0)));
39+
putValue(ACTION_COMMAND_KEY, ActionCommands.OPEN_SERIES.toString());
40+
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke('S', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
41+
putValue(SMALL_ICON, ImageHelper.loadImageIcon("open.png"));
42+
43+
openFileView = new OpenFileView();
44+
}
45+
46+
@Override
47+
public void actionPerformed(ActionEvent e) {
48+
final int val = openFileView.showOpenDialog(gcViewer);
49+
if (val == JFileChooser.APPROVE_OPTION) {
50+
File[] selectedFiles = openFileView.getSelectedFiles();
51+
List<GCResource> resources = getResources(selectedFiles);
52+
controller.openAsSeries(resources);
53+
}
54+
}
55+
56+
private List<GCResource> getResources(File[] selectedFiles) {
57+
if (selectedFiles == null || selectedFiles.length == 0)
58+
throw new IllegalArgumentException("At least one file must be selected!");
59+
60+
java.util.List<GCResource> resources = new ArrayList<>();
61+
for (File file : selectedFiles) {
62+
resources.add(new GcResourceFile(file));
63+
}
64+
return resources;
65+
}
66+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.tagtraum.perf.gcviewer.ctrl.impl;
2+
3+
import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
4+
import com.tagtraum.perf.gcviewer.imp.DataReaderException;
5+
import com.tagtraum.perf.gcviewer.imp.MonitoredBufferedInputStream;
6+
import com.tagtraum.perf.gcviewer.model.GCModel;
7+
8+
import javax.swing.*;
9+
import java.beans.PropertyChangeEvent;
10+
import java.util.concurrent.ExecutionException;
11+
import java.util.logging.Level;
12+
import java.util.logging.Logger;
13+
14+
/**
15+
* Base class for {@link GCModelLoader}s
16+
*
17+
* @author martin.geldmacher (refactored)
18+
*/
19+
public abstract class AbstractGCModelLoaderImpl extends SwingWorker<GCModel, Object> implements GCModelLoader {
20+
@Override
21+
public void propertyChange(PropertyChangeEvent evt) {
22+
if (evt.getPropertyName() == MonitoredBufferedInputStream.PROGRESS) {
23+
setProgress((int) evt.getNewValue());
24+
}
25+
}
26+
27+
protected void done() {
28+
Logger logger = getGcResource().getLogger();
29+
30+
try {
31+
getGcResource().setModel(get());
32+
// TODO delete
33+
getGcResource().getModel().printDetailedInformation();
34+
}
35+
catch (InterruptedException e) {
36+
logger.log(Level.FINE, "model get() interrupted", e);
37+
}
38+
catch (ExecutionException | RuntimeException e) {
39+
if (logger.isLoggable(Level.WARNING))
40+
logger.log(Level.WARNING, "Failed to create GCModel from " + getGcResource().getResourceName(), e);
41+
}
42+
}
43+
44+
@Override
45+
protected GCModel doInBackground() throws Exception {
46+
setProgress(0);
47+
final GCModel result;
48+
try {
49+
result = loadGcModel();
50+
}
51+
catch (DataReaderException | RuntimeException e) {
52+
Logger logger = getGcResource().getLogger();
53+
if (logger.isLoggable(Level.FINE)) {
54+
logger.log(Level.FINE, "Failed to load GCModel from " + getGcResource().getResourceName(), e);
55+
}
56+
throw e;
57+
}
58+
return result;
59+
}
60+
61+
protected abstract GCModel loadGcModel() throws DataReaderException;
62+
}

src/main/java/com/tagtraum/perf/gcviewer/ctrl/impl/GCModelLoaderControllerImpl.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.tagtraum.perf.gcviewer.ctrl.impl.FileDropTargetListener.DropFlavor;
77
import com.tagtraum.perf.gcviewer.model.GcResourceFile;
88
import com.tagtraum.perf.gcviewer.model.GCResource;
9+
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;
910
import com.tagtraum.perf.gcviewer.view.GCDocument;
1011
import com.tagtraum.perf.gcviewer.view.GCViewerGui;
1112
import com.tagtraum.perf.gcviewer.view.GCViewerGuiMenuBar;
@@ -17,10 +18,7 @@
1718
import java.awt.event.ActionListener;
1819
import java.beans.PropertyChangeListener;
1920
import java.io.File;
20-
import java.util.ArrayList;
21-
import java.util.Arrays;
22-
import java.util.List;
23-
import java.util.Map;
21+
import java.util.*;
2422

2523
/**
2624
* Controller class for {@link GCModelLoader}.
@@ -113,25 +111,25 @@ private ViewMenuController getViewMenuController() {
113111

114112
throw new IllegalStateException("no ActionListener of type 'ViewMenuController' found");
115113
}
116-
114+
117115
private void openGCResource(GCResource gcResource) {
118116
GCModelLoader loader = new GCModelLoaderImpl(gcResource);
117+
openGCResource(gcResource, loader);
118+
}
119+
120+
private void openGCResource(GCResource gcResource, GCModelLoader loader) {
119121
GCDocument document = new GCDocument(gcViewerGui.getPreferences(), gcResource.getResourceName());
120-
document.setDropTarget(
121-
new DropTarget(document,
122-
DnDConstants.ACTION_COPY,
123-
new FileDropTargetListener(this, DropFlavor.ADD))
124-
);
122+
document.setDropTarget(new DropTarget(document, DnDConstants.ACTION_COPY, new FileDropTargetListener(this, DropFlavor.ADD)));
125123
document.addInternalFrameListener(new GCViewerGuiInternalFrameController());
126-
124+
127125
gcViewerGui.addDocument(document);
128-
126+
129127
GCDocumentController docController = new GCDocumentController(document);
130128
docController.addGCResource(loader, getViewMenuController());
131-
129+
132130
loader.execute();
133131
}
134-
132+
135133
@Override
136134
public void open(File[] files) {
137135
List<GCResource> gcResourceList = new ArrayList<GCResource>();
@@ -164,24 +162,32 @@ public void open(List<GCResource> gcResourceList) {
164162

165163
getRecentGCResourcesModel().add(gcResourceList);
166164
}
167-
165+
166+
@Override
167+
public void openAsSeries(List<GCResource> gcResourceList) {
168+
GcResourceSeries resourceSeries = new GcResourceSeries(gcResourceList);
169+
GCModelLoader loader = GCModelLoaderFactory.createFor(resourceSeries);
170+
openGCResource(loader.getGcResource(), loader);
171+
getRecentGCResourcesModel().add(Collections.singletonList(resourceSeries));
172+
}
173+
168174
@Override
169175
public GCModelLoaderGroupTracker reload(GCDocument gcDocument) {
170176
GCModelLoaderGroupTracker tracker = new GCModelLoaderGroupTrackerImpl();
171177
for (GCResource gcResource : gcDocument.getGCResources()) {
172178
if (gcResource.hasUnderlyingResourceChanged()) {
173179
gcResource.reset();
174180
gcResource.setIsReload(true);
175-
GCModelLoader loader = new GCModelLoaderImpl(gcResource);
181+
GCModelLoader loader = GCModelLoaderFactory.createFor(gcResource);
176182
GCDocumentController docController = getDocumentController(gcDocument);
177183
docController.reloadGCResource(loader);
178184

179185
tracker.addGcModelLoader(loader);
180186
}
181187
}
182-
188+
183189
tracker.execute();
184-
190+
185191
return tracker;
186192
}
187193

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.tagtraum.perf.gcviewer.ctrl.impl;
2+
3+
import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
4+
import com.tagtraum.perf.gcviewer.model.GCResource;
5+
import com.tagtraum.perf.gcviewer.model.GcResourceFile;
6+
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;
7+
8+
/**
9+
* @author martin.geldmacher
10+
*/
11+
public class GCModelLoaderFactory {
12+
/**
13+
* Creates an appropriate {@link GCModelLoader} for the given {@link GCResource}
14+
*
15+
* @param gcResource the {@link GCResource}
16+
* @return an appropriate {@link GCModelLoader}
17+
*/
18+
public static GCModelLoader createFor(GCResource gcResource) {
19+
if (gcResource instanceof GcResourceFile) {
20+
return new GCModelLoaderImpl(gcResource);
21+
}
22+
else if (gcResource instanceof GcResourceSeries) {
23+
return new GCModelSeriesLoaderImpl((GcResourceSeries) gcResource);
24+
}
25+
else
26+
throw new IllegalArgumentException("Unknown GcResource: " + gcResource);
27+
}
28+
}
Lines changed: 15 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,36 @@
11
package com.tagtraum.perf.gcviewer.ctrl.impl;
22

3-
import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
43
import com.tagtraum.perf.gcviewer.imp.DataReaderException;
54
import com.tagtraum.perf.gcviewer.imp.DataReaderFacade;
6-
import com.tagtraum.perf.gcviewer.imp.MonitoredBufferedInputStream;
75
import com.tagtraum.perf.gcviewer.model.GCModel;
86
import com.tagtraum.perf.gcviewer.model.GCResource;
97

10-
import javax.swing.*;
11-
import java.beans.PropertyChangeEvent;
12-
import java.util.concurrent.ExecutionException;
13-
import java.util.logging.Level;
14-
import java.util.logging.Logger;
15-
168
/**
179
* Loads the model in a background thread (progress can be tracked by propertyChangeListeners).
1810
*
1911
* @author Hans Bausewein
2012
* @author <a href="mailto:[email protected]">Joerg Wuethrich</a>
21-
* <p>Date: November 8, 2013</p>
13+
* <p>Date: November 8, 2013</p>
2214
*/
23-
public class GCModelLoaderImpl extends SwingWorker<GCModel, Object> implements GCModelLoader {
24-
25-
private final DataReaderFacade dataReaderFacade;
15+
public class GCModelLoaderImpl extends AbstractGCModelLoaderImpl {
16+
private final DataReaderFacade dataReaderFacade;
2617
private final GCResource gcResource;
27-
28-
public GCModelLoaderImpl(final GCResource gcResource) {
29-
super();
30-
31-
this.gcResource = gcResource;
32-
this.dataReaderFacade = new DataReaderFacade();
33-
this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
34-
}
35-
36-
@Override
37-
protected GCModel doInBackground() throws Exception {
38-
setProgress(0);
39-
final GCModel result;
40-
try {
41-
result = dataReaderFacade.loadModel(gcResource);
42-
}
43-
catch (DataReaderException | RuntimeException e) {
44-
Logger logger = gcResource.getLogger();
45-
if (logger.isLoggable(Level.FINE)) {
46-
logger.log(Level.FINE, "Failed to load GCModel from " + gcResource.getResourceName(), e);
47-
}
48-
throw e;
49-
}
50-
return result;
51-
}
5218

53-
protected void done() {
54-
Logger logger = gcResource.getLogger();
19+
public GCModelLoaderImpl(final GCResource gcResource) {
20+
super();
5521

56-
try {
57-
gcResource.setModel(get());
58-
// TODO delete
59-
gcResource.getModel().printDetailedInformation();
60-
}
61-
catch (InterruptedException e) {
62-
logger.log(Level.FINE, "model get() interrupted", e);
63-
}
64-
catch (ExecutionException | RuntimeException e) {
65-
if (logger.isLoggable(Level.WARNING))
66-
logger.log(Level.WARNING, "Failed to create GCModel from " + gcResource.getResourceName(), e);
67-
}
68-
}
22+
this.gcResource = gcResource;
23+
this.dataReaderFacade = new DataReaderFacade();
24+
this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
25+
}
6926

70-
@Override
71-
public GCResource getGcResource() {
72-
return gcResource;
73-
}
27+
@Override
28+
protected GCModel loadGcModel() throws DataReaderException {
29+
return dataReaderFacade.loadModel(gcResource);
30+
}
7431

7532
@Override
76-
public void propertyChange(PropertyChangeEvent evt) {
77-
if (evt.getPropertyName() == MonitoredBufferedInputStream.PROGRESS) {
78-
setProgress((int)evt.getNewValue());
79-
}
33+
public GCResource getGcResource() {
34+
return gcResource;
8035
}
8136
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.tagtraum.perf.gcviewer.ctrl.impl;
2+
3+
import com.tagtraum.perf.gcviewer.imp.DataReaderException;
4+
import com.tagtraum.perf.gcviewer.imp.DataReaderFacade;
5+
import com.tagtraum.perf.gcviewer.model.GCModel;
6+
import com.tagtraum.perf.gcviewer.model.GCResource;
7+
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;
8+
9+
/**
10+
* An {@link AbstractGCModelLoaderImpl} that loads {@link GCResource}s as a series of logs
11+
*
12+
* @author gelder.
13+
*/
14+
public class GCModelSeriesLoaderImpl extends AbstractGCModelLoaderImpl {
15+
private final DataReaderFacade dataReaderFacade;
16+
private final GcResourceSeries gcResourceSeries;
17+
18+
public GCModelSeriesLoaderImpl(GcResourceSeries gcResourceSeries) {
19+
this.dataReaderFacade = new DataReaderFacade();
20+
this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
21+
this.gcResourceSeries = gcResourceSeries;
22+
}
23+
24+
@Override
25+
public GCResource getGcResource() {
26+
return gcResourceSeries;
27+
}
28+
29+
@Override
30+
protected GCModel loadGcModel() throws DataReaderException {
31+
return dataReaderFacade.loadModelFromSeries(gcResourceSeries);
32+
}
33+
}

0 commit comments

Comments
 (0)