Skip to content

Upgrade to Brave 6 and Zipkin Reporter 3 #39049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.Propagation;
import brave.propagation.Propagation.Factory;
import brave.propagation.Propagation.KeyFactory;
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;

import org.springframework.beans.factory.ObjectProvider;
Expand Down Expand Up @@ -99,12 +98,11 @@ BaggagePropagation.FactoryBuilder propagationFactoryBuilder(
return builder;
}

@SuppressWarnings("deprecation")
private Factory createThrowAwayFactory() {
return new Factory() {

@Override
public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
public Propagation<String> get() {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.function.Predicate;
import java.util.stream.Stream;

import brave.internal.propagation.StringPropagationAdapter;
import brave.propagation.B3Propagation;
import brave.propagation.Propagation;
import brave.propagation.Propagation.Factory;
Expand Down Expand Up @@ -71,9 +70,8 @@ public boolean requires128BitTraceId() {
}

@Override
@SuppressWarnings("deprecation")
public <K> Propagation<K> create(Propagation.KeyFactory<K> keyFactory) {
return StringPropagationAdapter.create(this.propagation, keyFactory);
public Propagation<String> get() {
return this.propagation;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,135 +18,81 @@

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.net.URI;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import zipkin2.Call;
import zipkin2.CheckResult;
import zipkin2.codec.Encoding;
import zipkin2.reporter.BytesMessageEncoder;
import zipkin2.reporter.ClosedSenderException;
import zipkin2.reporter.Sender;
import zipkin2.reporter.BaseHttpSender;
import zipkin2.reporter.BytesMessageSender;
import zipkin2.reporter.Encoding;
import zipkin2.reporter.HttpEndpointSupplier.Factory;

import org.springframework.http.HttpHeaders;
import org.springframework.util.unit.DataSize;

/**
* A Zipkin {@link Sender} that uses an HTTP client to send JSON spans. Supports automatic
* compression with gzip.
* A Zipkin {@link BytesMessageSender} that uses an HTTP client to send JSON spans.
* Supports automatic compression with gzip.
*
* @author Moritz Halbritter
* @author Stefan Bratanov
*/
abstract class HttpSender extends Sender {
abstract class HttpSender extends BaseHttpSender<URI, byte[]> {

private static final DataSize MESSAGE_MAX_SIZE = DataSize.ofKilobytes(512);

private volatile boolean closed;

@Override
public Encoding encoding() {
return Encoding.JSON;
}
/**
* Only use gzip compression on data which is bigger than this in bytes.
*/
private static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);

@Override
public int messageMaxBytes() {
return (int) MESSAGE_MAX_SIZE.toBytes();
HttpSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint) {
super(encoding, endpointSupplierFactory, endpoint);
}

@Override
public int messageSizeInBytes(List<byte[]> encodedSpans) {
return encoding().listSizeInBytes(encodedSpans);
protected URI newEndpoint(String endpoint) {
return URI.create(endpoint);
}

@Override
public int messageSizeInBytes(int encodedSizeInBytes) {
return encoding().listSizeInBytes(encodedSizeInBytes);
protected byte[] newBody(List<byte[]> list) {
return this.encoding.encode(list);
}

@Override
public CheckResult check() {
try {
sendSpans(Collections.emptyList()).execute();
return CheckResult.OK;
protected void postSpans(URI endpoint, byte[] body) throws IOException {
HttpHeaders headers = getDefaultHeaders();
if (needsCompression(body)) {
body = compress(body);
headers.set("Content-Encoding", "gzip");
}
catch (IOException | RuntimeException ex) {
return CheckResult.failed(ex);
}
}

@Override
public void close() throws IOException {
this.closed = true;
postSpans(endpoint, headers, body);
}

/**
* The returned {@link HttpPostCall} will send span(s) as a POST to a zipkin endpoint
* when executed.
* @param batchedEncodedSpans list of encoded spans as a byte array
* @return an instance of a Zipkin {@link Call} which can be executed
* This will send span(s) as a POST to a zipkin endpoint.
* @param endpoint the POST endpoint. For example, http://localhost:9411/api/v2/spans.
* @param headers headers for the POST request
* @param body list of possibly gzipped, encoded spans.
*/
protected abstract HttpPostCall sendSpans(byte[] batchedEncodedSpans);
abstract void postSpans(URI endpoint, HttpHeaders headers, byte[] body);

@Override
public Call<Void> sendSpans(List<byte[]> encodedSpans) {
if (this.closed) {
throw new ClosedSenderException();
}
return sendSpans(BytesMessageEncoder.JSON.encode(encodedSpans));
HttpHeaders getDefaultHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("b3", "0");
headers.set("Content-Type", this.encoding.mediaType());
return headers;
}

abstract static class HttpPostCall extends Call.Base<Void> {

/**
* Only use gzip compression on data which is bigger than this in bytes.
*/
private static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);

private final byte[] body;

HttpPostCall(byte[] body) {
this.body = body;
}

protected byte[] getBody() {
if (needsCompression()) {
return compress(this.body);
}
return this.body;
}

protected byte[] getUncompressedBody() {
return this.body;
}

protected HttpHeaders getDefaultHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("b3", "0");
headers.set("Content-Type", "application/json");
if (needsCompression()) {
headers.set("Content-Encoding", "gzip");
}
return headers;
}

private boolean needsCompression() {
return this.body.length > COMPRESSION_THRESHOLD.toBytes();
}
private boolean needsCompression(byte[] body) {
return body.length > COMPRESSION_THRESHOLD.toBytes();
}

private byte[] compress(byte[] input) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(result)) {
gzip.write(input);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
return result.toByteArray();
private byte[] compress(byte[] input) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(result)) {
gzip.write(input);
}

return result.toByteArray();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@

package org.springframework.boot.actuate.autoconfigure.tracing.zipkin;

import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.codec.SpanBytesEncoder;
import zipkin2.reporter.Sender;
import zipkin2.reporter.BytesMessageSender;
import zipkin2.reporter.Encoding;

import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.BraveConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.ReporterConfiguration;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.SenderConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
Expand All @@ -44,9 +41,8 @@
* @since 3.0.0
*/
@AutoConfiguration(after = RestTemplateAutoConfiguration.class)
@ConditionalOnClass(Sender.class)
@Import({ SenderConfiguration.class, ReporterConfiguration.class, BraveConfiguration.class,
OpenTelemetryConfiguration.class })
@ConditionalOnClass(BytesMessageSender.class)
@Import({ SenderConfiguration.class, BraveConfiguration.class, OpenTelemetryConfiguration.class })
@EnableConfigurationProperties(ZipkinProperties.class)
public class ZipkinAutoConfiguration {

Expand All @@ -58,8 +54,8 @@ PropertiesZipkinConnectionDetails zipkinConnectionDetails(ZipkinProperties prope

@Bean
@ConditionalOnMissingBean
public BytesEncoder<Span> spanBytesEncoder() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BytesEncoder<Span> is only used by opentelemetry so moved it there

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if BytesEncoder<Span> will be useful outside of OpenTelemetry. It has been moved to ZipkinConfigurations.OpenTelemetryConfiguration, and I wonder if we should leave it in ZipkinAutoConfiguration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, this could break users. I don't really know how many users depend on BytesEncoder<Span> be available, but I would leave it in ZipkinAutoConfiguration instead of moving it to the OpenTelemetry configuration.

return SpanBytesEncoder.JSON_V2;
public Encoding encoding(ZipkinProperties properties) {
return properties.getEncoding();
}

}
Loading