Search in sources :

Example 6 with StructuredTrace

use of org.hypertrace.core.datamodel.StructuredTrace in project hypertrace-ingester by hypertrace.

the class StructuredTraceGraphBuilderTest method testBuildGraph.

@Test
void testBuildGraph() {
    Entity entity = mock(Entity.class);
    Event parent = mock(Event.class);
    Event child = mock(Event.class);
    Edge eventEdge = mock(Edge.class);
    StructuredTrace underTestTrace = mock(StructuredTrace.class);
    when(underTestTrace.getCustomerId()).thenReturn("__defaultTenant");
    when(underTestTrace.getTraceId()).thenReturn(ByteBuffer.wrap("2ebbc19b6428510f".getBytes()));
    when(underTestTrace.getEntityList()).thenReturn(List.of(entity));
    when(underTestTrace.getEventList()).thenReturn(List.of(parent, child));
    when(underTestTrace.getEntityEdgeList()).thenReturn(List.of());
    when(underTestTrace.getEntityEventEdgeList()).thenReturn(List.of());
    when(underTestTrace.getEventEdgeList()).thenReturn(List.of(eventEdge));
    try (MockedStatic<StructuredTrace> builderMockedStatic = mockStatic(StructuredTrace.class)) {
        StructuredTrace.Builder builder = mock(StructuredTrace.Builder.class);
        when(builder.build()).thenReturn(underTestTrace);
        builderMockedStatic.when(() -> StructuredTrace.newBuilder(underTestTrace)).thenReturn(builder);
        try (MockedConstruction<StructuredTraceGraph> mocked = mockConstruction(StructuredTraceGraph.class)) {
            // calls first time
            StructuredTraceGraph actual = StructuredTraceGraphBuilder.buildGraph(underTestTrace);
            // calls second time, this time it returns from cache
            StructuredTraceGraph cached = StructuredTraceGraphBuilder.buildGraph(underTestTrace);
            Assertions.assertEquals(actual, cached);
        }
    }
}
Also used : Entity(org.hypertrace.core.datamodel.Entity) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Event(org.hypertrace.core.datamodel.Event) StructuredTraceGraph(org.hypertrace.core.datamodel.shared.StructuredTraceGraph) Edge(org.hypertrace.core.datamodel.Edge) Test(org.junit.jupiter.api.Test)

Example 7 with StructuredTrace

use of org.hypertrace.core.datamodel.StructuredTrace in project hypertrace-ingester by hypertrace.

the class SpanNormalizerTest method whenByPassedExpectStructuredTraceToBeOutput.

@Test
@SetEnvironmentVariable(key = "SERVICE_NAME", value = "span-normalizer")
public void whenByPassedExpectStructuredTraceToBeOutput() {
    Config config = ConfigFactory.parseURL(getClass().getClassLoader().getResource("configs/span-normalizer/application.conf"));
    Map<String, Object> mergedProps = new HashMap<>();
    underTest.getBaseStreamsConfig().forEach(mergedProps::put);
    underTest.getStreamsConfig(config).forEach(mergedProps::put);
    mergedProps.put(SpanNormalizerConstants.SPAN_NORMALIZER_JOB_CONFIG, config);
    StreamsBuilder streamsBuilder = underTest.buildTopology(mergedProps, new StreamsBuilder(), new HashMap<>());
    Properties props = new Properties();
    mergedProps.forEach(props::put);
    TopologyTestDriver td = new TopologyTestDriver(streamsBuilder.build(), props);
    TestInputTopic<byte[], Span> inputTopic = td.createInputTopic(config.getString(SpanNormalizerConstants.INPUT_TOPIC_CONFIG_KEY), Serdes.ByteArray().serializer(), new JaegerSpanSerde().serializer());
    Serde<RawSpan> rawSpanSerde = new AvroSerde<>();
    rawSpanSerde.configure(Map.of(), false);
    Serde<StructuredTrace> structuredTraceSerde = new AvroSerde<>();
    structuredTraceSerde.configure(Map.of(), false);
    Serde<TraceIdentity> spanIdentitySerde = new AvroSerde<>();
    spanIdentitySerde.configure(Map.of(), true);
    TestOutputTopic outputTopic = td.createOutputTopic(config.getString(SpanNormalizerConstants.OUTPUT_TOPIC_CONFIG_KEY), spanIdentitySerde.deserializer(), rawSpanSerde.deserializer());
    TestOutputTopic bypassOutputTopic = td.createOutputTopic(config.getString(SpanNormalizerConstants.BYPASS_OUTPUT_TOPIC_CONFIG_KEY), Serdes.String().deserializer(), structuredTraceSerde.deserializer());
    TestOutputTopic rawLogOutputTopic = td.createOutputTopic(config.getString(SpanNormalizerConstants.OUTPUT_TOPIC_RAW_LOGS_CONFIG_KEY), spanIdentitySerde.deserializer(), new AvroSerde<>().deserializer());
    // with logs event, with bypass key
    // expects no output to raw-span-grouper
    // expects output to trace-enricher
    // expects log output
    Span span1 = Span.newBuilder().setSpanId(ByteString.copyFrom("1".getBytes())).setTraceId(ByteString.copyFrom("trace-1".getBytes())).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("jaeger.servicename").setVStr(SERVICE_NAME).build()).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("test.bypass").setVStr("true").build()).addLogs(Log.newBuilder().setTimestamp(Timestamp.newBuilder().setSeconds(10).build()).addFields(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("z2").setVStr("some event detail").build())).build();
    inputTopic.pipeInput(span1);
    // validate output for trace-enricher
    assertFalse(bypassOutputTopic.isEmpty());
    KeyValue<String, StructuredTrace> kv1 = bypassOutputTopic.readKeyValue();
    assertEquals("__default", kv1.value.getCustomerId());
    assertEquals(HexUtils.getHex(ByteString.copyFrom("trace-1".getBytes()).toByteArray()), HexUtils.getHex(kv1.value.getTraceId().array()));
    // validate no output for raw-spans-grouper
    assertTrue(outputTopic.isEmpty());
    // validate that no change in log traffic
    assertFalse(rawLogOutputTopic.isEmpty());
    LogEvents logEvents = (LogEvents) rawLogOutputTopic.readKeyValue().value;
    Assertions.assertEquals(1, logEvents.getLogEvents().size());
    // with logs event, without bypass key
    // expects output to raw-span-grouper
    // expects no output to trace-enricher
    // expects log output
    Span span2 = Span.newBuilder().setSpanId(ByteString.copyFrom("2".getBytes())).setTraceId(ByteString.copyFrom("trace-2".getBytes())).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("jaeger.servicename").setVStr(SERVICE_NAME).build()).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()).addLogs(Log.newBuilder().setTimestamp(Timestamp.newBuilder().setSeconds(10).build()).addFields(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("z2").setVStr("some event detail").build())).build();
    inputTopic.pipeInput(span2);
    // validate that no output to trace-enricher
    assertTrue(bypassOutputTopic.isEmpty());
    // validate that output to raw-spans-grouper
    assertFalse(outputTopic.isEmpty());
    KeyValue<TraceIdentity, RawSpan> kv2 = outputTopic.readKeyValue();
    assertEquals("__default", kv2.key.getTenantId());
    assertEquals(HexUtils.getHex(ByteString.copyFrom("trace-2".getBytes()).toByteArray()), HexUtils.getHex(kv2.key.getTraceId().array()));
    // validate that no change in log traffic
    assertFalse(rawLogOutputTopic.isEmpty());
    logEvents = (LogEvents) rawLogOutputTopic.readKeyValue().value;
    Assertions.assertEquals(1, logEvents.getLogEvents().size());
    // with logs event, with bypass key but false value
    // expects output to raw-span-grouper
    // expects no output to trace-enricher
    // expects log output
    Span span3 = Span.newBuilder().setSpanId(ByteString.copyFrom("3".getBytes())).setTraceId(ByteString.copyFrom("trace-3".getBytes())).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("jaeger.servicename").setVStr(SERVICE_NAME).build()).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()).addTags(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("test.bypass").setVStr("false").build()).addLogs(Log.newBuilder().setTimestamp(Timestamp.newBuilder().setSeconds(10).build()).addFields(JaegerSpanInternalModel.KeyValue.newBuilder().setKey("z2").setVStr("some event detail").build())).build();
    inputTopic.pipeInput(span3);
    // validate that no output to trace-enricher
    assertTrue(bypassOutputTopic.isEmpty());
    // validate that output to raw-spans-grouper
    assertFalse(outputTopic.isEmpty());
    KeyValue<TraceIdentity, RawSpan> kv3 = outputTopic.readKeyValue();
    assertEquals("__default", kv3.key.getTenantId());
    assertEquals(HexUtils.getHex(ByteString.copyFrom("trace-3".getBytes()).toByteArray()), HexUtils.getHex(kv3.key.getTraceId().array()));
    // validate that no change in log traffic
    assertFalse(rawLogOutputTopic.isEmpty());
    logEvents = (LogEvents) rawLogOutputTopic.readKeyValue().value;
    Assertions.assertEquals(1, logEvents.getLogEvents().size());
}
Also used : HashMap(java.util.HashMap) Config(com.typesafe.config.Config) JaegerSpanSerde(org.hypertrace.core.spannormalizer.jaeger.JaegerSpanSerde) TopologyTestDriver(org.apache.kafka.streams.TopologyTestDriver) ByteString(com.google.protobuf.ByteString) RawSpan(org.hypertrace.core.datamodel.RawSpan) Properties(java.util.Properties) Span(io.jaegertracing.api_v2.JaegerSpanInternalModel.Span) RawSpan(org.hypertrace.core.datamodel.RawSpan) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) TestOutputTopic(org.apache.kafka.streams.TestOutputTopic) LogEvents(org.hypertrace.core.datamodel.LogEvents) StreamsBuilder(org.apache.kafka.streams.StreamsBuilder) AvroSerde(org.hypertrace.core.kafkastreams.framework.serdes.AvroSerde) SetEnvironmentVariable(org.junitpioneer.jupiter.SetEnvironmentVariable) Test(org.junit.jupiter.api.Test)

Example 8 with StructuredTrace

use of org.hypertrace.core.datamodel.StructuredTrace in project hypertrace-ingester by hypertrace.

the class ViewGeneratorStateTest method testGetTraceState.

@Test
public void testGetTraceState() {
    StructuredTrace trace = getTestTrace(customerId, traceId1);
    TraceState traceState = ViewGeneratorState.getTraceState(trace);
    assertNotNull(traceState);
    assertEquals(trace, traceState.getTrace());
    TraceState sameTraceState = ViewGeneratorState.getTraceState(trace);
    assertEquals(sameTraceState, traceState);
    StructuredTrace modifiedTrace = getTestTrace(customerId, traceId1);
    modifiedTrace.setEntityList(Arrays.asList(Entity.newBuilder().setCustomerId(customerId).setEntityId("entity-2").setEntityName("entity-2").setEntityType("service").build()));
    // same trace id but different object should result in rebuilding of trace state
    TraceState differentTraceState1 = ViewGeneratorState.getTraceState(modifiedTrace);
    assertNotEquals(traceState, differentTraceState1);
    StructuredTrace differentTrace = getTestTrace(customerId, traceId2);
    TraceState differentTraceState2 = ViewGeneratorState.getTraceState(differentTrace);
    assertEquals(differentTrace, differentTraceState2.getTrace());
}
Also used : TraceState(org.hypertrace.viewgenerator.generators.ViewGeneratorState.TraceState) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Test(org.junit.jupiter.api.Test)

Example 9 with StructuredTrace

use of org.hypertrace.core.datamodel.StructuredTrace in project hypertrace-ingester by hypertrace.

the class RawSpansGrouper method buildTopology.

public StreamsBuilder buildTopology(Map<String, Object> properties, StreamsBuilder streamsBuilder, Map<String, KStream<?, ?>> inputStreams) {
    Config jobConfig = getJobConfig(properties);
    String inputTopic = jobConfig.getString(INPUT_TOPIC_CONFIG_KEY);
    String outputTopic = jobConfig.getString(OUTPUT_TOPIC_CONFIG_KEY);
    KStream<TraceIdentity, RawSpan> inputStream = (KStream<TraceIdentity, RawSpan>) inputStreams.get(inputTopic);
    if (inputStream == null) {
        inputStream = streamsBuilder.stream(inputTopic);
        inputStreams.put(inputTopic, inputStream);
    }
    // Retrieve the default value serde defined in config and use it
    Serde valueSerde = defaultValueSerde(properties);
    Serde keySerde = defaultKeySerde(properties);
    StoreBuilder<KeyValueStore<TraceIdentity, TraceState>> traceStateStoreBuilder = Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(TRACE_STATE_STORE), keySerde, valueSerde).withCachingEnabled();
    StoreBuilder<KeyValueStore<SpanIdentity, RawSpan>> spanStoreBuilder = Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(SPAN_STATE_STORE_NAME), keySerde, valueSerde).withCachingEnabled();
    streamsBuilder.addStateStore(spanStoreBuilder);
    streamsBuilder.addStateStore(traceStateStoreBuilder);
    Produced<String, StructuredTrace> outputTopicProducer = Produced.with(Serdes.String(), null);
    outputTopicProducer = outputTopicProducer.withName(OUTPUT_TOPIC_PRODUCER);
    inputStream.transform(RawSpansProcessor::new, Named.as(RawSpansProcessor.class.getSimpleName()), SPAN_STATE_STORE_NAME, TRACE_STATE_STORE).to(outputTopic, outputTopicProducer);
    return streamsBuilder;
}
Also used : Serde(org.apache.kafka.common.serialization.Serde) StreamsConfig(org.apache.kafka.streams.StreamsConfig) Config(com.typesafe.config.Config) KStream(org.apache.kafka.streams.kstream.KStream) TraceIdentity(org.hypertrace.core.spannormalizer.TraceIdentity) KeyValueStore(org.apache.kafka.streams.state.KeyValueStore) RawSpan(org.hypertrace.core.datamodel.RawSpan) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace)

Example 10 with StructuredTrace

use of org.hypertrace.core.datamodel.StructuredTrace in project hypertrace-ingester by hypertrace.

the class RawSpansProcessor method transform.

public KeyValue<String, StructuredTrace> transform(TraceIdentity key, RawSpan value) {
    Instant start = Instant.now();
    long currentTimeMs = System.currentTimeMillis();
    TraceState traceState = traceStateStore.get(key);
    boolean firstEntry = (traceState == null);
    if (shouldDropSpan(key, traceState)) {
        return null;
    }
    String tenantId = key.getTenantId();
    ByteBuffer traceId = value.getTraceId();
    ByteBuffer spanId = value.getEvent().getEventId();
    spanStore.put(new SpanIdentity(tenantId, traceId, spanId), value);
    /*
     the trace emit ts is essentially currentTs + groupingWindowTimeoutMs
     i.e. if there is no span added in the next 'groupingWindowTimeoutMs' interval
     then the trace can be finalized and emitted
    */
    long traceEmitTs = currentTimeMs + groupingWindowTimeoutMs;
    if (logger.isDebugEnabled()) {
        logger.debug("Updating trigger_ts=[{}] for for tenant_id=[{}], trace_id=[{}]", Instant.ofEpochMilli(traceEmitTs), key.getTenantId(), HexUtils.getHex(traceId));
    }
    if (firstEntry) {
        traceState = fastNewBuilder(TraceState.Builder.class).setTraceStartTimestamp(currentTimeMs).setTraceEndTimestamp(currentTimeMs).setEmitTs(traceEmitTs).setTenantId(tenantId).setTraceId(traceId).setSpanIds(List.of(spanId)).build();
        schedulePunctuator(key);
    } else {
        traceState.getSpanIds().add(spanId);
        traceState.setTraceEndTimestamp(currentTimeMs);
        traceState.setEmitTs(traceEmitTs);
    }
    traceStateStore.put(key, traceState);
    tenantToSpansGroupingTimer.computeIfAbsent(value.getCustomerId(), k -> PlatformMetricsRegistry.registerTimer(PROCESSING_LATENCY_TIMER, Map.of("tenantId", k))).record(Duration.between(start, Instant.now()).toMillis(), TimeUnit.MILLISECONDS);
    // the punctuator will emit the trace
    return null;
}
Also used : TRACE_STATE_STORE(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.TRACE_STATE_STORE) SPAN_STATE_STORE_NAME(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.SPAN_STATE_STORE_NAME) OUTPUT_TOPIC_PRODUCER(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.OUTPUT_TOPIC_PRODUCER) AvroBuilderCache.fastNewBuilder(org.hypertrace.core.datamodel.shared.AvroBuilderCache.fastNewBuilder) LoggerFactory(org.slf4j.LoggerFactory) TraceState(org.hypertrace.core.spannormalizer.TraceState) HashMap(java.util.HashMap) ByteBuffer(java.nio.ByteBuffer) To(org.apache.kafka.streams.processor.To) ConcurrentMap(java.util.concurrent.ConcurrentMap) PlatformMetricsRegistry(org.hypertrace.core.serviceframework.metrics.PlatformMetricsRegistry) Timer(io.micrometer.core.instrument.Timer) Duration(java.time.Duration) Map(java.util.Map) KeyValueStore(org.apache.kafka.streams.state.KeyValueStore) PunctuationType(org.apache.kafka.streams.processor.PunctuationType) DATAFLOW_SAMPLING_PERCENT_CONFIG_KEY(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.DATAFLOW_SAMPLING_PERCENT_CONFIG_KEY) HexUtils(org.hypertrace.core.datamodel.shared.HexUtils) TraceIdentity(org.hypertrace.core.spannormalizer.TraceIdentity) SpanIdentity(org.hypertrace.core.spannormalizer.SpanIdentity) Counter(io.micrometer.core.instrument.Counter) RawSpan(org.hypertrace.core.datamodel.RawSpan) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Logger(org.slf4j.Logger) Config(com.typesafe.config.Config) Transformer(org.apache.kafka.streams.kstream.Transformer) SPAN_GROUPBY_SESSION_WINDOW_INTERVAL_CONFIG_KEY(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.SPAN_GROUPBY_SESSION_WINDOW_INTERVAL_CONFIG_KEY) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) KeyValue(org.apache.kafka.streams.KeyValue) Instant(java.time.Instant) RAW_SPANS_GROUPER_JOB_CONFIG(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.RAW_SPANS_GROUPER_JOB_CONFIG) Collectors(java.util.stream.Collectors) DEFAULT_INFLIGHT_TRACE_MAX_SPAN_COUNT(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.DEFAULT_INFLIGHT_TRACE_MAX_SPAN_COUNT) TimeUnit(java.util.concurrent.TimeUnit) ProcessorContext(org.apache.kafka.streams.processor.ProcessorContext) List(java.util.List) Cancellable(org.apache.kafka.streams.processor.Cancellable) KeyValueIterator(org.apache.kafka.streams.state.KeyValueIterator) TRUNCATED_TRACES_COUNTER(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.TRUNCATED_TRACES_COUNTER) INFLIGHT_TRACE_MAX_SPAN_COUNT(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.INFLIGHT_TRACE_MAX_SPAN_COUNT) DROPPED_SPANS_COUNTER(org.hypertrace.core.rawspansgrouper.RawSpanGrouperConstants.DROPPED_SPANS_COUNTER) TraceState(org.hypertrace.core.spannormalizer.TraceState) Instant(java.time.Instant) ByteBuffer(java.nio.ByteBuffer) SpanIdentity(org.hypertrace.core.spannormalizer.SpanIdentity)

Aggregations

StructuredTrace (org.hypertrace.core.datamodel.StructuredTrace)79 Test (org.junit.jupiter.api.Test)66 Event (org.hypertrace.core.datamodel.Event)47 HashMap (java.util.HashMap)15 AbstractAttributeEnricherTest (org.hypertrace.traceenricher.enrichment.enrichers.AbstractAttributeEnricherTest)15 Config (com.typesafe.config.Config)7 ByteBuffer (java.nio.ByteBuffer)7 Map (java.util.Map)7 Edge (org.hypertrace.core.datamodel.Edge)7 File (java.io.File)6 List (java.util.List)6 Entity (org.hypertrace.entity.data.service.v1.Entity)6 URL (java.net.URL)5 ArrayList (java.util.ArrayList)5 SpecificDatumReader (org.apache.avro.specific.SpecificDatumReader)5 RawSpan (org.hypertrace.core.datamodel.RawSpan)5 HexUtils (org.hypertrace.core.datamodel.shared.HexUtils)5 Counter (io.micrometer.core.instrument.Counter)4 Duration (java.time.Duration)4 Instant (java.time.Instant)4