Skip to content

Commit 05a6a27

Browse files
refactor: add spaces scaffolding (#90)
* refactor: add spaces scaffolding hypertrace/hypertrace#142 * test: add a couple space id tests * refactor: move space id attribute to java constant * style: remove unused import
1 parent 31b027a commit 05a6a27

File tree

21 files changed

+177
-34
lines changed

21 files changed

+177
-34
lines changed

hypertrace-trace-enricher/enriched-span-constants/src/main/java/org/hypertrace/traceenricher/enrichedspan/constants/EnrichedSpanConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
public class EnrichedSpanConstants {
99
private static final Logger LOGGER = LoggerFactory.getLogger(EnrichedSpanConstants.class);
1010

11+
public static final String SPACE_IDS_ATTRIBUTE = "SPACE_IDS";
12+
1113
/**
1214
* Returns the constant value for the given Enum.
1315
*

hypertrace-trace-enricher/enriched-span-constants/src/main/java/org/hypertrace/traceenricher/enrichedspan/constants/utils/EnrichedSpanUtils.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.annotations.VisibleForTesting;
44
import com.google.common.collect.ImmutableList;
55
import java.nio.ByteBuffer;
6+
import java.util.Collections;
67
import java.util.List;
78
import java.util.Map;
89
import java.util.Optional;
@@ -12,7 +13,6 @@
1213
import org.hypertrace.core.datamodel.shared.SpanAttributeUtils;
1314
import org.hypertrace.core.semantic.convention.constants.http.OTelHttpSemanticConventions;
1415
import org.hypertrace.core.span.constants.RawSpanConstants;
15-
import org.hypertrace.core.span.constants.v1.Docker;
1616
import org.hypertrace.core.span.constants.v1.TracerAttribute;
1717
import org.hypertrace.entity.constants.v1.ApiAttribute;
1818
import org.hypertrace.entity.constants.v1.BackendAttribute;
@@ -27,17 +27,16 @@
2727
import org.hypertrace.traceenricher.enrichedspan.constants.v1.Protocol;
2828

2929
/**
30-
* Utility class to easily read named attributes from an enriched span. This is equivalent of
31-
* an enriched span POJO.
30+
* Utility class to easily read named attributes from an enriched span. This is equivalent of an
31+
* enriched span POJO.
3232
*/
3333
public class EnrichedSpanUtils {
3434
private static final String SERVICE_ID_ATTR =
3535
EntityConstants.getValue(ServiceAttribute.SERVICE_ATTRIBUTE_ID);
3636
private static final String SERVICE_NAME_ATTR =
3737
EntityConstants.getValue(ServiceAttribute.SERVICE_ATTRIBUTE_NAME);
3838

39-
private static final String API_ID_ATTR =
40-
EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_ID);
39+
private static final String API_ID_ATTR = EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_ID);
4140
private static final String API_URL_PATTERN_ATTR =
4241
EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_URL_PATTERN);
4342
private static final String API_NAME_ATTR =
@@ -78,18 +77,26 @@ public class EnrichedSpanUtils {
7877
private static final String USER_AGENT =
7978
RawSpanConstants.getValue(org.hypertrace.core.span.constants.v1.Http.HTTP_USER_DOT_AGENT);
8079
private static final String USER_AGENT_UNDERSCORE =
81-
RawSpanConstants.getValue(org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_WITH_UNDERSCORE);
80+
RawSpanConstants.getValue(
81+
org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_WITH_UNDERSCORE);
8282
private static final String USER_AGENT_DASH =
83-
RawSpanConstants.getValue(org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_WITH_DASH);
83+
RawSpanConstants.getValue(
84+
org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_WITH_DASH);
8485
private static final String USER_AGENT_REQUEST_HEADER =
85-
RawSpanConstants.getValue(org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_REQUEST_HEADER);
86-
private static final String OTEL_HTTP_USER_AGENT = OTelHttpSemanticConventions.HTTP_USER_AGENT.getValue();
86+
RawSpanConstants.getValue(
87+
org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_REQUEST_HEADER);
88+
private static final String OTEL_HTTP_USER_AGENT =
89+
OTelHttpSemanticConventions.HTTP_USER_AGENT.getValue();
8790

8891
@VisibleForTesting
8992
static final List<String> USER_AGENT_ATTRIBUTES =
9093
ImmutableList.of(
91-
USER_AGENT, USER_AGENT_UNDERSCORE, USER_AGENT_DASH,
92-
USER_AGENT_REQUEST_HEADER, HTTP_USER_AGENT, OTEL_HTTP_USER_AGENT);
94+
USER_AGENT,
95+
USER_AGENT_UNDERSCORE,
96+
USER_AGENT_DASH,
97+
USER_AGENT_REQUEST_HEADER,
98+
HTTP_USER_AGENT,
99+
OTEL_HTTP_USER_AGENT);
93100

94101
@Nullable
95102
private static String getStringAttribute(Event event, String attributeKey) {
@@ -174,8 +181,8 @@ public static String getApiDiscoveryState(Event event) {
174181
}
175182

176183
public static boolean isExternalApi(Event e) {
177-
return SpanAttributeUtils.getBooleanAttribute(e,
178-
EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_IS_EXTERNAL_API));
184+
return SpanAttributeUtils.getBooleanAttribute(
185+
e, EntityConstants.getValue(ApiAttribute.API_ATTRIBUTE_IS_EXTERNAL_API));
179186
}
180187

181188
public static String getSpanType(Event event) {
@@ -191,39 +198,33 @@ public static String getApiBoundaryType(Event event) {
191198
return getStringAttribute(event, API_BOUNDARY_TYPE_ATTR);
192199
}
193200

194-
195-
/**
196-
* Find the First Span (Entrance Span) of the Api Trace and return its id
197-
*/
201+
/** Find the First Span (Entrance Span) of the Api Trace and return its id */
198202
@Nullable
199203
public static ByteBuffer getApiEntrySpanId(
200-
Event event,
201-
Map<ByteBuffer, Event> idToEvent,
202-
Map<ByteBuffer, ByteBuffer> childToParent) {
204+
Event event, Map<ByteBuffer, Event> idToEvent, Map<ByteBuffer, ByteBuffer> childToParent) {
203205
Event entryApiEvent = getApiEntrySpan(event, idToEvent, childToParent);
204206
if (entryApiEvent != null) {
205207
return entryApiEvent.getEventId();
206208
}
207209
return null;
208210
}
209211

210-
/**
211-
* Helper method to find and entryApiEvent by iterate parent-child chain.
212-
*/
212+
/** Helper method to find and entryApiEvent by iterate parent-child chain. */
213213
@Nullable
214-
public static Event getApiEntrySpan(Event event,
215-
Map<ByteBuffer, Event> idToEvent,
216-
Map<ByteBuffer, ByteBuffer> childToParent) {
214+
public static Event getApiEntrySpan(
215+
Event event, Map<ByteBuffer, Event> idToEvent, Map<ByteBuffer, ByteBuffer> childToParent) {
217216
String apiBoundary = getApiBoundaryType(event);
218-
if (EnrichedSpanConstants.getValue(BoundaryTypeValue.BOUNDARY_TYPE_VALUE_ENTRY).equals(apiBoundary)) {
217+
if (EnrichedSpanConstants.getValue(BoundaryTypeValue.BOUNDARY_TYPE_VALUE_ENTRY)
218+
.equals(apiBoundary)) {
219219
// if current span itself is an api entry span, return same.
220220
return event;
221221
} else {
222222
// current span is not an api entry span, find an ancestor who is an api entry span
223223
Event parentEvent = idToEvent.get(childToParent.get(event.getEventId()));
224224
while (parentEvent != null) {
225225
apiBoundary = getApiBoundaryType(parentEvent);
226-
if (EnrichedSpanConstants.getValue(BoundaryTypeValue.BOUNDARY_TYPE_VALUE_ENTRY).equals(apiBoundary)) {
226+
if (EnrichedSpanConstants.getValue(BoundaryTypeValue.BOUNDARY_TYPE_VALUE_ENTRY)
227+
.equals(apiBoundary)) {
227228
return parentEvent;
228229
}
229230
parentEvent = idToEvent.get(childToParent.get(parentEvent.getEventId()));
@@ -352,4 +353,11 @@ public static Optional<Integer> getResponseSize(Event event) {
352353

353354
return Optional.empty();
354355
}
356+
357+
public static List<String> getSpaceIds(Event event) {
358+
return Optional.ofNullable(
359+
SpanAttributeUtils.getAttributeValue(event, EnrichedSpanConstants.SPACE_IDS_ATTRIBUTE))
360+
.map(AttributeValue::getValueList)
361+
.orElseGet(Collections::emptyList);
362+
}
355363
}

hypertrace-trace-enricher/enriched-span-constants/src/test/java/org/hypertrace/traceenricher/enrichedspan/constants/utils/EnrichedSpanUtilsTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.hypertrace.traceenricher.enrichedspan.constants.utils;
22

3+
import static java.util.Collections.emptyList;
34
import static org.junit.jupiter.api.Assertions.assertEquals;
45
import static org.junit.jupiter.api.Assertions.assertFalse;
56
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -395,4 +396,25 @@ public void getResponseSize_emptyProtocol() {
395396
Optional<Integer> requestSize = EnrichedSpanUtils.getResponseSize(e);
396397
assertTrue(requestSize.isEmpty());
397398
}
399+
400+
@Test
401+
public void testGetSpaceIds_empty() {
402+
Event e = mock(Event.class);
403+
404+
List<String> spaceIds = EnrichedSpanUtils.getSpaceIds(e);
405+
assertEquals(emptyList(), spaceIds);
406+
}
407+
408+
@Test
409+
public void testGetSpaceIds_withData() {
410+
List<String> spaceIds = List.of("space1", "space2");
411+
Event e = mock(Event.class);
412+
when(e.getEnrichedAttributes())
413+
.thenReturn(
414+
Attributes.newBuilder()
415+
.setAttributeMap(Map.of("SPACE_IDS", AttributeValueCreator.create(spaceIds)))
416+
.build());
417+
418+
assertEquals(spaceIds, EnrichedSpanUtils.getSpaceIds(e));
419+
}
398420
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.hypertrace.traceenricher.enrichment.enrichers;
2+
3+
import static org.hypertrace.traceenricher.enrichedspan.constants.EnrichedSpanConstants.SPACE_IDS_ATTRIBUTE;
4+
5+
import java.util.Collection;
6+
import java.util.Collections;
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
import org.hypertrace.core.datamodel.Event;
10+
import org.hypertrace.core.datamodel.StructuredTrace;
11+
import org.hypertrace.core.datamodel.shared.trace.AttributeValueCreator;
12+
import org.hypertrace.traceenricher.enrichedspan.constants.utils.EnrichedSpanUtils;
13+
import org.hypertrace.traceenricher.enrichment.AbstractTraceEnricher;
14+
15+
public class SpaceEnricher extends AbstractTraceEnricher {
16+
17+
@Override
18+
public void enrichEvent(StructuredTrace trace, Event event) {
19+
// TODO space generation will go here, once implemented
20+
addEnrichedAttribute(
21+
event, SPACE_IDS_ATTRIBUTE, AttributeValueCreator.create(Collections.emptyList()));
22+
}
23+
24+
@Override
25+
public void enrichTrace(StructuredTrace trace) {
26+
List<String> includedSpaceIds =
27+
trace.getEventList().stream()
28+
.map(EnrichedSpanUtils::getSpaceIds)
29+
.flatMap(Collection::stream)
30+
.distinct()
31+
.collect(Collectors.toList());
32+
33+
trace
34+
.getAttributes()
35+
.getAttributeMap()
36+
.put(SPACE_IDS_ATTRIBUTE, AttributeValueCreator.create(includedSpaceIds));
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.hypertrace.traceenricher.enrichment.enrichers;
2+
3+
import static java.util.Collections.emptyList;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
import org.hypertrace.core.datamodel.Event;
7+
import org.hypertrace.core.datamodel.StructuredTrace;
8+
import org.hypertrace.core.datamodel.shared.trace.AttributeValueCreator;
9+
import org.junit.jupiter.api.Test;
10+
11+
class SpaceEnricherTest extends AbstractAttributeEnricherTest {
12+
13+
private final SpaceEnricher enricher = new SpaceEnricher();
14+
15+
@Test
16+
void testEnrichEvent() {
17+
Event targetEvent = createMockEvent();
18+
enricher.enrichEvent(createMockStructuredTrace(), targetEvent);
19+
20+
assertEquals(
21+
AttributeValueCreator.create(emptyList()),
22+
targetEvent.getEnrichedAttributes().getAttributeMap().get("SPACE_IDS"));
23+
}
24+
25+
@Test
26+
void testEnrichTrace() {
27+
StructuredTrace targetTrace = createMockStructuredTrace();
28+
enricher.enrichTrace(targetTrace);
29+
30+
assertEquals(
31+
AttributeValueCreator.create(emptyList()),
32+
targetTrace.getAttributes().getAttributeMap().get("SPACE_IDS"));
33+
}
34+
}

hypertrace-trace-enricher/hypertrace-trace-enricher/src/main/resources/configs/common/application.conf

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ kafka.streams.config = {
2424
}
2525

2626
enricher {
27-
names = ["SpanTypeAttributeEnricher", "ApiStatusEnricher", "EndpointEnricher", "TransactionNameEnricher", "ApiBoundaryTypeAttributeEnricher", "ErrorsAndExceptionsEnricher", "BackendEntityEnricher", "HttpAttributeEnricher", "DefaultServiceEntityEnricher", "UserAgentSpanEnricher", "EntitySpanEnricher"]
27+
names = ["SpanTypeAttributeEnricher", "ApiStatusEnricher", "EndpointEnricher", "TransactionNameEnricher", "ApiBoundaryTypeAttributeEnricher", "ErrorsAndExceptionsEnricher", "BackendEntityEnricher", "HttpAttributeEnricher", "DefaultServiceEntityEnricher", "UserAgentSpanEnricher", "SpaceEnricher", "EntitySpanEnricher"]
2828

2929
DefaultServiceEntityEnricher {
3030
class = "org.hypertrace.traceenricher.enrichment.enrichers.DefaultServiceEntityEnricher"
@@ -105,6 +105,10 @@ enricher {
105105
port = ${?ATTRIBUTE_SERVICE_PORT_CONFIG}
106106
}
107107
}
108+
109+
SpaceEnricher {
110+
class = "org.hypertrace.traceenricher.enrichment.enrichers.SpaceEnricher"
111+
}
108112
}
109113

110114
logger {

hypertrace-view-generator/hypertrace-view-creator/src/main/resources/configs/backend-entity-view/application.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pinot.controllerHost = pinot-controller
1717
pinot.controllerPort = 9000
1818
pinot.timeColumn = start_time_millis
1919
pinot.timeUnit = MILLISECONDS
20-
pinot.dimensionColumns = [tenant_id, trace_id, span_id, backend_id, backend_host, backend_port, backend_protocol, backend_path, span_kind, exception_count, error_count, duration_millis, end_time_millis, num_calls, backend_name, backend_trace_id, display_name, tags__KEYS, tags__VALUES, status_code, status_message, status, caller_service_id, caller_api_id]
20+
pinot.dimensionColumns = [tenant_id, trace_id, span_id, backend_id, backend_host, backend_port, backend_protocol, backend_path, span_kind, exception_count, error_count, duration_millis, end_time_millis, num_calls, backend_name, backend_trace_id, display_name, tags__KEYS, tags__VALUES, status_code, status_message, status, caller_service_id, caller_api_id, space_ids]
2121
pinot.columnsMaxLength={}
2222
pinot.metricColumns = []
2323
pinot.invertedIndexColumns= []

hypertrace-view-generator/hypertrace-view-creator/src/main/resources/configs/raw-service-view/application.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pinot.controllerPort = 9000
1818
pinot.timeColumn = start_time_millis
1919
pinot.timeUnit = MILLISECONDS
2020
# todo: Add Attributes and Metrics after adding map type value
21-
pinot.dimensionColumns = [tenant_id, span_kind, error_count, exception_count, duration_millis, end_time_millis, api_name, service_name, span_id, trace_id, protocol_name, status_code, service_id, api_id, num_calls, api_discovery_state]
21+
pinot.dimensionColumns = [tenant_id, span_kind, error_count, exception_count, duration_millis, end_time_millis, api_name, service_name, span_id, trace_id, protocol_name, status_code, service_id, api_id, num_calls, api_discovery_state, space_ids]
2222
pinot.columnsMaxLength={}
2323
pinot.metricColumns = []
2424
pinot.invertedIndexColumns= []

hypertrace-view-generator/hypertrace-view-creator/src/main/resources/configs/raw-trace-view/application.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pinot.controllerHost = pinot-controller
1717
pinot.controllerPort = 9000
1818
pinot.timeColumn = start_time_millis
1919
pinot.timeUnit = MILLISECONDS
20-
pinot.dimensionColumns = [tenant_id, duration_millis, start_time_millis, end_time_millis, services, transaction_name, trace_id, num_spans, num_services]
20+
pinot.dimensionColumns = [tenant_id, duration_millis, start_time_millis, end_time_millis, services, transaction_name, trace_id, num_spans, num_services, space_ids]
2121
pinot.rangeIndexColumns = [start_time_millis]
2222
pinot.bloomFilterColumns = []
2323
pinot.noDictionaryColumns = []

hypertrace-view-generator/hypertrace-view-creator/src/main/resources/configs/service-call-view/application.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pinot.controllerPort = 9000
1818
pinot.timeColumn = start_time_millis
1919
pinot.timeUnit = MILLISECONDS
2020
# todo: Add Attributes and Metrics after adding map type value
21-
pinot.dimensionColumns = [tenant_id, end_time_millis, client_event_id, server_event_id, caller_service_id_str, caller_service, caller_api_id_str, caller_api, callee_service_id_str, callee_service, callee_api_id_str, callee_api, trace_id, transaction_name, request_url, request_method, protocol_name, response_status_code, callee_backend_id, callee_backend_name]
21+
pinot.dimensionColumns = [tenant_id, end_time_millis, client_event_id, server_event_id, caller_service_id_str, caller_service, caller_api_id_str, caller_api, callee_service_id_str, callee_service, callee_api_id_str, callee_api, trace_id, transaction_name, request_url, request_method, protocol_name, response_status_code, callee_backend_id, callee_backend_name, callee_space_ids, caller_space_ids]
2222
pinot.columnsMaxLength={}
2323
pinot.metricColumns = [duration_millis, error_count, exception_count, num_calls]
2424
pinot.invertedIndexColumns= []

0 commit comments

Comments
 (0)