Mercurial > hg > thermostat
changeset 2315:0f94f0744d94
Add StackTrace field to ThreadState
Allows for stack trace recording during thread monitoring
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-May/018962.html
line wrap: on
line diff
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableBean.java Tue May 24 12:02:31 2016 -0400 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableBean.java Thu May 26 13:28:49 2016 -0400 @@ -36,7 +36,11 @@ package com.redhat.thermostat.thread.client.common; +import com.redhat.thermostat.thread.model.StackTrace; + +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Objects; public class ThreadTableBean { @@ -58,6 +62,8 @@ private long monitorTime; private long sleepingTime; + private List<StackTrace> stackTraces = new ArrayList<>(); + public long getId() { return id; } @@ -200,5 +206,14 @@ public long getWaitingTime() { return waitingTime; } + + public void addStackTrace(StackTrace stackTrace) { + stackTraces.add(stackTrace); + } + + public List<StackTrace> getStackTraces() { + return stackTraces; + } + }
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTableController.java Tue May 24 12:02:31 2016 -0400 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTableController.java Thu May 26 13:28:49 2016 -0400 @@ -44,6 +44,7 @@ import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; import com.redhat.thermostat.thread.client.common.view.ThreadTableView; import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.StackTrace; import com.redhat.thermostat.thread.model.ThreadState; import java.util.HashMap; import java.util.Map; @@ -181,6 +182,8 @@ bean.setStopTimeStamp(thread.getTimeStamp()); + bean.addStackTrace(StackTrace.fromJson(thread.getStackTrace())); + threadTableView.display(bean); boolean _stopLooping = stopLooping;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/StackFrame.java Thu May 26 13:28:49 2016 -0400 @@ -0,0 +1,148 @@ +/* + * Copyright 2012-2016 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.thread.model; + +import com.google.gson.Gson; + +public class StackFrame { + + private static final Gson gson = new Gson(); + + private String fileName; + private String packageName; + private String className; + private String methodName; + private int lineNumber; + private boolean isNativeMethod; + + public StackFrame() {} + + public StackFrame(String fileName, String packageName, String className, String methodName, + int lineNumber, boolean isNativeMethod) { + this.fileName = fileName; + this.packageName = packageName; + this.className = className; + this.methodName = methodName; + this.lineNumber = lineNumber; + this.isNativeMethod = isNativeMethod; + } + + public StackFrame(StackTraceElement frame) { + this( + frame.getFileName(), + parsePackage(frame.getClassName()), + parseClass(frame.getClassName()), + frame.getMethodName(), + frame.getLineNumber(), + frame.isNativeMethod() + ); + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public int getLineNumber() { + return lineNumber; + } + + public void setLineNumber(int lineNumber) { + this.lineNumber = lineNumber; + } + + public boolean isNativeMethod() { + return isNativeMethod; + } + + public void setNativeMethod(boolean nativeMethod) { + isNativeMethod = nativeMethod; + } + + static String parsePackage(String className) { + if (className.contains(".")) { + return className.substring(0, className.lastIndexOf('.')); + } else { + return null; + } + } + + static String parseClass(String className) { + if (className.contains(".")) { + return className.substring(className.lastIndexOf('.') + 1); + } else { + return className; + } + } + + public static StackFrame fromJson(String json) { + return gson.fromJson(json, StackFrame.class); + } + + @Override + public String toString() { + return gson.toJson(this); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/StackTrace.java Thu May 26 13:28:49 2016 -0400 @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2016 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.thread.model; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.List; + +public class StackTrace { + + private static final Gson gson = new Gson(); + + private final List<StackFrame> frames = new ArrayList<>(); + + public StackTrace() {} + + public StackTrace(List<StackFrame> frames) { + this.frames.addAll(frames); + } + + public StackTrace(StackTraceElement[] frames) { + for (StackTraceElement frame : frames) { + this.frames.add(new StackFrame(frame)); + } + } + + public List<StackFrame> getFrames() { + return new ArrayList<>(frames); + } + + public static StackTrace fromJson(String json) { + return gson.fromJson(json, StackTrace.class); + } + + @Override + public String toString() { + return gson.toJson(this); + } + +}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadState.java Tue May 24 12:02:31 2016 -0400 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadState.java Thu May 26 13:28:49 2016 -0400 @@ -43,6 +43,7 @@ import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.storage.model.TimeStampedPojo; import com.redhat.thermostat.thread.dao.internal.ThreadDaoCategories; +import com.sun.tools.hat.internal.model.StackTrace; /** * Represents a single delta variation of a Thread state. @@ -63,6 +64,7 @@ private long blockedTime; private long waitedCount; private long waitedTime; + private String stackTrace; public ThreadState() { this(null); @@ -163,6 +165,16 @@ return inNative; } + @Persist + public void setStackTrace(String stackTrace) { + this.stackTrace = stackTrace; + } + + @Persist + public String getStackTrace() { + return stackTrace; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -182,6 +194,8 @@ return false; if (vmId != null ? !vmId.equals(that.vmId) : that.vmId != null) return false; + if (stackTrace != null ? !stackTrace.equals(that.stackTrace) : that.stackTrace != null) + return false; return true; } @@ -196,6 +210,7 @@ result = 31 * result + (int) (id ^ (id >>> 32)); result = 31 * result + (suspended ? 1 : 0); result = 31 * result + (inNative ? 1 : 0); + result = 31 * result + (stackTrace != null ? stackTrace.hashCode() : 0); return result; }
--- a/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelper.java Tue May 24 12:02:31 2016 -0400 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelper.java Thu May 26 13:28:49 2016 -0400 @@ -39,7 +39,9 @@ import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.thread.dao.ThreadDao; import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.StackTrace; import com.redhat.thermostat.thread.model.ThreadState; + import java.lang.management.ThreadInfo; public class ThreadStateHelper { @@ -82,6 +84,8 @@ state.setWaitedCount(beanInfo.getWaitedCount()); state.setWaitedTime(beanInfo.getWaitedTime()); + state.setStackTrace(new StackTrace(beanInfo.getStackTrace()).toString()); + // TODO: lock information return state;
--- a/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelperTest.java Tue May 24 12:02:31 2016 -0400 +++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelperTest.java Thu May 26 13:28:49 2016 -0400 @@ -85,6 +85,7 @@ ThreadInfo info = mock(ThreadInfo.class); when(info.getThreadState()).thenReturn(Thread.State.BLOCKED); + when(info.getStackTrace()).thenReturn(new StackTraceElement[0]); long timestamp = -1l;