Skip to content

Commit

Permalink
SentryJobErrorReportingClient: set event platform from parsed stacktr…
Browse files Browse the repository at this point in the history
…ace (airbytehq#16906)

* set sentry event platform from parsed stacktrace

* fix pmd

* use an enum

* use enum in test

* fix imports

* fix imports

* format

* fix imports
  • Loading branch information
pedroslopez authored and jhammarstedt committed Oct 31, 2022
1 parent 33da489 commit 88c5f1b
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,51 @@
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
public class SentryExceptionHelper {

private static final Logger LOGGER = LoggerFactory.getLogger(SentryExceptionHelper.class);
public record SentryParsedException(SentryExceptionPlatform platform, List<SentryException> exceptions) {}

public static final String ERROR_MAP_MESSAGE_KEY = "errorMessage";
public static final String ERROR_MAP_TYPE_KEY = "errorType";
private static final Logger LOGGER = LoggerFactory.getLogger(SentryExceptionHelper.class);

public enum ERROR_MAP_KEYS {
ERROR_MAP_MESSAGE_KEY,
ERROR_MAP_TYPE_KEY
}

/**
* Specifies the platform for a thrown exception. Values must be supported by Sentry as specified in
* https://develop.sentry.dev/sdk/event-payloads/#required-attributes. Currently, only java, python
* and dbt (other) exceptions are supported.
*/
public enum SentryExceptionPlatform {

JAVA("java"),
PYTHON("python"),
OTHER("other");

private final String value;

SentryExceptionPlatform(final String value) {
this.value = value;
}

public String getValue() {
return value;
}

@Override
public String toString() {
return String.valueOf(value);
}

}

/**
* Processes a raw stacktrace string into structured SentryExceptions
* <p>
* Currently, Java and Python stacktraces are supported. If an unsupported stacktrace format is
* encountered, an empty optional will be returned, in which case we can fall back to alternate
* grouping.
*/
public Optional<List<SentryException>> buildSentryExceptions(final String stacktrace) {
public Optional<SentryParsedException> buildSentryExceptions(final String stacktrace) {
return Exceptions.swallowWithDefault(() -> {
if (stacktrace.startsWith("Traceback (most recent call last):")) {
return buildPythonSentryExceptions(stacktrace);
Expand All @@ -56,7 +83,7 @@ public Optional<List<SentryException>> buildSentryExceptions(final String stackt
}, Optional.empty());
}

private static Optional<List<SentryException>> buildPythonSentryExceptions(final String stacktrace) {
private static Optional<SentryParsedException> buildPythonSentryExceptions(final String stacktrace) {
final List<SentryException> sentryExceptions = new ArrayList<>();

// separate chained exceptions
Expand Down Expand Up @@ -115,10 +142,10 @@ private static Optional<List<SentryException>> buildPythonSentryExceptions(final
if (sentryExceptions.isEmpty())
return Optional.empty();

return Optional.of(sentryExceptions);
return Optional.of(new SentryParsedException(SentryExceptionPlatform.PYTHON, sentryExceptions));
}

private static Optional<List<SentryException>> buildJavaSentryExceptions(final String stacktrace) {
private static Optional<SentryParsedException> buildJavaSentryExceptions(final String stacktrace) {
final List<SentryException> sentryExceptions = new ArrayList<>();

// separate chained exceptions
Expand Down Expand Up @@ -182,10 +209,10 @@ private static Optional<List<SentryException>> buildJavaSentryExceptions(final S
if (sentryExceptions.isEmpty())
return Optional.empty();

return Optional.of(sentryExceptions);
return Optional.of(new SentryParsedException(SentryExceptionPlatform.JAVA, sentryExceptions));
}

private static Optional<List<SentryException>> buildNormalizationDbtSentryExceptions(final String stacktrace) {
private static Optional<SentryParsedException> buildNormalizationDbtSentryExceptions(final String stacktrace) {
final List<SentryException> sentryExceptions = new ArrayList<>();

final Map<ERROR_MAP_KEYS, String> usefulErrorMap = getUsefulErrorMessageAndTypeFromDbtError(stacktrace);
Expand All @@ -202,7 +229,7 @@ private static Optional<List<SentryException>> buildNormalizationDbtSentryExcept
if (sentryExceptions.isEmpty())
return Optional.empty();

return Optional.of(sentryExceptions);
return Optional.of(new SentryParsedException(SentryExceptionPlatform.OTHER, sentryExceptions));
}

public static Map<ERROR_MAP_KEYS, String> getUsefulErrorMessageAndTypeFromDbtError(final String stacktrace) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.airbyte.config.FailureReason;
import io.airbyte.config.Metadata;
import io.airbyte.config.StandardWorkspace;
import io.airbyte.persistence.job.errorreporter.SentryExceptionHelper.SentryParsedException;
import io.sentry.Hub;
import io.sentry.IHub;
import io.sentry.NoOpHub;
Expand All @@ -24,6 +25,7 @@
public class SentryJobErrorReportingClient implements JobErrorReportingClient {

static final String STACKTRACE_PARSE_ERROR_TAG_KEY = "stacktrace_parse_error";
static final String STACKTRACE_PLATFORM_TAG_KEY = "stacktrace_platform";
private final IHub sentryHub;
private final SentryExceptionHelper exceptionHelper;

Expand Down Expand Up @@ -98,9 +100,13 @@ public void reportJobFailureReason(@Nullable final StandardWorkspace workspace,
// attach failure reason stack trace
final String failureStackTrace = failureReason.getStacktrace();
if (failureStackTrace != null && !failureStackTrace.isBlank()) {
final Optional<List<SentryException>> parsedExceptions = exceptionHelper.buildSentryExceptions(failureStackTrace);
if (parsedExceptions.isPresent()) {
event.setExceptions(parsedExceptions.get());
final Optional<SentryParsedException> optParsedException = exceptionHelper.buildSentryExceptions(failureStackTrace);
if (optParsedException.isPresent()) {
final SentryParsedException parsedException = optParsedException.get();
final String platform = parsedException.platform().getValue();
event.setPlatform(platform);
event.setTag(STACKTRACE_PLATFORM_TAG_KEY, platform);
event.setExceptions(parsedException.exceptions());
} else {
event.setTag(STACKTRACE_PARSE_ERROR_TAG_KEY, "1");

Expand Down
Loading

0 comments on commit 88c5f1b

Please sign in to comment.