1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.serviceregistry.api;
23
24 import static org.opencastproject.util.data.Monadics.mlist;
25 import static org.opencastproject.util.data.Tuple.tuple;
26
27 import org.opencastproject.job.api.Incident;
28 import org.opencastproject.job.api.Incident.Severity;
29 import org.opencastproject.job.api.IncidentTree;
30 import org.opencastproject.job.api.Job;
31 import org.opencastproject.util.NotFoundException;
32 import org.opencastproject.util.data.Function;
33 import org.opencastproject.util.data.Tuple;
34
35 import org.apache.commons.lang3.exception.ExceptionUtils;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.Date;
43 import java.util.List;
44 import java.util.Map;
45
46
47 public final class Incidents {
48
49 private static final Logger log = LoggerFactory.getLogger(Incident.class);
50
51
52
53
54 private static final String SYSTEM_UNHANDLED_EXCEPTION = "org.opencastproject.system.unhandled-exception";
55 private static final String SYSTEM_JOB_CREATION_EXCEPTION = "org.opencastproject.system.job-creation-exception";
56
57 public static final Map<String, String> NO_PARAMS = Collections.emptyMap();
58 public static final List<Tuple<String, String>> NO_DETAILS = Collections.emptyList();
59
60 private final IncidentService is;
61 private final ServiceRegistry sr;
62
63 public Incidents(ServiceRegistry sr, IncidentService is) {
64 this.is = is;
65 this.sr = sr;
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79 public void record(Job job, Severity severity, int code, Map<String, String> params,
80 List<Tuple<String, String>> details) {
81 try {
82 is.storeIncident(job, new Date(), job.getJobType() + "." + code, severity, params, details);
83 } catch (IncidentServiceException e) {
84 logException(e);
85 }
86 }
87
88
89
90
91
92
93
94
95
96 public void record(Job job, Severity severity, int code) {
97 record(job, severity, code, NO_PARAMS, NO_DETAILS);
98 }
99
100
101
102
103
104
105
106
107 public void recordFailure(Job job, int code, Map<String, String> params) {
108 record(job, Severity.FAILURE, code, params, NO_DETAILS);
109 }
110
111
112
113
114
115
116
117
118 public void recordFailure(Job job, int code, Throwable t, Map<String, String> params,
119 List<Tuple<String, String>> details) {
120 List<Tuple<String, String>> detailList = new ArrayList<>(details);
121 detailList.add(tuple("stack-trace", ExceptionUtils.getStackTrace(t)));
122 record(job, Severity.FAILURE, code, params, detailList);
123 }
124
125 public void recordJobCreationIncident(Job job, Throwable t) {
126 unhandledException(job, SYSTEM_JOB_CREATION_EXCEPTION, Severity.FAILURE, t);
127 }
128
129
130
131
132
133 public void unhandledException(Job job, Severity severity, Throwable t) {
134 unhandledException(job, SYSTEM_UNHANDLED_EXCEPTION, severity, t);
135 }
136
137
138
139
140
141
142
143 public void unhandledException(long jobId, Severity severity, Throwable t) {
144 try {
145 unhandledException(sr.getJob(jobId), severity, t);
146 } catch (NotFoundException ignore) {
147 } catch (ServiceRegistryException e) {
148 logException(e);
149 }
150 }
151
152
153
154
155
156 private void unhandledException(Job job, String code, Severity severity, Throwable t) {
157 if (!alreadyRecordedFailureIncident(job.getId())) {
158 try {
159 is.storeIncident(
160 job,
161 new Date(),
162 code,
163 severity,
164 Collections.singletonMap("exception", ExceptionUtils.getMessage(t)),
165 Arrays.asList(tuple("job-type", job.getJobType()), tuple("job-operation", job.getOperation()),
166 tuple("stack-trace", ExceptionUtils.getStackTrace(t))));
167 } catch (IncidentServiceException e) {
168 logException(e);
169 }
170 }
171 }
172
173 private void logException(Throwable t) {
174 log.error("Error recording job incident. Log exception and move on.", t);
175 }
176
177 public boolean alreadyRecordedFailureIncident(long jobId) {
178 try {
179 return findFailure(is.getIncidentsOfJob(jobId, true));
180 } catch (Exception e) {
181 return false;
182 }
183 }
184
185 static boolean findFailure(IncidentTree r) {
186 return mlist(r.getIncidents()).exists(isFailure) || mlist(r.getDescendants()).exists(findFailureFn);
187 }
188
189 static final Function<IncidentTree, Boolean> findFailureFn = new Function<IncidentTree, Boolean>() {
190 @Override
191 public Boolean apply(IncidentTree r) {
192 return findFailure(r);
193 }
194 };
195
196 static final Function<Incident, Boolean> isFailure = new Function<Incident, Boolean>() {
197 @Override
198 public Boolean apply(Incident i) {
199 return i.getSeverity() == Severity.FAILURE;
200 }
201 };
202 }