public static void registerSMAttributes(ComparisonFailureData notification, String trace,
                                          String failureMessage,
                                          Map<String, String> attrs,
                                          Throwable throwable,
                                          String comparisonFailurePrefix,
                                          final String expectedPrefix) {

    final int failureIdx = failureMessage != null ? trace.indexOf(failureMessage) : -1;
    final int failureMessageLength = failureMessage != null ? failureMessage.length() : 0;
    String details = failureIdx > -1 ? trace.substring(failureIdx + failureMessageLength) : trace;

    if (notification != null) {
      final int expectedIdx = trace.indexOf(expectedPrefix);
      final String comparisonFailureMessage;
      if (expectedIdx > 0) {
        comparisonFailureMessage = trace.substring(0, expectedIdx);
      }
      else if (failureIdx > -1) {
        comparisonFailureMessage = trace.substring(0, failureIdx + failureMessageLength);
      }
      else {
        comparisonFailureMessage = (failureMessageLength > 0 ? failureMessage + "\n" : "") + comparisonFailurePrefix;
      }
      if (!attrs.containsKey("message")) {
        attrs.put("message", comparisonFailureMessage);
      }

      final String expectedFilePath = notification.getExpectedFilePath();
      final String actualFilePath = notification.getActualFilePath();
      final String expected = notification.getExpected();
      final String actual = notification.getActual();

      int fullLength = (expectedFilePath == null && expected != null ? expected.length() : 0) +
                       (actualFilePath == null && actual != null ? actual.length() : 0) +
                       details.length() +
                       comparisonFailureMessage.length() + 100;
      if (expectedFilePath != null) {
        attrs.put("expectedFile", expectedFilePath);
      }
      else {
        writeDiffSide(attrs, "expected", expected, fullLength);
      }

      if (actualFilePath != null) {
        attrs.put("actualFile", actualFilePath);
      }
      else {
        writeDiffSide(attrs, "actual", actual, fullLength);
      }
    }
    else {
      Throwable throwableCause = null;
      try {
        throwableCause = throwable.getCause();
      }
      catch (Throwable ignored) {}

      if (!isAssertionError(throwable.getClass()) && !isAssertionError(throwableCause != null ? throwableCause.getClass() : null)) {
        attrs.put("error", "true");
      }
      attrs.put("message", failureIdx > -1 ? trace.substring(0, failureIdx + failureMessageLength)
                                           : failureMessage != null ? failureMessage : "");
    }
    attrs.put("details", details);
  }
public static void registerSMAttributes(ComparisonFailureData notification, String trace,
                                          String failureMessage,
                                          Map<String, String> attrs,
                                          Throwable throwable,
                                          String comparisonFailurePrefix,
                                          final String expectedPrefix)