Skip to content

Commit

Permalink
armeria: showcase Eureka integration (#104)
Browse files Browse the repository at this point in the history
Signed-off-by: Adrian Cole <[email protected]>
  • Loading branch information
codefromthecrypt authored Jan 14, 2024
1 parent fe58f3a commit 9bdcd4c
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 23 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 53 additions & 5 deletions armeria/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,64 @@
</properties>

<dependencies>
<dependency>
<groupId>com.linecorp.armeria</groupId>
<artifactId>armeria</artifactId>
<exclusions>
<!-- temporary until netty includes https://github.com/netty/netty/pull/13724 -->
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- temporary until netty includes https://github.com/netty/netty/pull/13724 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<classifier>linux-x86_64</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<classifier>linux-aarch_64</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<classifier>osx-x86_64</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<classifier>osx-aarch_64</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<classifier>windows-x86_64</classifier>
<scope>runtime</scope>
</dependency>

<!-- Instruments the underlying Armeria requests -->
<dependency>
<groupId>com.linecorp.armeria</groupId>
<artifactId>armeria-brave</artifactId>
</dependency>

<!-- Optionally look up Zipkin with Eureka -->
<dependency>
<groupId>com.linecorp.armeria</groupId>
<artifactId>armeria-eureka</artifactId>
</dependency>
<!-- Integrates so you can use log patterns like %X{traceId}/%X{spanId} -->
<dependency>
<groupId>com.linecorp.armeria</groupId>
Expand All @@ -45,10 +97,6 @@
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-sender-urlconnection</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
34 changes: 25 additions & 9 deletions armeria/src/main/java/brave/example/TracingFactory.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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))));
}
Expand Down Expand Up @@ -61,21 +66,32 @@ 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(() -> {
spanHandler.close(); // Make sure spans are reported on shutdown
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());
}
}));

Expand Down
48 changes: 48 additions & 0 deletions armeria/src/main/java/brave/example/WebClientSender.java
Original file line number Diff line number Diff line change
@@ -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<byte[]> 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;
}
}
41 changes: 41 additions & 0 deletions docker-compose-eureka.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 2 additions & 3 deletions docker-compose-kafka.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
9 changes: 4 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -16,15 +15,15 @@ services:
backend:
condition: service_healthy
zipkin:
condition: service_started
condition: service_healthy
# Serves the /api endpoint the frontend uses
backend:
container_name: backend
image: ghcr.io/openzipkin/brave-example:${BRAVE_EXAMPLE:-armeria}
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
Expand Down
2 changes: 1 addition & 1 deletion parent-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<brave.version>6.0.0</brave.version>
<zipkin-reporter.version>3.1.1</zipkin-reporter.version>
<zipkin-reporter.version>3.2.1</zipkin-reporter.version>

<!-- The JRE used in Docker images can be higher than ${maven.compiler.release}. -->
<jre.version>SET MANUALLY IN PROJECTS</jre.version>
Expand Down

0 comments on commit 9bdcd4c

Please sign in to comment.