Skip to content

Commit 4d5f662

Browse files
authored
fix: handle the semantics of error related attributes for considering error span (#169)
* fix: handle the issue of error metrics are same as calls * fix: handle the otel tags for considering error span * chore: correct the comments for exception * fix: unit tests in enricher code * fixed failing tests * refactor: combing stack_trace and exception related attributes to same function
1 parent 4071f5e commit 4d5f662

5 files changed

Lines changed: 91 additions & 35 deletions

File tree

hypertrace-trace-enricher/hypertrace-trace-enricher-impl/src/main/java/org/hypertrace/traceenricher/enrichment/enrichers/ErrorsAndExceptionsEnricher.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void enrichEvent(StructuredTrace trace, Event event) {
4646

4747
private void enrichExceptionDetails(Event event) {
4848
// Figure out if event has any exceptions in it.
49-
boolean hasException = ErrorSemanticConventionUtils.checkForErrorStackTrace(event);
49+
boolean hasException = ErrorSemanticConventionUtils.checkForException(event);
5050

5151
if (hasException) {
5252
if (event.getMetrics() == null) {
@@ -66,6 +66,7 @@ private void enrichErrorDetails(Event event) {
6666
// Figure out if there are any errors in the event.
6767
boolean hasError =
6868
ErrorSemanticConventionUtils.checkForError(event)
69+
|| ErrorSemanticConventionUtils.checkForException(event)
6970
|| Constants.getEnrichedSpanConstant(ApiStatus.API_STATUS_FAIL)
7071
.equals(EnrichedSpanUtils.getStatus(event));
7172

hypertrace-trace-enricher/hypertrace-trace-enricher-impl/src/test/java/org/hypertrace/traceenricher/enrichment/enrichers/ErrorsAndExceptionsEnricherTest.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ public void errorExists() {
8484
Event e1 = createMockEvent();
8585
Map<String, AttributeValue> attributeValueMap = e1.getAttributes().getAttributeMap();
8686
attributeValueMap.put(
87-
Constants.getRawSpanConstant(Error.ERROR_ERROR),
88-
AttributeValueCreator.create("test error"));
87+
Constants.getRawSpanConstant(Error.ERROR_ERROR), AttributeValueCreator.create(true));
8988
enricher.enrichEvent(null, e1);
9089
Assertions.assertEquals(
9190
1.0d,
@@ -175,7 +174,7 @@ public void errorExists() {
175174
.getValue());
176175
enricher.enrichTrace(trace);
177176
Assertions.assertEquals(
178-
4.0d,
177+
6.0d,
179178
trace
180179
.getMetrics()
181180
.getMetricMap()
@@ -184,7 +183,7 @@ public void errorExists() {
184183
ErrorMetrics.ERROR_METRICS_TOTAL_SPANS_WITH_ERRORS))
185184
.getValue());
186185
Assertions.assertEquals(
187-
2.0d,
186+
3.0d,
188187
trace
189188
.getMetrics()
190189
.getMetricMap()
@@ -211,7 +210,7 @@ public void errorExists() {
211210
Constants.getEnrichedSpanConstant(BoundaryTypeValue.BOUNDARY_TYPE_VALUE_ENTRY)));
212211
enricher.enrichTrace(trace);
213212
Assertions.assertEquals(
214-
4.0d,
213+
6.0d,
215214
trace
216215
.getMetrics()
217216
.getMetricMap()
@@ -220,7 +219,7 @@ public void errorExists() {
220219
ErrorMetrics.ERROR_METRICS_TOTAL_SPANS_WITH_ERRORS))
221220
.getValue());
222221
Assertions.assertEquals(
223-
2.0d,
222+
3.0d,
224223
trace
225224
.getMetrics()
226225
.getMetricMap()

semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/error/ErrorSemanticConventionUtils.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,33 @@ public class ErrorSemanticConventionUtils {
1818
OTelErrorSemanticConventions.EXCEPTION_MESSAGE.getValue();
1919
private static final String OTEL_EXCEPTION_STACK_TRACE =
2020
OTelErrorSemanticConventions.EXCEPTION_STACKTRACE.getValue();
21+
private static final String OTEL_STATUS_CODE =
22+
OTelErrorSemanticConventions.STATUS_CODE.getValue();
23+
private static final String OTEL_STATUS_CODE_ERROR_VALUE =
24+
OTelErrorSemanticConventions.STATUS_CODE_ERROR_VALUE.getValue();
25+
private static final String OTEL_STATUS_CODE_UNSET_VALUE =
26+
OTelErrorSemanticConventions.STATUS_CODE_UNSET_VALUE.getValue();
27+
28+
private static final String OT_SPAN_TAG_ERROR =
29+
RawSpanConstants.getValue(OTSpanTag.OT_SPAN_TAG_ERROR);
2130

2231
private static final List<String> EXCEPTION_ATTRIBUTES =
23-
List.of(
24-
RawSpanConstants.getValue(Error.ERROR_ERROR),
25-
RawSpanConstants.getValue(OTSpanTag.OT_SPAN_TAG_ERROR),
26-
OTEL_EXCEPTION_TYPE,
27-
OTEL_EXCEPTION_MESSAGE);
32+
List.of(OTEL_EXCEPTION_TYPE, OTEL_EXCEPTION_MESSAGE);
2833

2934
private static final List<String> EXCEPTION_STACK_TRACE_ATTRIBUTES =
3035
List.of(RawSpanConstants.getValue(Error.ERROR_STACK_TRACE), OTEL_EXCEPTION_STACK_TRACE);
3136

32-
public static List<String> getAttributeKeysForException() {
33-
return EXCEPTION_ATTRIBUTES;
34-
}
35-
3637
/**
3738
* This maps to {@link ErrorMetrics#ERROR_METRICS_ERROR_COUNT} enriched constant
3839
*
3940
* @param event object encapsulating span data
4041
* @return check for error in the span event
4142
*/
4243
public static boolean checkForError(Event event) {
43-
return EXCEPTION_ATTRIBUTES.stream()
44-
.anyMatch(v -> SpanAttributeUtils.containsAttributeKey(event, v));
44+
return SpanAttributeUtils.getBooleanAttribute(event, OT_SPAN_TAG_ERROR)
45+
|| OTEL_STATUS_CODE_ERROR_VALUE.equals(
46+
SpanAttributeUtils.getStringAttributeWithDefault(
47+
event, OTEL_STATUS_CODE, OTEL_STATUS_CODE_UNSET_VALUE));
4548
}
4649

4750
/**
@@ -50,8 +53,10 @@ public static boolean checkForError(Event event) {
5053
* @param event object encapsulating span data
5154
* @return check for exception in the span event
5255
*/
53-
public static boolean checkForErrorStackTrace(Event event) {
54-
return EXCEPTION_STACK_TRACE_ATTRIBUTES.stream()
55-
.anyMatch(v -> SpanAttributeUtils.containsAttributeKey(event, v));
56+
public static boolean checkForException(Event event) {
57+
return EXCEPTION_ATTRIBUTES.stream()
58+
.anyMatch(v -> SpanAttributeUtils.containsAttributeKey(event, v))
59+
|| EXCEPTION_STACK_TRACE_ATTRIBUTES.stream()
60+
.anyMatch(v -> SpanAttributeUtils.containsAttributeKey(event, v));
5661
}
5762
}

semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/error/ErrorSemanticConventionUtilsTest.java

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,56 +25,103 @@ public void testCheckForError() {
2525
SemanticConventionTestUtil.buildAttributes(
2626
Map.of(
2727
RawSpanConstants.getValue(Error.ERROR_ERROR),
28-
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
28+
SemanticConventionTestUtil.buildAttributeValue("false")));
2929
when(e.getAttributes()).thenReturn(attributes);
3030
boolean v = ErrorSemanticConventionUtils.checkForError(e);
31-
assertTrue(v);
31+
assertFalse(v);
32+
33+
attributes =
34+
SemanticConventionTestUtil.buildAttributes(
35+
Map.of(
36+
RawSpanConstants.getValue(Error.ERROR_ERROR),
37+
SemanticConventionTestUtil.buildAttributeValue("false")));
38+
when(e.getAttributes()).thenReturn(attributes);
39+
v = ErrorSemanticConventionUtils.checkForError(e);
40+
assertFalse(v);
3241

3342
attributes =
3443
SemanticConventionTestUtil.buildAttributes(
3544
Map.of(
3645
RawSpanConstants.getValue(OTSpanTag.OT_SPAN_TAG_ERROR),
37-
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
46+
SemanticConventionTestUtil.buildAttributeValue("true")));
3847
when(e.getAttributes()).thenReturn(attributes);
3948
v = ErrorSemanticConventionUtils.checkForError(e);
4049
assertTrue(v);
4150

51+
// check for UNSET, OK
4252
attributes =
4353
SemanticConventionTestUtil.buildAttributes(
4454
Map.of(
45-
OTelErrorSemanticConventions.EXCEPTION_TYPE.getValue(),
46-
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
55+
OTelErrorSemanticConventions.STATUS_CODE.getValue(),
56+
SemanticConventionTestUtil.buildAttributeValue(
57+
OTelErrorSemanticConventions.STATUS_CODE_UNSET_VALUE.getValue())));
4758
when(e.getAttributes()).thenReturn(attributes);
4859
v = ErrorSemanticConventionUtils.checkForError(e);
49-
assertTrue(v);
60+
assertFalse(v);
5061

5162
attributes =
5263
SemanticConventionTestUtil.buildAttributes(
5364
Map.of(
54-
OTelErrorSemanticConventions.EXCEPTION_MESSAGE.getValue(),
55-
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
65+
OTelErrorSemanticConventions.STATUS_CODE.getValue(),
66+
SemanticConventionTestUtil.buildAttributeValue(
67+
OTelErrorSemanticConventions.STATUS_CODE_OK_VALUE.getValue())));
5668
when(e.getAttributes()).thenReturn(attributes);
5769
v = ErrorSemanticConventionUtils.checkForError(e);
58-
assertTrue(v);
70+
assertFalse(v);
5971

72+
// check for ERROR
6073
attributes =
6174
SemanticConventionTestUtil.buildAttributes(
62-
Map.of("other_error", SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
75+
Map.of(
76+
OTelErrorSemanticConventions.STATUS_CODE.getValue(),
77+
SemanticConventionTestUtil.buildAttributeValue(
78+
OTelErrorSemanticConventions.STATUS_CODE_ERROR_VALUE.getValue())));
79+
when(e.getAttributes()).thenReturn(attributes);
80+
v = ErrorSemanticConventionUtils.checkForError(e);
81+
assertTrue(v);
82+
83+
// check for both the attributes are empty
84+
attributes = SemanticConventionTestUtil.buildAttributes(Map.of());
6385
when(e.getAttributes()).thenReturn(attributes);
6486
v = ErrorSemanticConventionUtils.checkForError(e);
6587
assertFalse(v);
6688
}
6789

6890
@Test
69-
public void testCheckForErrorStacktrace() {
91+
public void testCheckForException() {
7092
Event e = mock(Event.class);
7193
Attributes attributes =
94+
SemanticConventionTestUtil.buildAttributes(
95+
Map.of(
96+
OTelErrorSemanticConventions.EXCEPTION_TYPE.getValue(),
97+
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
98+
when(e.getAttributes()).thenReturn(attributes);
99+
boolean v = ErrorSemanticConventionUtils.checkForException(e);
100+
assertTrue(v);
101+
102+
attributes =
103+
SemanticConventionTestUtil.buildAttributes(
104+
Map.of(
105+
OTelErrorSemanticConventions.EXCEPTION_MESSAGE.getValue(),
106+
SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
107+
when(e.getAttributes()).thenReturn(attributes);
108+
v = ErrorSemanticConventionUtils.checkForException(e);
109+
assertTrue(v);
110+
111+
attributes =
112+
SemanticConventionTestUtil.buildAttributes(
113+
Map.of("other_error", SemanticConventionTestUtil.buildAttributeValue("xyzerror")));
114+
when(e.getAttributes()).thenReturn(attributes);
115+
v = ErrorSemanticConventionUtils.checkForException(e);
116+
assertFalse(v);
117+
118+
attributes =
72119
SemanticConventionTestUtil.buildAttributes(
73120
Map.of(
74121
RawSpanConstants.getValue(Error.ERROR_STACK_TRACE),
75122
SemanticConventionTestUtil.buildAttributeValue("org.abc.etc...")));
76123
when(e.getAttributes()).thenReturn(attributes);
77-
boolean v = ErrorSemanticConventionUtils.checkForErrorStackTrace(e);
124+
v = ErrorSemanticConventionUtils.checkForException(e);
78125
assertTrue(v);
79126

80127
attributes =
@@ -83,7 +130,7 @@ public void testCheckForErrorStacktrace() {
83130
OTelErrorSemanticConventions.EXCEPTION_STACKTRACE.getValue(),
84131
SemanticConventionTestUtil.buildAttributeValue("org.abc.etc...")));
85132
when(e.getAttributes()).thenReturn(attributes);
86-
v = ErrorSemanticConventionUtils.checkForErrorStackTrace(e);
133+
v = ErrorSemanticConventionUtils.checkForException(e);
87134
assertTrue(v);
88135
}
89136
}

span-normalizer/span-normalizer-constants/src/main/java/org/hypertrace/core/semantic/convention/constants/error/OTelErrorSemanticConventions.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
public enum OTelErrorSemanticConventions {
55
EXCEPTION_TYPE("exception.type"),
66
EXCEPTION_MESSAGE("exception.message"),
7-
EXCEPTION_STACKTRACE("exception.stacktrace");
7+
EXCEPTION_STACKTRACE("exception.stacktrace"),
8+
STATUS_CODE("status.code"),
9+
STATUS_CODE_UNSET_VALUE("0"),
10+
STATUS_CODE_OK_VALUE("1"),
11+
STATUS_CODE_ERROR_VALUE("2");
812

913
private final String value;
1014

0 commit comments

Comments
 (0)