SAMZA-1791: Fixing problem with Serde of StackTraceElement, was causing test failure
authorrmatharu@linkedin.com <rmatharu@linkedin.com>
Sat, 28 Jul 2018 01:29:33 +0000 (18:29 -0700)
committerPrateek Maheshwari <pmaheshwari@apache.org>
Sat, 28 Jul 2018 01:29:33 +0000 (18:29 -0700)
Root cause of the failing test (after constructor param addition) is that java's StackTraceElement does not serialize/deserialize properly in all cases.

Counter example:

StackTraceElement s1 = new StackTraceElement("a", "b", null, 10);
byte[] b = new ObjectMapper().writeValueAsString(s1).getBytes("UTF-8");
StackTraceElement s2 = new ObjectMapper().readValue(b, StackTraceElement.class);
System.out.println(s1.equals(s2));// prints false

In reality, the null fileName for StackTraceElement **occurrs** for java's internal method calls
such as org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50), sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)

Author: rmatharu@linkedin.com <rmatharu@linkedin.com>

Reviewers: Shanthoosh Venkatraman <svenkata@linkedin.com>

Closes #590 from rmatharu/testfix

samza-core/src/main/scala/org/apache/samza/diagnostics/DiagnosticsExceptionEvent.java
samza-core/src/test/java/org/apache/samza/serializers/model/serializers/TestMetricsSnapshotSerdeV2.java

index d87249e..753a4a5 100644 (file)
  */
 package org.apache.samza.diagnostics;
 
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 
 
 /**
@@ -33,7 +33,8 @@ public class DiagnosticsExceptionEvent {
 
   private long timestamp; // the timestamp associated with this exception
   private Class exceptionType; // store the exception type separately
-  private Throwable throwable;
+  private String exceptionMessage; // the exception message
+  private String compactExceptionStackTrace; // a compact representation of the exception's stacktrace
   private Map mdcMap;
   // the MDC map associated with this exception, used to store/obtain any context associated with the throwable
 
@@ -41,8 +42,9 @@ public class DiagnosticsExceptionEvent {
   }
 
   public DiagnosticsExceptionEvent(long timestampMillis, Throwable throwable, Map mdcMap) {
-    this.throwable = throwable;
     this.exceptionType = throwable.getClass();
+    this.exceptionMessage = throwable.getMessage();
+    this.compactExceptionStackTrace = ExceptionUtils.getStackTrace(throwable);
     this.timestamp = timestampMillis;
     this.mdcMap = new HashMap(mdcMap);
   }
@@ -51,10 +53,6 @@ public class DiagnosticsExceptionEvent {
     return timestamp;
   }
 
-  public Throwable getThrowable() {
-    return this.throwable;
-  }
-
   public Class getExceptionType() {
     return this.exceptionType;
   }
@@ -63,6 +61,14 @@ public class DiagnosticsExceptionEvent {
     return mdcMap;
   }
 
+  public String getExceptionMessage() {
+    return exceptionMessage;
+  }
+
+  public String getCompactExceptionStackTrace() {
+    return compactExceptionStackTrace;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -72,15 +78,13 @@ public class DiagnosticsExceptionEvent {
       return false;
     }
     DiagnosticsExceptionEvent that = (DiagnosticsExceptionEvent) o;
-
-    // Throwable provides no equals impl, so we assume message & stacktrace equality suffices
-    return timestamp == that.timestamp && this.exceptionType.equals(that.exceptionType) && mdcMap.equals(that.mdcMap)
-        && this.throwable.getMessage().equals(that.throwable.getMessage()) && Arrays.equals(
-        this.throwable.getStackTrace(), that.throwable.getStackTrace());
+    return timestamp == that.timestamp && Objects.equals(exceptionType, that.exceptionType) && Objects.equals(
+        exceptionMessage, that.exceptionMessage) && Objects.equals(compactExceptionStackTrace,
+        that.compactExceptionStackTrace) && Objects.equals(mdcMap, that.mdcMap);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(timestamp, exceptionType, throwable, mdcMap);
+    return Objects.hash(timestamp, exceptionType, exceptionMessage, compactExceptionStackTrace, mdcMap);
   }
 }
\ No newline at end of file
index e4255a7..9f84ce6 100644 (file)
@@ -37,7 +37,8 @@ public class TestMetricsSnapshotSerdeV2 {
   @Test
   public void testSerde() {
     MetricsHeader metricsHeader =
-        new MetricsHeader("jobName", "i001", "container 0", "source", "300.14.25.1", "1", "1", 1, 1);
+        new MetricsHeader("jobName", "i001", "container 0", "test container ID", "source", "300.14.25.1", "1", "1", 1,
+            1);
 
     ListGauge listGauge = new ListGauge<DiagnosticsExceptionEvent>("exceptions");
     DiagnosticsExceptionEvent diagnosticsExceptionEvent1 =