1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
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 | |
|
37 | |
|
38 | |
|
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 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
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 | |
|
99 | |
|
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 | |
|
109 | |
|
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 | |
} |