This commit is contained in:
Phillip Webb 2024-02-21 16:06:02 -08:00
parent b4e8b57dac
commit e6fe273105
9 changed files with 81 additions and 69 deletions

View File

@ -22,7 +22,6 @@ import org.springframework.boot.autoconfigure.service.connection.ConnectionDetai
/**
* Details required to establish a connection to a Zipkin server.
*
* <p>
* Note: {@linkplain #getSpanEndpoint()} is only read once and passed to a bean of type
* {@link HttpEndpointSupplier.Factory} which defaults to no-op (constant).

View File

@ -55,7 +55,7 @@ class ZipkinHttpClientSender extends HttpSender {
.POST(BodyPublishers.ofByteArray(body))
.uri(endpoint)
.timeout(this.readTimeout);
headers.forEach((key, values) -> values.forEach((value) -> request.header(key, value)));
headers.forEach((name, values) -> values.forEach((value) -> request.header(name, value)));
try {
HttpResponse<Void> response = this.httpClient.send(request.build(), BodyHandlers.discarding());
if (response.statusCode() / 100 != 2) {

View File

@ -90,6 +90,7 @@ public class ZipkinProperties {
* JSON.
*/
JSON,
/**
* Protocol Buffers v3.
*/

View File

@ -30,7 +30,7 @@ class DefaultEncodingConfiguration {
@Bean
@ConditionalOnMissingBean
Encoding encoding() {
Encoding zipkinReporterEncoding() {
return Encoding.JSON;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;
import java.util.concurrent.atomic.AtomicInteger;
import zipkin2.reporter.HttpEndpointSupplier;
/**
* Test {@link HttpEndpointSupplier}.
*
* @author Moritz Halbritter
*/
class TestHttpEndpointSupplier implements HttpEndpointSupplier {
private final String url;
private final AtomicInteger suffix = new AtomicInteger();
TestHttpEndpointSupplier(String url) {
this.url = url;
}
@Override
public String get() {
return this.url + "/" + this.suffix.incrementAndGet();
}
@Override
public void close() {
}
}

View File

@ -72,7 +72,6 @@ class ZipkinConfigurationsBraveConfigurationTests {
this.contextRunner.withClassLoader(new FilteredClassLoader("zipkin2.reporter.brave"))
.withUserConfiguration(SenderConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));
}
@Test
@ -128,13 +127,7 @@ class ZipkinConfigurationsBraveConfigurationTests {
this.contextRunner.withUserConfiguration(SenderConfiguration.class).run((context) -> {
@SuppressWarnings("unchecked")
BytesEncoder<MutableSpan> encoder = context.getBean(BytesEncoder.class);
MutableSpan span = new MutableSpan();
span.traceId("1");
span.id("1");
span.tag("error", "true");
span.error(new RuntimeException("ice cream"));
MutableSpan span = createTestSpan();
// default tag key name is "error", and doesn't overwrite
assertThat(new String(encoder.encode(span), StandardCharsets.UTF_8)).isEqualTo(
"{\"traceId\":\"0000000000000001\",\"id\":\"0000000000000001\",\"tags\":{\"error\":\"true\"}}");
@ -147,19 +140,22 @@ class ZipkinConfigurationsBraveConfigurationTests {
.run((context) -> {
@SuppressWarnings("unchecked")
BytesEncoder<MutableSpan> encoder = context.getBean(BytesEncoder.class);
MutableSpan span = new MutableSpan();
span.traceId("1");
span.id("1");
span.tag("error", "true");
span.error(new RuntimeException("ice cream"));
MutableSpan span = createTestSpan();
// The custom throwable parser doesn't use the key "error" we can see both
assertThat(new String(encoder.encode(span), StandardCharsets.UTF_8)).isEqualTo(
"{\"traceId\":\"0000000000000001\",\"id\":\"0000000000000001\",\"tags\":{\"error\":\"true\",\"exception\":\"ice cream\"}}");
});
}
private MutableSpan createTestSpan() {
MutableSpan span = new MutableSpan();
span.traceId("1");
span.id("1");
span.tag("error", "true");
span.error(new RuntimeException("ice cream"));
return span;
}
@Configuration(proxyBeanMethods = false)
private static final class SenderConfiguration {
@ -185,7 +181,7 @@ class ZipkinConfigurationsBraveConfigurationTests {
@Bean
Tag<Throwable> throwableTag() {
return new Tag<Throwable>("exception") {
return new Tag<>("exception") {
@Override
protected String parseValue(Throwable throwable, TraceContext traceContext) {
return throwable.getMessage();

View File

@ -24,7 +24,6 @@ import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import okhttp3.mockwebserver.MockResponse;
@ -57,7 +56,7 @@ class ZipkinHttpClientSenderTests extends ZipkinHttpSenderTests {
private static MockWebServer mockBackEnd;
private static String zipkinUrl;
static String zipkinUrl;
@BeforeAll
static void beforeAll() throws IOException {
@ -130,22 +129,15 @@ class ZipkinHttpClientSenderTests extends ZipkinHttpSenderTests {
void sendUsesDynamicEndpoint() throws Exception {
mockBackEnd.enqueue(new MockResponse());
mockBackEnd.enqueue(new MockResponse());
AtomicInteger suffix = new AtomicInteger();
try (BytesMessageSender sender = createSender((e) -> new HttpEndpointSupplier() {
@Override
public String get() {
return zipkinUrl + "/" + suffix.incrementAndGet();
try (TestHttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(zipkinUrl)) {
try (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON,
Duration.ofSeconds(10))) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
}
@Override
public void close() {
}
}, Encoding.JSON, Duration.ofSeconds(10))) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/1");
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/2");
}
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/1");
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/2");
}
@Test

View File

@ -21,7 +21,6 @@ import java.net.URI;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -97,7 +96,6 @@ class ZipkinRestTemplateSenderTests extends ZipkinHttpSenderTests {
.andExpect(content().contentType("application/x-protobuf"))
.andExpect(content().string("span1span2"))
.andRespond(withStatus(HttpStatus.ACCEPTED));
try (BytesMessageSender sender = createSender(Encoding.PROTO3)) {
sender.send(List.of(toByteArray("span1"), toByteArray("span2")));
}
@ -111,20 +109,11 @@ class ZipkinRestTemplateSenderTests extends ZipkinHttpSenderTests {
void sendUsesDynamicEndpoint() throws Exception {
this.mockServer.expect(requestTo(ZIPKIN_URL + "/1")).andRespond(withStatus(HttpStatus.ACCEPTED));
this.mockServer.expect(requestTo(ZIPKIN_URL + "/2")).andRespond(withStatus(HttpStatus.ACCEPTED));
AtomicInteger suffix = new AtomicInteger();
try (BytesMessageSender sender = createSender((e) -> new HttpEndpointSupplier() {
@Override
public String get() {
return ZIPKIN_URL + "/" + suffix.incrementAndGet();
try (HttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(ZIPKIN_URL)) {
try (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON)) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
}
@Override
public void close() {
}
}, Encoding.JSON)) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
}
}

View File

@ -24,7 +24,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import okhttp3.mockwebserver.MockResponse;
@ -113,11 +112,9 @@ class ZipkinWebClientSenderTests extends ZipkinHttpSenderTests {
void sendShouldSendSpansToZipkinInProto3() throws IOException, InterruptedException {
mockBackEnd.enqueue(new MockResponse());
List<byte[]> encodedSpans = List.of(toByteArray("span1"), toByteArray("span2"));
try (BytesMessageSender sender = createSender(Encoding.PROTO3, Duration.ofSeconds(10))) {
sender.send(encodedSpans);
}
requestAssertions((request) -> {
assertThat(request.getMethod()).isEqualTo("POST");
assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-protobuf");
@ -133,24 +130,15 @@ class ZipkinWebClientSenderTests extends ZipkinHttpSenderTests {
void sendUsesDynamicEndpoint() throws Exception {
mockBackEnd.enqueue(new MockResponse());
mockBackEnd.enqueue(new MockResponse());
AtomicInteger suffix = new AtomicInteger();
try (BytesMessageSender sender = createSender((e) -> new HttpEndpointSupplier() {
@Override
public String get() {
return ZIPKIN_URL + "/" + suffix.incrementAndGet();
try (HttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(ZIPKIN_URL)) {
try (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON,
Duration.ofSeconds(10))) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
}
@Override
public void close() {
}
}, Encoding.JSON, Duration.ofSeconds(10))) {
sender.send(Collections.emptyList());
sender.send(Collections.emptyList());
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/1");
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/2");
}
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/1");
assertThat(mockBackEnd.takeRequest().getPath()).endsWith("/2");
}
@Test