logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rgo...@apache.org
Subject svn commit: r1177174 - in /logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src: main/java/org/apache/logging/log4j/message/ test/java/org/apache/logging/log4j/message/
Date Thu, 29 Sep 2011 06:22:46 GMT
Author: rgoers
Date: Thu Sep 29 06:22:45 2011
New Revision: 1177174

URL: http://svn.apache.org/viewvc?rev=1177174&view=rev
Log:
Add extended thread dump information

Added:
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/BasicThreadInformation.java
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ExtendedThreadInformation.java
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadInformation.java
Modified:
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java

Added: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/BasicThreadInformation.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/BasicThreadInformation.java?rev=1177174&view=auto
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/BasicThreadInformation.java
(added)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/BasicThreadInformation.java
Thu Sep 29 06:22:45 2011
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.message;
+
+/**
+ *
+ */
+class BasicThreadInformation implements ThreadInformation {
+
+        private final long id;
+        private final String name;
+        private final String longName;
+        private final Thread.State state;
+        private final int priority;
+        private final boolean isAlive;
+        private final boolean isDaemon;
+        private final String threadGroupName;
+
+        public BasicThreadInformation(Thread thread) {
+            this.id = thread.getId();
+            this.name = thread.getName();
+            this.longName = thread.toString();
+            this.state = thread.getState();
+            this.priority = thread.getPriority();
+            this.isAlive = thread.isAlive();
+            this.isDaemon = thread.isDaemon();
+            ThreadGroup group = thread.getThreadGroup();
+            threadGroupName = group == null ? null : group.getName();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            BasicThreadInformation that = (BasicThreadInformation) o;
+
+            if (id != that.id) {
+                return false;
+            }
+            if (name != null ? !name.equals(that.name) : that.name != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (id ^ (id >>> 32));
+            result = 31 * result + (name != null ? name.hashCode() : 0);
+            return result;
+        }
+
+     public void printThreadInfo(StringBuilder sb) {
+        sb.append("\"").append(name).append("\" ");
+        if (isDaemon) {
+            sb.append("daemon ");
+        }
+        sb.append("prio=").append(priority).append(" tid=").append(id).append(" ");
+        if (threadGroupName != null) {
+            sb.append("group=\"").append(threadGroupName).append("\"");
+        }
+        sb.append("\n");
+        sb.append("\tThread state: ").append(state.name()).append("\n");
+    }
+
+    public void printStack(StringBuilder sb, StackTraceElement[] trace) {
+        for (StackTraceElement element : trace) {
+            sb.append("\tat ").append(element).append("\n");
+        }
+    }
+}

Added: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ExtendedThreadInformation.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ExtendedThreadInformation.java?rev=1177174&view=auto
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ExtendedThreadInformation.java
(added)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ExtendedThreadInformation.java
Thu Sep 29 06:22:45 2011
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.message;
+
+import java.lang.management.LockInfo;
+import java.lang.management.MonitorInfo;
+import java.lang.management.ThreadInfo;
+
+/**
+ * Provides information on locks and monitors in the thread dump. This class requires Java
1.6 to compile and
+ * run.
+ */
+class ExtendedThreadInformation implements ThreadInformation {
+
+    private final ThreadInfo info;
+
+
+    public ExtendedThreadInformation(ThreadInfo thread) {
+        this.info = thread;
+    }
+
+    public void printThreadInfo(StringBuilder sb) {
+        sb.append("\"").append(info.getThreadName()).append("\"");
+        sb.append(" Id=").append(info.getThreadId()).append(" ");
+        formatState(sb, info);
+        if (info.isSuspended()) {
+            sb.append(" (suspended)");
+        }
+        if (info.isInNative()) {
+            sb.append(" (in native)");
+        }
+        sb.append('\n');
+    }
+
+    public void printStack(StringBuilder sb, StackTraceElement[] stack) {
+        int i = 0;
+        for (StackTraceElement element : stack) {
+            sb.append("\tat ").append(element.toString());
+            sb.append('\n');
+            if (i == 0 && info.getLockInfo() != null) {
+                Thread.State ts = info.getThreadState();
+                switch (ts) {
+                    case BLOCKED:
+                        sb.append("\t-  blocked on ");
+                        formatLock(sb, info.getLockInfo());
+                        sb.append('\n');
+                        break;
+                    case WAITING:
+                        sb.append("\t-  waiting on ");
+                        formatLock(sb, info.getLockInfo());
+                        sb.append('\n');
+                        break;
+                    case TIMED_WAITING:
+                        sb.append("\t-  waiting on ");
+                        formatLock(sb, info.getLockInfo());
+                        sb.append('\n');
+                        break;
+                    default:
+                }
+            }
+
+            for (MonitorInfo mi : info.getLockedMonitors()) {
+                if (mi.getLockedStackDepth() == i) {
+                    sb.append("\t-  locked ");
+                    formatLock(sb, mi);
+                    sb.append('\n');
+                }
+            }
+            ++i;
+        }
+
+        LockInfo[] locks = info.getLockedSynchronizers();
+        if (locks.length > 0) {
+            sb.append("\n\tNumber of locked synchronizers = ").append(locks.length).append('\n');
+            for (LockInfo li : locks) {
+                sb.append("\t- ");
+                formatLock(sb, li);
+                sb.append('\n');
+            }
+        }
+    }
+
+    private void formatLock(StringBuilder sb, LockInfo lock) {
+        sb.append("<").append(lock.getIdentityHashCode()).append("> (a ");
+        sb.append(lock.getClassName()).append(")");
+    }
+
+    private void formatState(StringBuilder sb, ThreadInfo info) {
+        Thread.State state = info.getThreadState();
+        sb.append(state);
+        switch (state) {
+            case BLOCKED: {
+                sb.append(" (on object monitor owned by \"");
+                sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId()).append(")");
+                break;
+            }
+            case WAITING: {
+                StackTraceElement element = info.getStackTrace()[0];
+                String className = element.getClassName();
+                String method = element.getMethodName();
+                if (className.equals("java.lang.Object") && method.equals("wait"))
{
+                    sb.append(" (on object monitor");
+                    if (info.getLockOwnerName() != null) {
+                        sb.append(" owned by \"");
+                        sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
+                    }
+                    sb.append(")");
+                } else if (className.equals("java.lang.Thread") && method.equals("join"))
{
+                    sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(")");
+                } else {
+                    sb.append(" (parking for lock");
+                    if (info.getLockOwnerName() != null) {
+                        sb.append(" owned by \"");
+                        sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
+                    }
+                    sb.append(")");
+                }
+                break;
+            }
+            case TIMED_WAITING: {
+                StackTraceElement element = info.getStackTrace()[0];
+                String className = element.getClassName();
+                String method = element.getMethodName();
+                if (className.equals("java.lang.Object") && method.equals("wait"))
{
+                    sb.append(" (on object monitor");
+                    if (info.getLockOwnerName() != null) {
+                        sb.append(" owned by \"");
+                        sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
+                    }
+                    sb.append(")");
+                } else if (className.equals("java.lang.Thread") && method.equals("sleep"))
{
+                    sb.append(" (sleeping)");
+                } else if (className.equals("java.lang.Thread") && method.equals("join"))
{
+                    sb.append(" (on completion of thread ").append(info.getLockOwnerId()).append(")");
+                } else {
+                    sb.append(" (parking for lock");
+                    if (info.getLockOwnerName() != null) {
+                        sb.append(" owned by \"");
+                        sb.append(info.getLockOwnerName()).append("\" Id=").append(info.getLockOwnerId());
+                    }
+                    sb.append(")");
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}

Modified: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java?rev=1177174&r1=1177173&r2=1177174&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
(original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
Thu Sep 29 06:22:45 2011
@@ -16,7 +16,13 @@
  */
 package org.apache.logging.log4j.message;
 
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -25,12 +31,28 @@ import java.util.Map;
  */
 public class ThreadDumpMessage implements Message {
 
-    private final String title;
+    private static final long serialVersionUID = -1103400781608841088L;
+
+    private volatile Map<ThreadInformation, StackTraceElement[]> threads;
 
-    private final Map<ThreadInfo, StackTraceElement[]> threads;
+    private final String title;
 
     private String formattedMessage = null;
 
+    private static ThreadInfoFactory factory;
+
+    static {
+        Method[] methods = ThreadInfo.class.getMethods();
+        boolean basic = true;
+        for (Method method : methods) {
+            if (method.getName().equals("getLockInfo")) {
+                basic = false;
+                break;
+            }
+        }
+        factory = basic ? new BasicThreadInfoFactory() : new ExtendedThreadInfoFactory();
+    }
+
     /**
      * Generate a ThreadDumpMessage with no title.
      */
@@ -45,11 +67,12 @@ public class ThreadDumpMessage implement
      */
     public ThreadDumpMessage(String title) {
         this.title = title == null ? "" : title;
-        Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
-        threads = new HashMap<ThreadInfo, StackTraceElement[]>(map.size());
-        for (Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
-            threads.put(new ThreadInfo(entry.getKey()), entry.getValue());
-        }
+        threads = factory.createThreadInfo();
+    }
+
+    private ThreadDumpMessage(String formattedMsg, String title) {
+        this.formattedMessage = formattedMsg;
+        this.title = title;
     }
 
     /**
@@ -64,33 +87,15 @@ public class ThreadDumpMessage implement
         if (title.length() > 0) {
             sb.append("\n");
         }
-        for (Map.Entry<ThreadInfo, StackTraceElement[]> entry : threads.entrySet())
{
-            printThreadInfo(sb, entry.getKey());
-            printStack(sb, entry.getValue());
+        for (Map.Entry<ThreadInformation, StackTraceElement[]> entry : threads.entrySet())
{
+            ThreadInformation info = entry.getKey();
+            info.printThreadInfo(sb);
+            info.printStack(sb, entry.getValue());
             sb.append("\n");
         }
         return sb.toString();
     }
 
-    private void printThreadInfo(StringBuilder sb, ThreadInfo info) {
-        sb.append("\"").append(info.name).append("\" ");
-        if (info.isDaemon) {
-            sb.append("daemon ");
-        }
-        sb.append("prio=").append(info.priority).append(" tid=").append(info.id).append("
");
-        if (info.threadGroupName != null) {
-            sb.append("group=\"").append(info.threadGroupName).append("\"");
-        }
-        sb.append("\n");
-        sb.append("\tThread state: ").append(info.state.name()).append("\n");
-    }
-
-    private void printStack(StringBuilder sb, StackTraceElement[] trace) {
-        for (StackTraceElement element : trace) {
-            sb.append("\tat ").append(element).append("\n");
-        }
-    }
-
     /**
      * Returns the title.
      * @return the title.
@@ -105,62 +110,72 @@ public class ThreadDumpMessage implement
      * @return the "parameters" to this Message.
      */
     public Object[] getParameters() {
-        return new Object[] {threads};
+        return null;
+    }
+
+        /**
+     * Creates a ThreadDumpMessageProxy that can be serialized.
+     * @return a ThreadDumpMessageProxy.
+     */
+    protected Object writeReplace() {
+        return new ThreadDumpMessageProxy(this);
+    }
+
+    private void readObject(ObjectInputStream stream)
+        throws InvalidObjectException {
+        throw new InvalidObjectException("Proxy required");
     }
 
     /**
-     * Information describing each thread.
+     * Proxy pattern used to serialize the ThreadDumpMessage.
      */
-    public class ThreadInfo implements Serializable {
+    private static class ThreadDumpMessageProxy implements Serializable {
 
-        private static final long serialVersionUID = 6899550135289181860L;
-        private final long id;
-        private final String name;
-        private final String longName;
-        private final Thread.State state;
-        private final int priority;
-        private final boolean isAlive;
-        private final boolean isDaemon;
-        private final String threadGroupName;
-
-        public ThreadInfo(Thread thread) {
-            this.id = thread.getId();
-            this.name = thread.getName();
-            this.longName = thread.toString();
-            this.state = thread.getState();
-            this.priority = thread.getPriority();
-            this.isAlive = thread.isAlive();
-            this.isDaemon = thread.isDaemon();
-            ThreadGroup group = thread.getThreadGroup();
-            threadGroupName = group == null ? null : group.getName();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
+        private static final long serialVersionUID = -3476620450287648269L;
+        private String formattedMsg;
+        private String title;
 
-            ThreadInfo that = (ThreadInfo) o;
+        public ThreadDumpMessageProxy(ThreadDumpMessage msg) {
+            this.formattedMsg = msg.getFormattedMessage();
+            this.title = msg.title;
+        }
 
-            if (id != that.id) {
-                return false;
-            }
-            if (name != null ? !name.equals(that.name) : that.name != null) {
-                return false;
-            }
+        /**
+         * Return a ThreadDumpMessage using the data in the proxy.
+         * @return a ThreadDumpMessage.
+         */
+        protected Object readResolve() {
+            return new ThreadDumpMessage(formattedMsg, title);
+        }
+    }
+
+    private interface ThreadInfoFactory {
+        Map<ThreadInformation, StackTraceElement[]> createThreadInfo();
+    }
 
-            return true;
+    private static class BasicThreadInfoFactory implements ThreadInfoFactory {
+        public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
+            Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
+            Map<ThreadInformation, StackTraceElement[]> threads =
+                new HashMap<ThreadInformation, StackTraceElement[]>(map.size());
+            for (Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
+                threads.put(new BasicThreadInformation(entry.getKey()), entry.getValue());
+            }
+            return threads;
         }
+    }
 
-        @Override
-        public int hashCode() {
-            int result = (int) (id ^ (id >>> 32));
-            result = 31 * result + (name != null ? name.hashCode() : 0);
-            return result;
+    private static class ExtendedThreadInfoFactory implements ThreadInfoFactory {
+        public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
+            ThreadMXBean bean = ManagementFactory.getThreadMXBean();
+            ThreadInfo[] array = bean.dumpAllThreads(true, true);
+
+            Map<ThreadInformation, StackTraceElement[]>  threads =
+                new HashMap<ThreadInformation, StackTraceElement[]>(array.length);
+            for (ThreadInfo info : array) {
+                threads.put(new ExtendedThreadInformation(info), info.getStackTrace());
+            }
+            return threads;
         }
     }
 }

Added: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadInformation.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadInformation.java?rev=1177174&view=auto
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadInformation.java
(added)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/main/java/org/apache/logging/log4j/message/ThreadInformation.java
Thu Sep 29 06:22:45 2011
@@ -0,0 +1,13 @@
+package org.apache.logging.log4j.message;
+
+import java.io.Serializable;
+
+/**
+ *
+ */
+interface ThreadInformation {
+    void printThreadInfo(StringBuilder sb);
+
+    void printStack(StringBuilder sb, StackTraceElement[] trace);
+
+}

Modified: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java?rev=1177174&r1=1177173&r2=1177174&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
(original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-api/src/test/java/org/apache/logging/log4j/message/ThreadDumpMessageTest.java
Thu Sep 29 06:22:45 2011
@@ -40,24 +40,58 @@ public class ThreadDumpMessageTest {
 
 
     @Test
-    public void testMessageWithLocks() {
+    public void testMessageWithLocks() throws Exception {
         ReentrantLock lock = new ReentrantLock();
         lock.lock();
+        Thread thread1 = new Thread1(lock);
+        thread1.start();
         ThreadDumpMessage msg;
         synchronized(this) {
+            Thread thread2 = new Thread2(this);
+            thread2.start();
             try {
-                msg = new ThreadDumpMessage("Testing"/* , true */);
+                Thread.sleep(200);
+                msg = new ThreadDumpMessage("Testing");
             } finally {
                 lock.unlock();
             }
         }
 
         String message = msg.getFormattedMessage();
-        //System.out.print(message);
+        System.out.print(message);
         assertTrue("No header", message.contains("Testing"));
         assertTrue("No RUNNABLE", message.contains("RUNNABLE"));
         assertTrue("No ThreadDumpMessage", message.contains("ThreadDumpMessage"));
         //assertTrue("No Locks", message.contains("waiting on"));
         //assertTrue("No syncronizers", message.contains("locked syncrhonizers"));
     }
+
+    private class Thread1 extends Thread {
+        private ReentrantLock lock;
+
+        public Thread1(ReentrantLock lock) {
+            this.lock = lock;
+        }
+
+        @Override
+        public void run() {
+            lock.lock();
+            lock.unlock();
+        }
+    }
+
+    private class Thread2 extends Thread {
+        private Object obj;
+
+        public Thread2(Object obj) {
+            this.obj = obj;
+        }
+
+        @Override
+        public void run() {
+            synchronized (obj) {
+
+            }
+        }
+    }
 }



Mime
View raw message