Skip to content

Commit

Permalink
Support for logfile rotation (#61)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
geld0r committed Jun 5, 2016
1 parent 12070b2 commit 262dfed
Show file tree
Hide file tree
Showing 34 changed files with 2,413 additions and 255 deletions.
Expand Up @@ -30,6 +30,13 @@ public interface GCModelLoaderController {


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


/**
* Opens the given {@link GCResource}s as a series of rotated logfiles.
*
* @param gcResourceList a list of rotated gc logfiles. Ordering is not required.
*/
void openAsSeries(List<GCResource> gcResourceList);

/** /**
* Reload all models of <code>gcDocument</code> and provide tracker. The tracker will * Reload all models of <code>gcDocument</code> and provide tracker. The tracker will
* fire a propertyChangeEvent, as soon as all GCModelLoaders have finished loading. * fire a propertyChangeEvent, as soon as all GCModelLoaders have finished loading.
Expand Down
@@ -0,0 +1,66 @@
package com.tagtraum.perf.gcviewer.ctrl.action;

import com.tagtraum.perf.gcviewer.ctrl.GCModelLoaderController;
import com.tagtraum.perf.gcviewer.model.GCResource;
import com.tagtraum.perf.gcviewer.model.GcResourceFile;
import com.tagtraum.perf.gcviewer.util.LocalisationHelper;
import com.tagtraum.perf.gcviewer.view.ActionCommands;
import com.tagtraum.perf.gcviewer.view.GCViewerGui;
import com.tagtraum.perf.gcviewer.view.OpenFileView;
import com.tagtraum.perf.gcviewer.view.util.ImageHelper;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
* Allows to open a series of log files, treating them as a consecutive log.
*
* @author martin.geldmacher
*/
public class OpenSeries extends AbstractAction {
private static final Logger logger = Logger.getLogger(OpenSeries.class.getName());

private GCModelLoaderController controller;
private GCViewerGui gcViewer;
private OpenFileView openFileView;

public OpenSeries(GCModelLoaderController controller, final GCViewerGui gcViewer) {
this.controller = controller;
this.gcViewer = gcViewer;

putValue(NAME, LocalisationHelper.getString("main_frame_menuitem_open_series"));
putValue(SHORT_DESCRIPTION, LocalisationHelper.getString("main_frame_menuitem_hint_open_series"));
putValue(MNEMONIC_KEY, Integer.valueOf(LocalisationHelper.getString("main_frame_menuitem_mnemonic_open_series").charAt(0)));
putValue(ACTION_COMMAND_KEY, ActionCommands.OPEN_SERIES.toString());
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke('S', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
putValue(SMALL_ICON, ImageHelper.loadImageIcon("open.png"));

openFileView = new OpenFileView();
}

@Override
public void actionPerformed(ActionEvent e) {
final int val = openFileView.showOpenDialog(gcViewer);
if (val == JFileChooser.APPROVE_OPTION) {
File[] selectedFiles = openFileView.getSelectedFiles();
List<GCResource> resources = getResources(selectedFiles);
controller.openAsSeries(resources);
}
}

private List<GCResource> getResources(File[] selectedFiles) {
if (selectedFiles == null || selectedFiles.length == 0)
throw new IllegalArgumentException("At least one file must be selected!");

java.util.List<GCResource> resources = new ArrayList<>();
for (File file : selectedFiles) {
resources.add(new GcResourceFile(file));
}
return resources;
}
}
@@ -0,0 +1,62 @@
package com.tagtraum.perf.gcviewer.ctrl.impl;

import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
import com.tagtraum.perf.gcviewer.imp.DataReaderException;
import com.tagtraum.perf.gcviewer.imp.MonitoredBufferedInputStream;
import com.tagtraum.perf.gcviewer.model.GCModel;

import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Base class for {@link GCModelLoader}s
*
* @author martin.geldmacher (refactored)
*/
public abstract class AbstractGCModelLoaderImpl extends SwingWorker<GCModel, Object> implements GCModelLoader {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName() == MonitoredBufferedInputStream.PROGRESS) {
setProgress((int) evt.getNewValue());
}
}

protected void done() {
Logger logger = getGcResource().getLogger();

try {
getGcResource().setModel(get());
// TODO delete
getGcResource().getModel().printDetailedInformation();
}
catch (InterruptedException e) {
logger.log(Level.FINE, "model get() interrupted", e);
}
catch (ExecutionException | RuntimeException e) {
if (logger.isLoggable(Level.WARNING))
logger.log(Level.WARNING, "Failed to create GCModel from " + getGcResource().getResourceName(), e);
}
}

@Override
protected GCModel doInBackground() throws Exception {
setProgress(0);
final GCModel result;
try {
result = loadGcModel();
}
catch (DataReaderException | RuntimeException e) {
Logger logger = getGcResource().getLogger();
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Failed to load GCModel from " + getGcResource().getResourceName(), e);
}
throw e;
}
return result;
}

protected abstract GCModel loadGcModel() throws DataReaderException;
}
Expand Up @@ -6,6 +6,7 @@
import com.tagtraum.perf.gcviewer.ctrl.impl.FileDropTargetListener.DropFlavor; import com.tagtraum.perf.gcviewer.ctrl.impl.FileDropTargetListener.DropFlavor;
import com.tagtraum.perf.gcviewer.model.GcResourceFile; import com.tagtraum.perf.gcviewer.model.GcResourceFile;
import com.tagtraum.perf.gcviewer.model.GCResource; import com.tagtraum.perf.gcviewer.model.GCResource;
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;
import com.tagtraum.perf.gcviewer.view.GCDocument; import com.tagtraum.perf.gcviewer.view.GCDocument;
import com.tagtraum.perf.gcviewer.view.GCViewerGui; import com.tagtraum.perf.gcviewer.view.GCViewerGui;
import com.tagtraum.perf.gcviewer.view.GCViewerGuiMenuBar; import com.tagtraum.perf.gcviewer.view.GCViewerGuiMenuBar;
Expand All @@ -17,10 +18,7 @@
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


/** /**
* Controller class for {@link GCModelLoader}. * Controller class for {@link GCModelLoader}.
Expand Down Expand Up @@ -113,25 +111,25 @@ private ViewMenuController getViewMenuController() {


throw new IllegalStateException("no ActionListener of type 'ViewMenuController' found"); throw new IllegalStateException("no ActionListener of type 'ViewMenuController' found");
} }

private void openGCResource(GCResource gcResource) { private void openGCResource(GCResource gcResource) {
GCModelLoader loader = new GCModelLoaderImpl(gcResource); GCModelLoader loader = new GCModelLoaderImpl(gcResource);
openGCResource(gcResource, loader);
}

private void openGCResource(GCResource gcResource, GCModelLoader loader) {
GCDocument document = new GCDocument(gcViewerGui.getPreferences(), gcResource.getResourceName()); GCDocument document = new GCDocument(gcViewerGui.getPreferences(), gcResource.getResourceName());
document.setDropTarget( document.setDropTarget(new DropTarget(document, DnDConstants.ACTION_COPY, new FileDropTargetListener(this, DropFlavor.ADD)));
new DropTarget(document,
DnDConstants.ACTION_COPY,
new FileDropTargetListener(this, DropFlavor.ADD))
);
document.addInternalFrameListener(new GCViewerGuiInternalFrameController()); document.addInternalFrameListener(new GCViewerGuiInternalFrameController());

gcViewerGui.addDocument(document); gcViewerGui.addDocument(document);

GCDocumentController docController = new GCDocumentController(document); GCDocumentController docController = new GCDocumentController(document);
docController.addGCResource(loader, getViewMenuController()); docController.addGCResource(loader, getViewMenuController());

loader.execute(); loader.execute();
} }

@Override @Override
public void open(File[] files) { public void open(File[] files) {
List<GCResource> gcResourceList = new ArrayList<GCResource>(); List<GCResource> gcResourceList = new ArrayList<GCResource>();
Expand Down Expand Up @@ -164,24 +162,32 @@ public void open(List<GCResource> gcResourceList) {


getRecentGCResourcesModel().add(gcResourceList); getRecentGCResourcesModel().add(gcResourceList);
} }


@Override
public void openAsSeries(List<GCResource> gcResourceList) {
GcResourceSeries resourceSeries = new GcResourceSeries(gcResourceList);
GCModelLoader loader = GCModelLoaderFactory.createFor(resourceSeries);
openGCResource(loader.getGcResource(), loader);
getRecentGCResourcesModel().add(Collections.singletonList(resourceSeries));
}

@Override @Override
public GCModelLoaderGroupTracker reload(GCDocument gcDocument) { public GCModelLoaderGroupTracker reload(GCDocument gcDocument) {
GCModelLoaderGroupTracker tracker = new GCModelLoaderGroupTrackerImpl(); GCModelLoaderGroupTracker tracker = new GCModelLoaderGroupTrackerImpl();
for (GCResource gcResource : gcDocument.getGCResources()) { for (GCResource gcResource : gcDocument.getGCResources()) {
if (gcResource.hasUnderlyingResourceChanged()) { if (gcResource.hasUnderlyingResourceChanged()) {
gcResource.reset(); gcResource.reset();
gcResource.setIsReload(true); gcResource.setIsReload(true);
GCModelLoader loader = new GCModelLoaderImpl(gcResource); GCModelLoader loader = GCModelLoaderFactory.createFor(gcResource);
GCDocumentController docController = getDocumentController(gcDocument); GCDocumentController docController = getDocumentController(gcDocument);
docController.reloadGCResource(loader); docController.reloadGCResource(loader);


tracker.addGcModelLoader(loader); tracker.addGcModelLoader(loader);
} }
} }

tracker.execute(); tracker.execute();

return tracker; return tracker;
} }


Expand Down
@@ -0,0 +1,28 @@
package com.tagtraum.perf.gcviewer.ctrl.impl;

import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
import com.tagtraum.perf.gcviewer.model.GCResource;
import com.tagtraum.perf.gcviewer.model.GcResourceFile;
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;

/**
* @author martin.geldmacher
*/
public class GCModelLoaderFactory {
/**
* Creates an appropriate {@link GCModelLoader} for the given {@link GCResource}
*
* @param gcResource the {@link GCResource}
* @return an appropriate {@link GCModelLoader}
*/
public static GCModelLoader createFor(GCResource gcResource) {
if (gcResource instanceof GcResourceFile) {
return new GCModelLoaderImpl(gcResource);
}
else if (gcResource instanceof GcResourceSeries) {
return new GCModelSeriesLoaderImpl((GcResourceSeries) gcResource);
}
else
throw new IllegalArgumentException("Unknown GcResource: " + gcResource);
}
}
@@ -1,81 +1,36 @@
package com.tagtraum.perf.gcviewer.ctrl.impl; package com.tagtraum.perf.gcviewer.ctrl.impl;


import com.tagtraum.perf.gcviewer.ctrl.GCModelLoader;
import com.tagtraum.perf.gcviewer.imp.DataReaderException; import com.tagtraum.perf.gcviewer.imp.DataReaderException;
import com.tagtraum.perf.gcviewer.imp.DataReaderFacade; import com.tagtraum.perf.gcviewer.imp.DataReaderFacade;
import com.tagtraum.perf.gcviewer.imp.MonitoredBufferedInputStream;
import com.tagtraum.perf.gcviewer.model.GCModel; import com.tagtraum.perf.gcviewer.model.GCModel;
import com.tagtraum.perf.gcviewer.model.GCResource; import com.tagtraum.perf.gcviewer.model.GCResource;


import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

/** /**
* Loads the model in a background thread (progress can be tracked by propertyChangeListeners). * Loads the model in a background thread (progress can be tracked by propertyChangeListeners).
* *
* @author Hans Bausewein * @author Hans Bausewein
* @author <a href="mailto:gcviewer@gmx.ch">Joerg Wuethrich</a> * @author <a href="mailto:gcviewer@gmx.ch">Joerg Wuethrich</a>
* <p>Date: November 8, 2013</p> * <p>Date: November 8, 2013</p>
*/ */
public class GCModelLoaderImpl extends SwingWorker<GCModel, Object> implements GCModelLoader { public class GCModelLoaderImpl extends AbstractGCModelLoaderImpl {

private final DataReaderFacade dataReaderFacade;
private final DataReaderFacade dataReaderFacade;
private final GCResource gcResource; private final GCResource gcResource;

public GCModelLoaderImpl(final GCResource gcResource) {
super();

this.gcResource = gcResource;
this.dataReaderFacade = new DataReaderFacade();
this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
}

@Override
protected GCModel doInBackground() throws Exception {
setProgress(0);
final GCModel result;
try {
result = dataReaderFacade.loadModel(gcResource);
}
catch (DataReaderException | RuntimeException e) {
Logger logger = gcResource.getLogger();
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Failed to load GCModel from " + gcResource.getResourceName(), e);
}
throw e;
}
return result;
}


protected void done() { public GCModelLoaderImpl(final GCResource gcResource) {
Logger logger = gcResource.getLogger(); super();


try { this.gcResource = gcResource;
gcResource.setModel(get()); this.dataReaderFacade = new DataReaderFacade();
// TODO delete this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
gcResource.getModel().printDetailedInformation(); }
}
catch (InterruptedException e) {
logger.log(Level.FINE, "model get() interrupted", e);
}
catch (ExecutionException | RuntimeException e) {
if (logger.isLoggable(Level.WARNING))
logger.log(Level.WARNING, "Failed to create GCModel from " + gcResource.getResourceName(), e);
}
}


@Override @Override
public GCResource getGcResource() { protected GCModel loadGcModel() throws DataReaderException {
return gcResource; return dataReaderFacade.loadModel(gcResource);
} }


@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public GCResource getGcResource() {
if (evt.getPropertyName() == MonitoredBufferedInputStream.PROGRESS) { return gcResource;
setProgress((int)evt.getNewValue());
}
} }
} }
@@ -0,0 +1,33 @@
package com.tagtraum.perf.gcviewer.ctrl.impl;

import com.tagtraum.perf.gcviewer.imp.DataReaderException;
import com.tagtraum.perf.gcviewer.imp.DataReaderFacade;
import com.tagtraum.perf.gcviewer.model.GCModel;
import com.tagtraum.perf.gcviewer.model.GCResource;
import com.tagtraum.perf.gcviewer.model.GcResourceSeries;

/**
* An {@link AbstractGCModelLoaderImpl} that loads {@link GCResource}s as a series of logs
*
* @author gelder.
*/
public class GCModelSeriesLoaderImpl extends AbstractGCModelLoaderImpl {
private final DataReaderFacade dataReaderFacade;
private final GcResourceSeries gcResourceSeries;

public GCModelSeriesLoaderImpl(GcResourceSeries gcResourceSeries) {
this.dataReaderFacade = new DataReaderFacade();
this.dataReaderFacade.addPropertyChangeListener(this); // receive progress updates from loading
this.gcResourceSeries = gcResourceSeries;
}

@Override
public GCResource getGcResource() {
return gcResourceSeries;
}

@Override
protected GCModel loadGcModel() throws DataReaderException {
return dataReaderFacade.loadModelFromSeries(gcResourceSeries);
}
}

0 comments on commit 262dfed

Please sign in to comment.