|
@@ -5,129 +5,24 @@
|
|
|
|
|
|
package io.opentelemetry.javaagent.instrumentation.pulsar.v2_8;
|
|
|
|
|
|
+import static io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil.orderByRootSpanKind;
|
|
|
import static io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil.orderByRootSpanName;
|
|
|
-import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
|
|
-import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
|
|
|
-import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
|
-import io.opentelemetry.api.common.AttributeKey;
|
|
|
import io.opentelemetry.api.trace.SpanKind;
|
|
|
-import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
|
|
-import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
|
|
-import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
|
|
|
import io.opentelemetry.sdk.trace.data.LinkData;
|
|
|
import io.opentelemetry.sdk.trace.data.SpanData;
|
|
|
-import io.opentelemetry.semconv.ServerAttributes;
|
|
|
-import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes;
|
|
|
-import java.time.Duration;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.List;
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
-import org.apache.pulsar.client.admin.PulsarAdmin;
|
|
|
-import org.apache.pulsar.client.api.Consumer;
|
|
|
import org.apache.pulsar.client.api.Message;
|
|
|
import org.apache.pulsar.client.api.MessageId;
|
|
|
import org.apache.pulsar.client.api.MessageListener;
|
|
|
-import org.apache.pulsar.client.api.Messages;
|
|
|
-import org.apache.pulsar.client.api.Producer;
|
|
|
-import org.apache.pulsar.client.api.PulsarClient;
|
|
|
-import org.apache.pulsar.client.api.PulsarClientException;
|
|
|
import org.apache.pulsar.client.api.Schema;
|
|
|
import org.apache.pulsar.client.api.SubscriptionInitialPosition;
|
|
|
-import org.assertj.core.api.AbstractLongAssert;
|
|
|
-import org.junit.jupiter.api.AfterAll;
|
|
|
-import org.junit.jupiter.api.BeforeAll;
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
-import org.junit.jupiter.api.extension.RegisterExtension;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.testcontainers.containers.PulsarContainer;
|
|
|
-import org.testcontainers.containers.output.Slf4jLogConsumer;
|
|
|
-import org.testcontainers.utility.DockerImageName;
|
|
|
-
|
|
|
-class PulsarClientTest {
|
|
|
-
|
|
|
- private static final Logger logger = LoggerFactory.getLogger(PulsarClientTest.class);
|
|
|
-
|
|
|
- private static final DockerImageName DEFAULT_IMAGE_NAME =
|
|
|
- DockerImageName.parse("apachepulsar/pulsar:2.8.0");
|
|
|
-
|
|
|
- @RegisterExtension
|
|
|
- static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
|
|
-
|
|
|
- private static PulsarContainer pulsar;
|
|
|
- private static PulsarClient client;
|
|
|
- private static PulsarAdmin admin;
|
|
|
- private static Producer<String> producer;
|
|
|
- private static Consumer<String> consumer;
|
|
|
- private static Producer<String> producer2;
|
|
|
-
|
|
|
- private static String brokerHost;
|
|
|
- private static int brokerPort;
|
|
|
-
|
|
|
- private static final AttributeKey<String> MESSAGE_TYPE =
|
|
|
- AttributeKey.stringKey("messaging.pulsar.message.type");
|
|
|
-
|
|
|
- @BeforeAll
|
|
|
- static void beforeAll() throws PulsarClientException {
|
|
|
- pulsar =
|
|
|
- new PulsarContainer(DEFAULT_IMAGE_NAME)
|
|
|
- .withEnv("PULSAR_MEM", "-Xmx128m")
|
|
|
- .withLogConsumer(new Slf4jLogConsumer(logger))
|
|
|
- .withStartupTimeout(Duration.ofMinutes(2));
|
|
|
- pulsar.start();
|
|
|
-
|
|
|
- brokerHost = pulsar.getHost();
|
|
|
- brokerPort = pulsar.getMappedPort(6650);
|
|
|
- client = PulsarClient.builder().serviceUrl(pulsar.getPulsarBrokerUrl()).build();
|
|
|
- admin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build();
|
|
|
- }
|
|
|
-
|
|
|
- @AfterAll
|
|
|
- static void afterAll() throws PulsarClientException {
|
|
|
- if (producer != null) {
|
|
|
- producer.close();
|
|
|
- }
|
|
|
- if (consumer != null) {
|
|
|
- consumer.close();
|
|
|
- }
|
|
|
- if (producer2 != null) {
|
|
|
- producer2.close();
|
|
|
- }
|
|
|
- if (client != null) {
|
|
|
- client.close();
|
|
|
- }
|
|
|
- if (admin != null) {
|
|
|
- admin.close();
|
|
|
- }
|
|
|
- pulsar.close();
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void testSendNonPartitionedTopic() throws Exception {
|
|
|
- String topic = "persistent://public/default/testSendNonPartitionedTopic";
|
|
|
- admin.topics().createNonPartitionedTopic(topic);
|
|
|
- producer = client.newProducer(Schema.STRING).topic(topic).enableBatching(false).create();
|
|
|
-
|
|
|
- String msg = "test";
|
|
|
- MessageId msgId = testing.runWithSpan("parent", () -> producer.send(msg));
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
- trace ->
|
|
|
- trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false))));
|
|
|
- }
|
|
|
+class PulsarClientTest extends AbstractPulsarClientTest {
|
|
|
|
|
|
@Test
|
|
|
void testConsumeNonPartitionedTopic() throws Exception {
|
|
@@ -155,26 +50,35 @@ class PulsarClientTest {
|
|
|
|
|
|
latch.await(1, TimeUnit.MINUTES);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic, msgId.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic, msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + " process")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))
|
|
|
+ .hasKind(SpanKind.CONSUMER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
processAttributes(topic, msgId.toString(), false))));
|
|
|
}
|
|
@@ -198,20 +102,28 @@ class PulsarClientTest {
|
|
|
Message<String> receivedMsg = consumer.receive();
|
|
|
consumer.acknowledge(receivedMsg);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic, msgId.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic, msgId.toString(), false))));
|
|
|
}
|
|
@@ -245,26 +157,34 @@ class PulsarClientTest {
|
|
|
|
|
|
result.get(1, TimeUnit.MINUTES);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic, msgId.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic, msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName("callback")
|
|
|
.hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))));
|
|
|
+ .hasParent(trace.getSpan(0))));
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -287,50 +207,9 @@ class PulsarClientTest {
|
|
|
Message<String> receivedMsg = consumer.receive(1, TimeUnit.MINUTES);
|
|
|
consumer.acknowledge(receivedMsg);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
- trace ->
|
|
|
- trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false)),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " receive")
|
|
|
- .hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- receiveAttributes(topic, msgId.toString(), false))));
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void testConsumeNonPartitionedTopicUsingBatchReceive() throws Exception {
|
|
|
- String topic = "persistent://public/default/testConsumeNonPartitionedTopicCallBatchReceive";
|
|
|
- admin.topics().createNonPartitionedTopic(topic);
|
|
|
- consumer =
|
|
|
- client
|
|
|
- .newConsumer(Schema.STRING)
|
|
|
- .subscriptionName("test_sub")
|
|
|
- .topic(topic)
|
|
|
- .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest)
|
|
|
- .subscribe();
|
|
|
-
|
|
|
- producer = client.newProducer(Schema.STRING).topic(topic).enableBatching(false).create();
|
|
|
-
|
|
|
- String msg = "test";
|
|
|
- MessageId msgId = testing.runWithSpan("parent", () -> producer.send(msg));
|
|
|
-
|
|
|
- testing.runWithSpan(
|
|
|
- "receive-parent",
|
|
|
- () -> {
|
|
|
- Messages<String> receivedMsg = consumer.batchReceive();
|
|
|
- consumer.acknowledge(receivedMsg);
|
|
|
- });
|
|
|
AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
-
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
trace -> {
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
@@ -340,80 +219,18 @@ class PulsarClientTest {
|
|
|
.hasParent(trace.getSpan(0))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
sendAttributes(topic, msgId.toString(), false)));
|
|
|
+
|
|
|
producerSpan.set(trace.getSpan(1));
|
|
|
},
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("receive-parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
span ->
|
|
|
span.hasName(topic + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
+ .hasNoParent()
|
|
|
.hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
- batchReceiveAttributes(topic, null, false))));
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void testConsumeNonPartitionedTopicUsingBatchReceiveAsync() throws Exception {
|
|
|
- String topic =
|
|
|
- "persistent://public/default/testConsumeNonPartitionedTopicCallBatchReceiveAsync";
|
|
|
- admin.topics().createNonPartitionedTopic(topic);
|
|
|
- consumer =
|
|
|
- client
|
|
|
- .newConsumer(Schema.STRING)
|
|
|
- .subscriptionName("test_sub")
|
|
|
- .topic(topic)
|
|
|
- .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest)
|
|
|
- .subscribe();
|
|
|
-
|
|
|
- producer = client.newProducer(Schema.STRING).topic(topic).enableBatching(false).create();
|
|
|
-
|
|
|
- String msg = "test";
|
|
|
- MessageId msgId = testing.runWithSpan("parent", () -> producer.send(msg));
|
|
|
-
|
|
|
- CompletableFuture<Messages<String>> result =
|
|
|
- testing.runWithSpan(
|
|
|
- "receive-parent",
|
|
|
- () ->
|
|
|
- consumer
|
|
|
- .batchReceiveAsync()
|
|
|
- .whenComplete(
|
|
|
- (messages, throwable) -> {
|
|
|
- if (messages != null) {
|
|
|
- testing.runWithSpan(
|
|
|
- "callback", () -> acknowledgeMessages(consumer, messages));
|
|
|
- }
|
|
|
- }));
|
|
|
-
|
|
|
- assertThat(result.get(1, TimeUnit.MINUTES).size()).isEqualTo(1);
|
|
|
-
|
|
|
- AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
- testing.waitAndAssertTraces(
|
|
|
- trace ->
|
|
|
- trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span -> {
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), false));
|
|
|
- producerSpan.set(trace.getSpan(1));
|
|
|
- }),
|
|
|
- trace ->
|
|
|
- trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("receive-parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " receive")
|
|
|
- .hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
- .hasAttributesSatisfyingExactly(batchReceiveAttributes(topic, null, false)),
|
|
|
- span ->
|
|
|
- span.hasName("callback")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(1))));
|
|
|
+ receiveAttributes(topic, msgId.toString(), false))));
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -445,49 +262,37 @@ class PulsarClientTest {
|
|
|
|
|
|
latch.await(1, TimeUnit.MINUTES);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic, msgId.toString(), true)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic, msgId.toString(), true)),
|
|
|
span ->
|
|
|
span.hasName(topic + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic, msgId.toString(), true)),
|
|
|
span ->
|
|
|
span.hasName(topic + " process")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- processAttributes(topic, msgId.toString(), true))));
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void testSendPartitionedTopic() throws Exception {
|
|
|
- String topic = "persistent://public/default/testSendPartitionedTopic";
|
|
|
- admin.topics().createPartitionedTopic(topic, 1);
|
|
|
- producer = client.newProducer(Schema.STRING).topic(topic).enableBatching(false).create();
|
|
|
-
|
|
|
- String msg = "test";
|
|
|
- MessageId msgId = testing.runWithSpan("parent", () -> producer.send(msg));
|
|
|
-
|
|
|
- testing.waitAndAssertTraces(
|
|
|
- trace ->
|
|
|
- trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + "-partition-0 publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasKind(SpanKind.CONSUMER)
|
|
|
.hasParent(trace.getSpan(0))
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic + "-partition-0", msgId.toString(), false))));
|
|
|
+ processAttributes(topic, msgId.toString(), true))));
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -517,26 +322,35 @@ class PulsarClientTest {
|
|
|
|
|
|
latch.await(1, TimeUnit.MINUTES);
|
|
|
|
|
|
- testing.waitAndAssertTraces(
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ testing.waitAndAssertSortedTraces(
|
|
|
+ orderByRootSpanKind(SpanKind.INTERNAL, SpanKind.CONSUMER),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic + "-partition-0 publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic + "-partition-0", msgId.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic + "-partition-0 publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic + "-partition-0", msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + "-partition-0 receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic + "-partition-0", msgId.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic + "-partition-0 process")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))
|
|
|
+ .hasKind(SpanKind.CONSUMER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
processAttributes(topic + "-partition-0", msgId.toString(), false))));
|
|
|
}
|
|
@@ -569,149 +383,65 @@ class PulsarClientTest {
|
|
|
|
|
|
latch.await(1, TimeUnit.MINUTES);
|
|
|
|
|
|
+ AtomicReference<SpanData> producerSpan = new AtomicReference<>();
|
|
|
+ AtomicReference<SpanData> producerSpan2 = new AtomicReference<>();
|
|
|
testing.waitAndAssertSortedTraces(
|
|
|
- orderByRootSpanName("parent1", "parent2"),
|
|
|
+ orderByRootSpanName("parent1", topic1 + " receive", "parent2", topic2 + " receive"),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent1").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic1 + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic1, msgId1.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent1").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic1 + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic1, msgId1.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic1 + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic1, msgId1.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic1 + " process")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))
|
|
|
+ .hasKind(SpanKind.CONSUMER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasLinks(LinkData.create(producerSpan.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
processAttributes(topic1, msgId1.toString(), false))),
|
|
|
+ trace -> {
|
|
|
+ trace.hasSpansSatisfyingExactly(
|
|
|
+ span -> span.hasName("parent2").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
+ span ->
|
|
|
+ span.hasName(topic2 + " publish")
|
|
|
+ .hasKind(SpanKind.PRODUCER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasAttributesSatisfyingExactly(
|
|
|
+ sendAttributes(topic2, msgId2.toString(), false)));
|
|
|
+
|
|
|
+ producerSpan2.set(trace.getSpan(1));
|
|
|
+ },
|
|
|
trace ->
|
|
|
trace.hasSpansSatisfyingExactly(
|
|
|
- span -> span.hasName("parent2").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
|
|
- span ->
|
|
|
- span.hasName(topic2 + " publish")
|
|
|
- .hasKind(SpanKind.PRODUCER)
|
|
|
- .hasParent(trace.getSpan(0))
|
|
|
- .hasAttributesSatisfyingExactly(
|
|
|
- sendAttributes(topic2, msgId2.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic2 + " receive")
|
|
|
.hasKind(SpanKind.CONSUMER)
|
|
|
- .hasParent(trace.getSpan(1))
|
|
|
+ .hasNoParent()
|
|
|
+ .hasLinks(LinkData.create(producerSpan2.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
receiveAttributes(topic2, msgId2.toString(), false)),
|
|
|
span ->
|
|
|
span.hasName(topic2 + " process")
|
|
|
- .hasKind(SpanKind.INTERNAL)
|
|
|
- .hasParent(trace.getSpan(2))
|
|
|
+ .hasKind(SpanKind.CONSUMER)
|
|
|
+ .hasParent(trace.getSpan(0))
|
|
|
+ .hasLinks(LinkData.create(producerSpan2.get().getSpanContext()))
|
|
|
.hasAttributesSatisfyingExactly(
|
|
|
processAttributes(topic2, msgId2.toString(), false))));
|
|
|
}
|
|
|
-
|
|
|
- private static List<AttributeAssertion> sendAttributes(
|
|
|
- String destination, String messageId, boolean testHeaders) {
|
|
|
- List<AttributeAssertion> assertions =
|
|
|
- new ArrayList<>(
|
|
|
- Arrays.asList(
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_SYSTEM, "pulsar"),
|
|
|
- equalTo(ServerAttributes.SERVER_ADDRESS, brokerHost),
|
|
|
- equalTo(ServerAttributes.SERVER_PORT, brokerPort),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME, destination),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_OPERATION, "publish"),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID, messageId),
|
|
|
- satisfies(
|
|
|
- MessagingIncubatingAttributes.MESSAGING_MESSAGE_BODY_SIZE,
|
|
|
- AbstractLongAssert::isNotNegative),
|
|
|
- equalTo(MESSAGE_TYPE, "normal")));
|
|
|
- if (testHeaders) {
|
|
|
- assertions.add(
|
|
|
- equalTo(
|
|
|
- AttributeKey.stringArrayKey("messaging.header.test_message_header"),
|
|
|
- Collections.singletonList("test")));
|
|
|
- }
|
|
|
- return assertions;
|
|
|
- }
|
|
|
-
|
|
|
- private static List<AttributeAssertion> batchReceiveAttributes(
|
|
|
- String destination, String messageId, boolean testHeaders) {
|
|
|
- return receiveAttributes(destination, messageId, testHeaders, true);
|
|
|
- }
|
|
|
-
|
|
|
- private static List<AttributeAssertion> receiveAttributes(
|
|
|
- String destination, String messageId, boolean testHeaders) {
|
|
|
- return receiveAttributes(destination, messageId, testHeaders, false);
|
|
|
- }
|
|
|
-
|
|
|
- private static List<AttributeAssertion> receiveAttributes(
|
|
|
- String destination, String messageId, boolean testHeaders, boolean isBatch) {
|
|
|
- List<AttributeAssertion> assertions =
|
|
|
- new ArrayList<>(
|
|
|
- Arrays.asList(
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_SYSTEM, "pulsar"),
|
|
|
- equalTo(ServerAttributes.SERVER_ADDRESS, brokerHost),
|
|
|
- equalTo(ServerAttributes.SERVER_PORT, brokerPort),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME, destination),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_OPERATION, "receive"),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID, messageId),
|
|
|
- satisfies(
|
|
|
- MessagingIncubatingAttributes.MESSAGING_MESSAGE_BODY_SIZE,
|
|
|
- AbstractLongAssert::isNotNegative)));
|
|
|
- if (testHeaders) {
|
|
|
- assertions.add(
|
|
|
- equalTo(
|
|
|
- AttributeKey.stringArrayKey("messaging.header.test_message_header"),
|
|
|
- Collections.singletonList("test")));
|
|
|
- }
|
|
|
- if (isBatch) {
|
|
|
- assertions.add(
|
|
|
- satisfies(
|
|
|
- MessagingIncubatingAttributes.MESSAGING_BATCH_MESSAGE_COUNT,
|
|
|
- AbstractLongAssert::isPositive));
|
|
|
- }
|
|
|
- return assertions;
|
|
|
- }
|
|
|
-
|
|
|
- private static List<AttributeAssertion> processAttributes(
|
|
|
- String destination, String messageId, boolean testHeaders) {
|
|
|
- List<AttributeAssertion> assertions =
|
|
|
- new ArrayList<>(
|
|
|
- Arrays.asList(
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_SYSTEM, "pulsar"),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME, destination),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_OPERATION, "process"),
|
|
|
- equalTo(MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID, messageId),
|
|
|
- satisfies(
|
|
|
- MessagingIncubatingAttributes.MESSAGING_MESSAGE_BODY_SIZE,
|
|
|
- AbstractLongAssert::isNotNegative)));
|
|
|
- if (testHeaders) {
|
|
|
- assertions.add(
|
|
|
- equalTo(
|
|
|
- AttributeKey.stringArrayKey("messaging.header.test_message_header"),
|
|
|
- Collections.singletonList("test")));
|
|
|
- }
|
|
|
- return assertions;
|
|
|
- }
|
|
|
-
|
|
|
- private static void acknowledgeMessage(Consumer<String> consumer, Message<String> message) {
|
|
|
- try {
|
|
|
- consumer.acknowledge(message);
|
|
|
- } catch (PulsarClientException exception) {
|
|
|
- throw new RuntimeException(exception);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private static void acknowledgeMessages(Consumer<String> consumer, Messages<String> messages) {
|
|
|
- try {
|
|
|
- consumer.acknowledge(messages);
|
|
|
- } catch (PulsarClientException exception) {
|
|
|
- throw new RuntimeException(exception);
|
|
|
- }
|
|
|
- }
|
|
|
}
|