From 7af3f456dd1a950d1f884d1d6a89113006ea2b28 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 14 Jan 2024 16:02:35 +0800 Subject: [PATCH] armeria: showcase Eureka integration Signed-off-by: Adrian Cole --- README.md | 2 + armeria/pom.xml | 58 +++++++++++++++++-- .../java/brave/example/TracingFactory.java | 34 ++++++++--- .../java/brave/example/WebClientSender.java | 48 +++++++++++++++ docker-compose-eureka.yml | 41 +++++++++++++ docker-compose-kafka.yml | 5 +- docker-compose.yml | 9 ++- parent-pom.xml | 2 +- 8 files changed, 176 insertions(+), 23 deletions(-) create mode 100644 armeria/src/main/java/brave/example/WebClientSender.java create mode 100644 docker-compose-eureka.yml diff --git a/README.md b/README.md index bc2a8f9..8cfc81b 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Here are the example projects you can try: * Runtime: Armeria, SLF4J 1.7, JRE 21 * Trace Instrumentation: [Armeria](https://armeria.dev/), [SLF4J](https://github.com/openzipkin/brave/tree/master/context/slf4j) * Trace Configuration: [Brave API](https://github.com/openzipkin/brave/tree/master/brave#setup) [Java](armeria/src/main/java/brave/example/HttpTracingFactory.java) + * You can also use Eureka discovery like this: + * `BRAVE_EXAMPLE=armeria docker-compose -f docker-compose.yml -f docker-compose-eureka.yml up` * [armeria-kafka](armeria-kafka) `BRAVE_EXAMPLE=armeria-kafka docker-compose -f docker-compose.yml -f docker-compose-kafka.yml up` * Runtime: Armeria, Kafka Clients and Streams 2.7, SLF4J 1.7, JRE 21 diff --git a/armeria/pom.xml b/armeria/pom.xml index 86d531d..0058814 100644 --- a/armeria/pom.xml +++ b/armeria/pom.xml @@ -24,12 +24,64 @@ + + com.linecorp.armeria + armeria + + + + io.netty + netty-tcnative-boringssl-static + + + + + + io.netty + netty-tcnative-boringssl-static + 2.0.62.Final + linux-x86_64 + runtime + + + io.netty + netty-tcnative-boringssl-static + 2.0.62.Final + linux-aarch_64 + runtime + + + io.netty + netty-tcnative-boringssl-static + 2.0.62.Final + osx-x86_64 + runtime + + + io.netty + netty-tcnative-boringssl-static + 2.0.62.Final + osx-aarch_64 + runtime + + + io.netty + netty-tcnative-boringssl-static + 2.0.62.Final + windows-x86_64 + runtime + + com.linecorp.armeria armeria-brave - + + + com.linecorp.armeria + armeria-eureka + com.linecorp.armeria @@ -45,10 +97,6 @@ io.zipkin.reporter2 zipkin-reporter-brave - - io.zipkin.reporter2 - zipkin-sender-urlconnection - diff --git a/armeria/src/main/java/brave/example/TracingFactory.java b/armeria/src/main/java/brave/example/TracingFactory.java index 9833a7b..221ac72 100644 --- a/armeria/src/main/java/brave/example/TracingFactory.java +++ b/armeria/src/main/java/brave/example/TracingFactory.java @@ -1,5 +1,7 @@ package brave.example; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import brave.Tracing; import brave.baggage.BaggageField; import brave.baggage.BaggagePropagation; @@ -11,17 +13,20 @@ import brave.propagation.CurrentTraceContext; import brave.propagation.CurrentTraceContext.ScopeDecorator; import brave.propagation.Propagation; +import com.linecorp.armeria.client.WebClient; +import com.linecorp.armeria.client.eureka.EurekaEndpointGroup; +import com.linecorp.armeria.common.SessionProtocol; import com.linecorp.armeria.common.brave.RequestContextCurrentTraceContext; +import com.linecorp.armeria.common.logging.RequestLogLevelMapper; import java.io.IOException; -import java.util.logging.Logger; -import zipkin2.reporter.Sender; +import zipkin2.reporter.BytesMessageSender; import zipkin2.reporter.brave.AsyncZipkinSpanHandler; -import zipkin2.reporter.urlconnection.URLConnectionSender; final class HttpTracingFactory { + static final Logger LOGGER = LoggerFactory.getLogger(HttpTracingFactory.class); static final BaggageField USER_NAME = BaggageField.create("userName"); - /** Decides how to name and tag spans. By default they are named the same as the http method. */ + /** Decides how to name and tag spans. By default, they are named the same as the http method. */ static HttpTracing create(String serviceName) { return HttpTracing.create(tracing((System.getProperty("brave.localServiceName", serviceName)))); } @@ -61,13 +66,24 @@ static Propagation.Factory propagationFactory() { } /** Configuration for how to send spans to Zipkin */ - static Sender sender() { - return URLConnectionSender.create( - System.getProperty("zipkin.baseUrl", "http://127.0.0.1:9411") + "/api/v2/spans"); + static BytesMessageSender sender() { + String postPath = "/api/v2/spans"; + String eurekaUri = System.getenv("EUREKA_SERVICE_URL"); + if (eurekaUri != null && !eurekaUri.isEmpty()) { + EurekaEndpointGroup zipkin = + EurekaEndpointGroup.builder(eurekaUri).appName("zipkin").build(); + LOGGER.info("Using eureka to discover zipkin: {}", eurekaUri); + Runtime.getRuntime().addShutdownHook(new Thread(zipkin::close)); + return new WebClientSender(WebClient.of(SessionProtocol.H2C, zipkin, postPath)); + } + String zipkinUri = + System.getProperty("zipkin.baseUrl", "http://127.0.0.1:9411") + postPath; + LOGGER.info("Using zipkin URI: {}", zipkinUri); + return new WebClientSender(WebClient.of(zipkinUri)); } /** Configuration for how to buffer spans into messages for Zipkin */ - static AsyncZipkinSpanHandler spanHandler(Sender sender) { + static AsyncZipkinSpanHandler spanHandler(BytesMessageSender sender) { final AsyncZipkinSpanHandler spanHandler = AsyncZipkinSpanHandler.create(sender); Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -75,7 +91,7 @@ static AsyncZipkinSpanHandler spanHandler(Sender sender) { try { sender.close(); // Release any network resources used to send spans } catch (IOException e) { - Logger.getAnonymousLogger().warning("error closing trace sender: " + e.getMessage()); + LOGGER.warn("error closing trace sender: " + e.getMessage()); } })); diff --git a/armeria/src/main/java/brave/example/WebClientSender.java b/armeria/src/main/java/brave/example/WebClientSender.java new file mode 100644 index 0000000..f4de741 --- /dev/null +++ b/armeria/src/main/java/brave/example/WebClientSender.java @@ -0,0 +1,48 @@ +package brave.example; + +import com.linecorp.armeria.client.WebClient; +import com.linecorp.armeria.common.AggregatedHttpResponse; +import com.linecorp.armeria.common.HttpData; +import com.linecorp.armeria.common.HttpMethod; +import com.linecorp.armeria.common.HttpRequest; +import com.linecorp.armeria.common.MediaType; +import java.io.IOException; +import java.util.List; +import zipkin2.reporter.BytesMessageEncoder; +import zipkin2.reporter.BytesMessageSender; +import zipkin2.reporter.ClosedSenderException; +import zipkin2.reporter.Encoding; + +final class WebClientSender extends BytesMessageSender.Base { + final WebClient zipkinApiV2SpansClient; + volatile boolean closeCalled; // volatile as not called from the reporting thread. + + WebClientSender(WebClient zipkinApiV2SpansClient) { + super(Encoding.JSON); + this.zipkinApiV2SpansClient = zipkinApiV2SpansClient; + } + + @Override public int messageMaxBytes() { + return 500_000; // Use the most common HTTP default + } + + @Override public void send(List encodedSpans) throws IOException { + if (closeCalled) throw new ClosedSenderException(); + byte[] body = BytesMessageEncoder.JSON.encode(encodedSpans); + HttpRequest request = + HttpRequest.of(HttpMethod.POST, "", MediaType.JSON, HttpData.wrap(body)); + AggregatedHttpResponse response = zipkinApiV2SpansClient.blocking().execute(request); + try (HttpData content = response.content()) { + if (!response.status().isSuccess()) { + if (content.isEmpty()) { + throw new IOException("response failed: " + response); + } + throw new IOException("response failed: " + content.toStringAscii()); + } + } + } + + @Override public void close() { + closeCalled = true; + } +} diff --git a/docker-compose-eureka.yml b/docker-compose-eureka.yml new file mode 100644 index 0000000..edd1a4e --- /dev/null +++ b/docker-compose-eureka.yml @@ -0,0 +1,41 @@ +# permit depends_on/condition: service_healthy +version: '2.4' + +services: + eureka: + image: ghcr.io/openzipkin/zipkin-eureka + container_name: eureka + # Uncomment to expose the eureka port for testing + # ports: + # - 8761:8761 + + zipkin: + extends: + file: docker-compose.yml + service: zipkin + environment: + - EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2 + - EUREKA_HOSTNAME=zipkin + depends_on: + eureka: + condition: service_healthy + + frontend: + extends: + file: docker-compose.yml + service: frontend + environment: + - EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2 + depends_on: + eureka: + condition: service_healthy + + backend: + extends: + file: docker-compose.yml + service: backend + environment: + - EUREKA_SERVICE_URL=http://eureka:8761/eureka/v2 + depends_on: + eureka: + condition: service_healthy \ No newline at end of file diff --git a/docker-compose-kafka.yml b/docker-compose-kafka.yml index 36af628..3c5cdbc 100644 --- a/docker-compose-kafka.yml +++ b/docker-compose-kafka.yml @@ -1,7 +1,6 @@ --- -# Format version 2.1 was introduced with Docker Compose v1.9 -# We need Docker Compose v1.9+ for unset variable interpolation -version: "2.1" +# permit depends_on/condition: service_healthy +version: "2.4" services: kafka: diff --git a/docker-compose.yml b/docker-compose.yml index e4e2560..22c47b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,5 @@ -# Format version 2.1 was introduced with Docker Compose v1.9 -# We need Docker Compose v1.9+ for unset variable interpolation -version: "2.1" +# permit depends_on/condition: service_healthy +version: "2.4" # BRAVE_EXAMPLE choices are listed here https://github.com/openzipkin/brave-example#example-projects @@ -16,7 +15,7 @@ services: backend: condition: service_healthy zipkin: - condition: service_started + condition: service_healthy # Serves the /api endpoint the frontend uses backend: container_name: backend @@ -24,7 +23,7 @@ services: entrypoint: start-backend depends_on: zipkin: - condition: service_started + condition: service_healthy # View traces at http://127.0.0.1:9411/zipkin zipkin: image: ghcr.io/openzipkin/zipkin-slim diff --git a/parent-pom.xml b/parent-pom.xml index afd5b20..06a7ecf 100644 --- a/parent-pom.xml +++ b/parent-pom.xml @@ -34,7 +34,7 @@ UTF-8 6.0.0 - 3.1.1 + 3.2.0 SET MANUALLY IN PROJECTS