Skip to content

Commit

Permalink
report worker errors as much shorter stack trace
Browse files Browse the repository at this point in the history
move filterStackTrace method into shared utility class
  • Loading branch information
abyrd committed Dec 20, 2023
1 parent bb64376 commit a79e2bb
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.conveyal.r5.util.ExceptionUtils;

import static com.conveyal.r5.util.ExceptionUtils.filterStackTrace;

/**
* This Event is fired each time a Throwable (usually an Exception or Error) occurs on the backend. It can then be
* recorded or tracked in various places - the console logs, Slack, etc. This could eventually be used for errors on
Expand Down Expand Up @@ -59,20 +61,4 @@ public String traceWithContext (boolean verbose) {
return builder.toString();
}

private static String filterStackTrace (String stackTrace) {
if (stackTrace == null) return null;
final String unknownFrame = "Unknown stack frame, probably optimized out by JVM.";
String error = stackTrace.lines().findFirst().get();
String frame = stackTrace.lines()
.map(String::strip)
.filter(s -> s.startsWith("at "))
.findFirst().orElse(unknownFrame);
String conveyalFrame = stackTrace.lines()
.map(String::strip)
.filter(s -> s.startsWith("at com.conveyal."))
.filter(s -> !frame.equals(s))
.findFirst().orElse("");
return String.join("\n", error, frame, conveyalFrame);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,17 @@ public RegionalWorkResult(OneOriginResult result, RegionalTask task) {
// TODO checkTravelTimeInvariants, checkAccessibilityInvariants to verify that values are monotonically increasing
}

/** Constructor used when results for this origin are considered unusable due to an unhandled error. */
/**
* Constructor used when results for this origin are considered unusable due to an unhandled error. Besides the
* short-form exception, most result fields are left null. There is no information to communicate, and because
* errors are often produced faster than valid results, we don't want to flood the backend with unnecessarily
* voluminous error reports. The short-form exception message is used for a similar reason, to limit the total size
* of error messages.
*/
public RegionalWorkResult(Throwable t, RegionalTask task) {
this.jobId = task.jobId;
this.taskId = task.taskId;
this.error = ExceptionUtils.shortAndLongString(t);
this.error = ExceptionUtils.filterStackTrace(t);
}

}
25 changes: 25 additions & 0 deletions src/main/java/com/conveyal/r5/util/ExceptionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,29 @@ public static String shortAndLongString (Throwable throwable) {
return shortCauseString(throwable) + "\n[detail follows]\n" + stackTraceString(throwable);
}

/**
* Given a full stack trace string with one frame per line, keep only the exception name, the first stack frame,
* and all additional frames that come from Conveyal packages. This yields a much shorter stack trace that still
* shows where the exception was thrown and where the problem originates in our own code.
*/
public static String filterStackTrace (String stackTrace) {
if (stackTrace == null) return null;
final String unknownFrame = "Unknown stack frame, probably optimized out by JVM.";
String error = stackTrace.lines().findFirst().get();
String frame = stackTrace.lines()
.map(String::strip)
.filter(s -> s.startsWith("at "))
.findFirst().orElse(unknownFrame);
String conveyalFrame = stackTrace.lines()
.map(String::strip)
.filter(s -> s.startsWith("at com.conveyal."))
.filter(s -> !frame.equals(s))
.findFirst().orElse("");
return String.join("\n", error, frame, conveyalFrame);
}

public static String filterStackTrace (Throwable throwable) {
return filterStackTrace(stackTraceString(throwable));
}

}

0 comments on commit a79e2bb

Please sign in to comment.