Coverage Report - net.admin4j.exception.ExceptionTracker
 
Classes in this File Line Coverage Branch Coverage Complexity
ExceptionTracker
67%
63/93
50%
10/20
1.917
 
 1  
 /*
 2  
  * This software is licensed under the Apache License, Version 2.0
 3  
  * (the "License") agreement; you may not use this file except in compliance with
 4  
  * the License.  You may obtain a copy of the License at
 5  
  * 
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  * 
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 13  
  */
 14  
 package net.admin4j.exception;
 15  
 
 16  
 import java.util.Date;
 17  
 import java.util.HashMap;
 18  
 import java.util.HashSet;
 19  
 import java.util.Map;
 20  
 import java.util.Set;
 21  
 import java.util.concurrent.ConcurrentHashMap;
 22  
 
 23  
 import net.admin4j.config.Admin4JConfiguration;
 24  
 import net.admin4j.dao.DAOFactory;
 25  
 import net.admin4j.deps.commons.lang3.Validate;
 26  
 import net.admin4j.deps.commons.lang3.exception.ExceptionUtils;
 27  
 import net.admin4j.entity.ExceptionInfo;
 28  
 import net.admin4j.entity.ExceptionInfoBase;
 29  
 import net.admin4j.util.Daemon;
 30  
 import net.admin4j.vo.ExceptionStatisticVO;
 31  
 
 32  
 import org.slf4j.Logger;
 33  
 import org.slf4j.LoggerFactory;
 34  
 
 35  
 /**
 36  
  * Tracks statistics about different kinds of traces and how often they are thrown.
 37  
  * @author D. Ashmore
 38  
  * @since 1.0
 39  
  */
 40  0
 public class ExceptionTracker {
 41  
         
 42  12
         private static Map<ExceptionInfo, ExceptionInfo> thrownExceptionMap = new HashMap<ExceptionInfo, ExceptionInfo>();
 43  12
         private static Map<String, ExceptionInfo> thrownAlternateKeyMap = new HashMap<String, ExceptionInfo>();
 44  12
         private static Logger logger = LoggerFactory.getLogger(ExceptionTracker.class);
 45  12
         private static Map<String,String> exemptedExceptionClassNames = new ConcurrentHashMap<String, String>();
 46  
         
 47  
         static {
 48  12
             if (Admin4JConfiguration.isExceptionInfoStored()) {
 49  
                 try {
 50  0
                     for (ExceptionInfo eInfo: DAOFactory.getExceptionInfoDAO().findAll()) {
 51  0
                         if (validate(eInfo)) {
 52  0
                             synchronized(thrownExceptionMap) {
 53  0
                                 thrownExceptionMap.put(eInfo, eInfo);
 54  0
                                 thrownAlternateKeyMap.put(eInfo.getAlternateId(), eInfo);
 55  0
                             }
 56  
                         }
 57  0
                         else {logger.warn("Invalid exception detected: ", eInfo);}
 58  
                     }
 59  
                     
 60  0
                     logger.info("Exception Info read without error.  Nbr of exceptions read: " + thrownExceptionMap.size());
 61  
                 }
 62  0
                 catch (Throwable t) {
 63  0
                     logger.error("Error reading stored exception info", t);
 64  0
                 }
 65  
             }
 66  
         }
 67  
         
 68  
         private static boolean validate(ExceptionInfo eInfo) {
 69  0
             boolean answer = true;
 70  0
             if (eInfo == null) {  
 71  0
                 answer = false; 
 72  
             } 
 73  0
             else if (eInfo.getExceptionClassName() == null || eInfo.getAlternateId() == null) {
 74  0
                 logger.info("Exception recorded that no longer exists.  Information from that exception: {}", eInfo.toString());
 75  0
                 answer = false;
 76  
             }
 77  
             // Can't do this -- JSP generated classes might not exist yet -- but might be valid.  It's just that
 78  
             // the temp dir was purged and nobody used the JSP yet.
 79  
 //            if (answer) {
 80  
 //                for (StackTraceElement element: eInfo.getStackTrace()) {
 81  
 //                    try {
 82  
 //                    Class.forName(element.getClassName());
 83  
 //                } catch (ClassNotFoundException e) {
 84  
 //                    logger.info("Exception recorded with invalid stacktrace.  Class not found: {}.  Information from that exception: {}", e.getMessage(), eInfo.toString());
 85  
 //                    return false;
 86  
 //                }
 87  
 //                }
 88  
 //            }
 89  0
             return answer;
 90  
         }
 91  
 
 92  12
     private static final Daemon CLEANUP_DAEMON = new Daemon(new ExceptionTrackerCleanupTask(), "Admin4J-ExceptionTrackerCleanupTask");
 93  
     static {
 94  12
         Runtime.getRuntime().addShutdownHook(new ExceptionTrackerShutdownHook());
 95  12
     }
 96  
     
 97  
     /**
 98  
      * Adds class names for exceptions that will <b>not</b> be tracked.
 99  
      * @param className
 100  
      */
 101  
     public static void addExemptedExceptionClassName(String className) {
 102  
         Validate.notEmpty(className, "Null or blank class name not allowed.");
 103  3
         String local = className.trim();
 104  3
         exemptedExceptionClassNames.put(local, local);
 105  3
     }
 106  
         
 107  
         /**
 108  
          * Tracks an exception for reporting/browsing.
 109  
          * @param t
 110  
          */
 111  
         public static void track(Throwable t) {
 112  
                 Validate.notNull(t, "Null exception not allowed.");
 113  
                 
 114  
                 Throwable rootCause = ExceptionUtils.getRootCause(t);
 115  51
                 if (rootCause == null) {
 116  36
                     rootCause = t;
 117  
                 }
 118  
                 
 119  51
                 if (exemptedExceptionClassNames.containsKey(rootCause.getClass().getName())) {
 120  15
                     logger.debug("Exception bypassed: {} - {}", rootCause.getClass().getName(), rootCause.getMessage());
 121  15
                     return;
 122  
                 }
 123  
                 
 124  36
                 ExceptionInfo eInfo = findExceptionInfo(rootCause);
 125  36
                 eInfo.setLastOccurrenceMessage(rootCause.getMessage());
 126  36
                 eInfo.postOccurance(System.identityHashCode(rootCause));
 127  
                 
 128  36
                 logger.debug("Exception tracked: {} - {}", rootCause.getClass().getName(), rootCause.getMessage());
 129  36
         }
 130  
         
 131  
         public static void recordUrl(String alternateId, String urlString) {
 132  0
             synchronized(thrownExceptionMap) {
 133  0
                 ExceptionInfoBase eInfo = thrownAlternateKeyMap.get(alternateId);
 134  0
                 if (eInfo != null) {
 135  0
                     eInfo.setTroubleTicketUrl(urlString);
 136  
                 }
 137  0
             }
 138  0
         }
 139  
         
 140  
         public static ExceptionInfo lookupException(String alternateId) {
 141  12
         synchronized(thrownExceptionMap) {
 142  12
             return thrownAlternateKeyMap.get(alternateId);
 143  0
         }
 144  
     }
 145  
         
 146  
         public static void deleteException(String alternateId) {
 147  3
             synchronized(thrownExceptionMap) {
 148  3
             ExceptionInfoBase eInfo = thrownAlternateKeyMap.get(alternateId);
 149  3
             if (eInfo != null) {
 150  3
                 thrownAlternateKeyMap.remove(alternateId);
 151  3
                 thrownExceptionMap.remove(eInfo);
 152  
                 
 153  3
                 if (Admin4JConfiguration.isExceptionInfoStored()) {
 154  0
                     DAOFactory.getExceptionInfoDAO().saveAll(getExceptionInfoSet());
 155  
                 }
 156  
             }
 157  3
             }
 158  3
     }
 159  
         
 160  
         public static void setPurgeThresholdInDays(int days) {
 161  3
             ExceptionTrackerCleanupTask task = (ExceptionTrackerCleanupTask)CLEANUP_DAEMON.getTask();
 162  3
             task.setPurgeThresholdInDays(days);
 163  3
         }
 164  
         
 165  
         protected static int getMapSize() {
 166  0
             synchronized(thrownExceptionMap) {
 167  0
                 return thrownExceptionMap.size();
 168  0
             }
 169  
         }
 170  
         
 171  
         public static Set<ExceptionInfo> getExceptionInfoSet() {
 172  12
             Set<ExceptionInfo> set = new HashSet<ExceptionInfo>();
 173  12
             synchronized(thrownExceptionMap) {
 174  12
                 set.addAll(thrownExceptionMap.keySet());
 175  12
             }
 176  12
             return set;
 177  
         }
 178  
         
 179  
         public static Set<ExceptionStatisticVO> getExceptionStatisticSet() {
 180  9
         Set<ExceptionStatisticVO> set = new HashSet<ExceptionStatisticVO>();
 181  9
         for (ExceptionInfo eInfo: getExceptionInfoSet()) {
 182  12
             set.add(new ExceptionStatisticVO(eInfo));
 183  
         }
 184  9
         return set;
 185  
     }
 186  
         
 187  
         protected static void purgeException(ExceptionInfo eInfo) {
 188  3
             synchronized(thrownExceptionMap) {
 189  3
                 thrownExceptionMap.remove(eInfo);
 190  3
                 thrownAlternateKeyMap.remove(eInfo.getAlternateId());
 191  3
             }
 192  3
         }
 193  
         
 194  
         protected static ExceptionInfo findExceptionInfo(Throwable t) {
 195  51
                 StackTraceElement[] stackTrace = t.getStackTrace();
 196  
                 
 197  51
                 ExceptionInfo eInfo = null;
 198  51
                 synchronized(thrownExceptionMap) {
 199  51
                     eInfo = thrownExceptionMap.get(new ExceptionInfo(t.getClass().getName(), stackTrace));
 200  51
                     if (eInfo == null) {
 201  15
                             eInfo = new ExceptionInfo(t.getClass().getName(), stackTrace);
 202  15
                             Date ts = new Date();
 203  15
                             eInfo.setFirstOccuranceDt(ts);
 204  15
                             eInfo.setLastOccuranceDt(ts);
 205  15
                             eInfo.setLastOccurrenceMessage(t.getMessage());
 206  15
                             eInfo.setExceptionClass(t.getClass());
 207  15
                             thrownExceptionMap.put(eInfo, eInfo);
 208  15
                             thrownAlternateKeyMap.put(eInfo.getAlternateId(), eInfo);
 209  
                     }
 210  51
                 }
 211  
                 
 212  51
                 return eInfo;
 213  
         }
 214  
 
 215  
 }