From e152db4f383425e7ede9f87ac9f9f257e64fab01 Mon Sep 17 00:00:00 2001
From: Pavol Loffay
Date: Mon, 26 Feb 2018 14:40:41 +0100
Subject: [PATCH] Expand exception logs (#168)
* Expand exception logs
Signed-off-by: Pavol Loffay
* Fix review comments
Signed-off-by: Pavol Loffay
* increase coverage
Signed-off-by: Pavol Loffay
* Increase coverage 2
Signed-off-by: Pavol Loffay
* Increase coverage 3
Signed-off-by: Pavol Loffay
* fix style
Signed-off-by: Pavol Loffay
---
.../src/main/java/com/uber/jaeger/Span.java | 38 ++++++++
.../src/main/java/com/uber/jaeger/Tracer.java | 17 +++-
.../test/java/com/uber/jaeger/SpanTest.java | 94 +++++++++++++++++++
3 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/jaeger-core/src/main/java/com/uber/jaeger/Span.java b/jaeger-core/src/main/java/com/uber/jaeger/Span.java
index 1d6677d2d..ed778e64b 100644
--- a/jaeger-core/src/main/java/com/uber/jaeger/Span.java
+++ b/jaeger-core/src/main/java/com/uber/jaeger/Span.java
@@ -14,7 +14,10 @@
package com.uber.jaeger;
+import io.opentracing.log.Fields;
import io.opentracing.tag.Tags;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -228,6 +231,9 @@ public Span log(long timestampMicroseconds, Map fields) {
return this;
}
if (context.isSampled()) {
+ if (tracer.isExpandExceptionLogs()) {
+ fields = addExceptionLogs(fields);
+ }
if (logs == null) {
this.logs = new ArrayList();
}
@@ -257,4 +263,36 @@ public Span log(long timestampMicroseconds, String event) {
return this;
}
}
+
+ /**
+ * Creates logs related to logged exception
+ *
+ * @param fields map containing exception logs which are not present in fields
+ * @return logged fields
+ */
+ private static Map addExceptionLogs(Map fields) {
+ Object ex = fields.get(Fields.ERROR_OBJECT);
+ if (!(ex instanceof Throwable)) {
+ return fields;
+ }
+
+ Map errorFields = new HashMap(fields);
+ Throwable loggedException = (Throwable) ex;
+
+ if (fields.get(Fields.ERROR_KIND) == null) {
+ errorFields.put(Fields.ERROR_KIND, loggedException.getClass().getName());
+ }
+ if (fields.get(Fields.MESSAGE) == null) {
+ String message = loggedException.getMessage();
+ if (message != null) {
+ errorFields.put(Fields.MESSAGE, message);
+ }
+ }
+ if (fields.get(Fields.STACK) == null) {
+ StringWriter sw = new StringWriter();
+ loggedException.printStackTrace(new PrintWriter(sw));
+ errorFields.put(Fields.STACK, sw.toString());
+ }
+ return errorFields;
+ }
}
diff --git a/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java b/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
index de63d2277..68d6aaa02 100644
--- a/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
+++ b/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
@@ -69,6 +69,7 @@ public class Tracer implements io.opentracing.Tracer, Closeable {
private final boolean zipkinSharedRpcSpan;
private final ScopeManager scopeManager;
private final BaggageSetter baggageSetter;
+ private final boolean expandExceptionLogs;
private Tracer(
String serviceName,
@@ -80,7 +81,8 @@ private Tracer(
Map tags,
boolean zipkinSharedRpcSpan,
ScopeManager scopeManager,
- BaggageRestrictionManager baggageRestrictionManager) {
+ BaggageRestrictionManager baggageRestrictionManager,
+ boolean expandExceptionLogs) {
this.serviceName = serviceName;
this.reporter = reporter;
this.sampler = sampler;
@@ -90,6 +92,7 @@ private Tracer(
this.zipkinSharedRpcSpan = zipkinSharedRpcSpan;
this.scopeManager = scopeManager;
this.baggageSetter = new BaggageSetter(baggageRestrictionManager, metrics);
+ this.expandExceptionLogs = expandExceptionLogs;
this.version = loadVersion();
@@ -447,6 +450,7 @@ public static final class Builder {
private boolean zipkinSharedRpcSpan;
private ScopeManager scopeManager = new ThreadLocalScopeManager();
private BaggageRestrictionManager baggageRestrictionManager = new DefaultBaggageRestrictionManager();
+ private boolean expandExceptionLogs;
public Builder(String serviceName, Reporter reporter, Sampler sampler) {
if (serviceName == null || serviceName.trim().length() == 0) {
@@ -495,6 +499,11 @@ public Builder withZipkinSharedRpcSpan() {
return this;
}
+ public Builder withExpandExceptionLogs() {
+ this.expandExceptionLogs = true;
+ return this;
+ }
+
public Builder withMetrics(Metrics metrics) {
this.metrics = metrics;
return this;
@@ -529,7 +538,7 @@ public Builder withBaggageRestrictionManager(BaggageRestrictionManager baggageRe
public Tracer build() {
return new Tracer(this.serviceName, reporter, sampler, registry, clock, metrics, tags,
- zipkinSharedRpcSpan, scopeManager, baggageRestrictionManager);
+ zipkinSharedRpcSpan, scopeManager, baggageRestrictionManager, expandExceptionLogs);
}
}
@@ -588,4 +597,8 @@ String getHostName() {
SpanContext setBaggage(Span span, String key, String value) {
return baggageSetter.setBaggage(span, key, value);
}
+
+ boolean isExpandExceptionLogs() {
+ return this.expandExceptionLogs;
+ }
}
diff --git a/jaeger-core/src/test/java/com/uber/jaeger/SpanTest.java b/jaeger-core/src/test/java/com/uber/jaeger/SpanTest.java
index 9b7103834..8ee54cc63 100644
--- a/jaeger-core/src/test/java/com/uber/jaeger/SpanTest.java
+++ b/jaeger-core/src/test/java/com/uber/jaeger/SpanTest.java
@@ -31,9 +31,15 @@
import com.uber.jaeger.samplers.ConstSampler;
import com.uber.jaeger.utils.Clock;
import io.opentracing.References;
+import io.opentracing.log.Fields;
import io.opentracing.tag.Tags;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Before;
@@ -59,6 +65,7 @@ public void setUp() throws Exception {
.withStatsReporter(metricsReporter)
.withClock(clock)
.withBaggageRestrictionManager(new DefaultBaggageRestrictionManager())
+ .withExpandExceptionLogs()
.build();
span = (Span) tracer.buildSpan("some-operation").start();
}
@@ -346,4 +353,91 @@ public void testImmutableBaggage() {
baggageIter.next();
assertFalse(baggageIter.hasNext());
}
+
+ @Test
+ public void testExpandExceptionLogs() {
+ RuntimeException ex = new RuntimeException(new NullPointerException("npe"));
+ Map logs = new HashMap<>();
+ logs.put(Fields.ERROR_OBJECT, ex);
+ Span span = (Span)tracer.buildSpan("foo").start();
+ span.log(logs);
+
+ List logData = span.getLogs();
+ assertEquals(1, logData.size());
+ assertEquals(4, logData.get(0).getFields().size());
+
+ assertEquals(ex, logData.get(0).getFields().get(Fields.ERROR_OBJECT));
+ assertEquals(ex.getMessage(), logData.get(0).getFields().get(Fields.MESSAGE));
+ assertEquals(ex.getClass().getName(), logData.get(0).getFields().get(Fields.ERROR_KIND));
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ assertEquals(sw.toString(), logData.get(0).getFields().get(Fields.STACK));
+ }
+
+ @Test
+ public void testExpandExceptionLogsExpanded() {
+ RuntimeException ex = new RuntimeException(new NullPointerException("npe"));
+ Map logs = new HashMap<>();
+ logs.put(Fields.ERROR_OBJECT, ex);
+ logs.put(Fields.MESSAGE, ex.getMessage());
+ logs.put(Fields.ERROR_KIND, ex.getClass().getName());
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ logs.put(Fields.STACK, sw.toString());
+ Span span = (Span)tracer.buildSpan("foo").start();
+ span.log(logs);
+
+ List logData = span.getLogs();
+ assertEquals(1, logData.size());
+ assertEquals(4, logData.get(0).getFields().size());
+
+ assertEquals(ex, logData.get(0).getFields().get(Fields.ERROR_OBJECT));
+ assertEquals(ex.getMessage(), logData.get(0).getFields().get(Fields.MESSAGE));
+ assertEquals(ex.getClass().getName(), logData.get(0).getFields().get(Fields.ERROR_KIND));
+ assertEquals(sw.toString(), logData.get(0).getFields().get(Fields.STACK));
+ }
+
+ @Test
+ public void testExpandExceptionLogsLoggedNoException() {
+ Span span = (Span)tracer.buildSpan("foo").start();
+
+ Object object = new Object();
+ Map logs = new HashMap<>();
+ logs.put(Fields.ERROR_OBJECT, object);
+ span.log(logs);
+
+ List logData = span.getLogs();
+ assertEquals(1, logData.size());
+ assertEquals(1, logData.get(0).getFields().size());
+ assertEquals(object, logData.get(0).getFields().get(Fields.ERROR_OBJECT));
+ }
+
+ @Test
+ public void testNoExpandExceptionLogs() {
+ Tracer tracer = new Tracer.Builder("fo", reporter, new ConstSampler(true))
+ .build();
+
+ Span span = (Span)tracer.buildSpan("foo").start();
+
+ RuntimeException ex = new RuntimeException();
+ Map logs = new HashMap<>();
+ logs.put(Fields.ERROR_OBJECT, ex);
+ span.log(logs);
+
+ List logData = span.getLogs();
+ assertEquals(1, logData.size());
+ assertEquals(1, logData.get(0).getFields().size());
+ assertEquals(ex, logData.get(0).getFields().get(Fields.ERROR_OBJECT));
+ }
+
+ @Test
+ public void testSpanNotSampled() {
+ Tracer tracer = new Tracer.Builder("fo", reporter, new ConstSampler(false))
+ .build();
+ io.opentracing.Span foo = tracer.buildSpan("foo")
+ .start();
+ foo.log(Collections.emptyMap())
+ .finish();
+ assertEquals(0, reporter.getSpans().size());
+ }
}