Skip to content

Commit 6e36a9c

Browse files
committed
Initial Work
Signed-off-by: Emmanuel Hugonnet <[email protected]>
1 parent 4c71032 commit 6e36a9c

File tree

15 files changed

+333
-6
lines changed

15 files changed

+333
-6
lines changed

examples/helloworld/server/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929
<artifactId>quarkus-resteasy-jackson</artifactId>
3030
<scope>provided</scope>
3131
</dependency>
32+
<dependency>
33+
<groupId>io.quarkus</groupId>
34+
<artifactId>quarkus-opentelemetry</artifactId>
35+
</dependency>
36+
37+
<dependency>
38+
<groupId>io.github.a2asdk</groupId>
39+
<artifactId>a2a-java-sdk-opentelemetry</artifactId>
40+
<version>0.4.0.Alpha1-SNAPSHOT</version>
41+
</dependency>
3242
<dependency>
3343
<groupId>jakarta.enterprise</groupId>
3444
<artifactId>jakarta.enterprise.cdi-api</artifactId>

examples/helloworld/server/src/main/java/io/a2a/examples/helloworld/AgentCardProducer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
import jakarta.enterprise.inject.Produces;
88

99
import io.a2a.server.PublicAgentCard;
10+
import io.a2a.server.interceptors.Trace;
1011
import io.a2a.spec.AgentCapabilities;
1112
import io.a2a.spec.AgentCard;
1213
import io.a2a.spec.AgentSkill;
1314

1415
@ApplicationScoped
1516
public class AgentCardProducer {
1617

18+
@Trace
1719
@Produces
1820
@PublicAgentCard
1921
public AgentCard agentCard() {
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
%dev.quarkus.http.port=9999
1+
%dev.quarkus.http.port=9999
2+
3+
# OpenTelemetry configuration
4+
quarkus.otel.sdk.disabled=false
5+
quarkus.otel.exporter.otlp.endpoint=http://localhost:4317
6+
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n

extras/opentelemetry/pom.xml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.github.a2asdk</groupId>
9+
<artifactId>a2a-java-sdk-parent</artifactId>
10+
<version>0.4.0.Alpha1-SNAPSHOT</version>
11+
<relativePath>../../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>a2a-java-sdk-opentelemetry</artifactId>
15+
16+
<name>A2A Java SDK :: Extras :: Opentelemetry</name>
17+
<description>Java SDK for the Agent2Agent Protocol (A2A) - Extras - Opentelemetry</description>
18+
<properties>
19+
<version.eclipse.microprofile.telemetry>2.0.1</version.eclipse.microprofile.telemetry>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>${project.groupId}</groupId>
25+
<artifactId>a2a-java-sdk-server-common</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>jakarta.enterprise</groupId>
29+
<artifactId>jakarta.enterprise.cdi-api</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>jakarta.inject</groupId>
33+
<artifactId>jakarta.inject-api</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.eclipse.microprofile.telemetry</groupId>
37+
<artifactId>microprofile-telemetry-api</artifactId>
38+
<version>${version.eclipse.microprofile.telemetry}</version>
39+
<type>pom</type>
40+
<scope>provided</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.slf4j</groupId>
44+
<artifactId>slf4j-api</artifactId>
45+
</dependency>
46+
</dependencies>
47+
48+
</project>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package io.a2a.extras.opentelemetry;
2+
3+
import io.a2a.server.interceptors.AttributeExtractor;
4+
import io.a2a.server.interceptors.Kind;
5+
import io.a2a.server.interceptors.Trace;
6+
import io.opentelemetry.api.trace.Span;
7+
import io.opentelemetry.api.trace.SpanBuilder;
8+
import io.opentelemetry.api.trace.SpanKind;
9+
import io.opentelemetry.api.trace.StatusCode;
10+
import io.opentelemetry.api.trace.Tracer;
11+
import io.opentelemetry.context.Scope;
12+
import jakarta.inject.Inject;
13+
import jakarta.interceptor.AroundInvoke;
14+
import jakarta.interceptor.Interceptor;
15+
import jakarta.interceptor.InvocationContext;
16+
import java.util.Map;
17+
18+
@Trace
19+
@Interceptor
20+
public class SpanInterceptor {
21+
22+
private static final String OTEL_SCOPE_KEY_NAME = "OpenTelemetryScope";
23+
private static final String OTEL_SPAN_KEY_NAME = "OpenTelemetrySpan";
24+
25+
@Inject
26+
private Tracer tracer;
27+
28+
@AroundInvoke
29+
public Object trace(InvocationContext context) throws Exception {
30+
Kind kind = context
31+
.getMethod()
32+
.getAnnotation(Trace.class)
33+
.kind();
34+
Class<? extends AttributeExtractor> extractorClass = context
35+
.getMethod()
36+
.getAnnotation(Trace.class)
37+
.extractor();
38+
SpanBuilder spanBuilder = tracer.spanBuilder(context.getMethod().getName())
39+
.setSpanKind(SpanKind.valueOf(kind.toString()));
40+
if (extractorClass != null) {
41+
Map<String, String> attributes = extractorClass.getConstructor(new Class[0]).newInstance(new Object[0]).extract(context.getTarget(), context.getMethod().getName(), context.getParameters());
42+
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
43+
spanBuilder.setAttribute(attribute.getKey(), attribute.getValue());
44+
}
45+
}
46+
Span span = spanBuilder.startSpan();
47+
Scope scope = span.makeCurrent();
48+
context.getContextData().put(OTEL_SCOPE_KEY_NAME, scope);
49+
context.getContextData().put(OTEL_SPAN_KEY_NAME, span);
50+
try {
51+
Object ret = context.proceed();
52+
span.setStatus(StatusCode.OK);
53+
span.end();
54+
return ret;
55+
} catch (Exception ex) {
56+
span.setStatus(StatusCode.ERROR, ex.getMessage());
57+
span.end();
58+
throw ex;
59+
}
60+
}
61+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
5+
bean-discovery-mode="annotated">
6+
<interceptors>
7+
<class>io.a2a.extras.opentelemetry.SpanInterceptor</class>
8+
</interceptors>
9+
</beans>

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@
443443
<module>examples/helloworld</module>
444444
<module>examples/cloud-deployment/server</module>
445445
<module>extras/common</module>
446+
<module>extras/opentelemetry</module>
446447
<module>extras/task-store-database-jpa</module>
447448
<module>extras/push-notification-config-store-database-jpa</module>
448449
<module>extras/queue-manager-replicated</module>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.a2a.server.interceptors;
2+
3+
import java.util.Map;
4+
5+
@FunctionalInterface
6+
public interface AttributeExtractor {
7+
Map<String, String> extract(Object target, String method, Object[] parameters);
8+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.a2a.server.interceptors;
2+
3+
public enum Kind {
4+
INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER;
5+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.a2a.server.interceptors;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
public class NoAttributeExtractor implements AttributeExtractor{
7+
8+
@Override
9+
public Map<String, String> extract(Object target, String method, Object[] parameters) {
10+
return Collections.emptyMap();
11+
}
12+
13+
}

0 commit comments

Comments
 (0)