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