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
author Andrew Azores <aazores@redhat.com>
date Thu, 26 May 2016 13:28:49 -0400
parents e357a435d29d
children 40a4877bd19f
files thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadTableBean.java thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTableController.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/StackFrame.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/StackTrace.java thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadState.java thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelper.java thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/internal/ThreadStateHelperTest.java
diffstat 7 files changed, 261 insertions(+), 0 deletions(-) [+]
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;