Skip to content

Commit

Permalink
New rest observation instrumentation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobat committed Dec 4, 2024
1 parent e6e6b3c commit 664a2d9
Show file tree
Hide file tree
Showing 46 changed files with 2,387 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ private static Severity toSeverity(final Level level) {
}

public static void install(final OpenTelemetry openTelemetry) {
Logger logger = openTelemetry.getLogsBridge().loggerBuilder(OpenTelemetryConfig.INSTRUMENTATION_NAME).build();
Logger logger = openTelemetry.getLogsBridge()
.loggerBuilder(OpenTelemetryConfig.INSTRUMENTATION_NAME)
.setInstrumentationVersion(OpenTelemetryConfig.INSTRUMENTATION_VERSION)
.build();
LogManager.getLogManager().getLogger("").addHandler(new OpenTelemetryHandler(logger));
}
}
8 changes: 0 additions & 8 deletions implementation/observation-otel-bridge/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@
<artifactId>smallrye-opentelemetry-observation-otel-bridge</artifactId>
<name>SmallRye OpenTelemetry: Observation to OpenTelemetry bridge</name>

<properties>
<micrometer-docs-generator.version>1.0.2</micrometer-docs-generator.version>
<micrometer-docs-generator.inputPath>${project.build.sourceDirectory}</micrometer-docs-generator.inputPath>
<micrometer-docs-generator.inclusionPattern>.*</micrometer-docs-generator.inclusionPattern>
<micrometer-docs-generator.outputPath>${project.build.directory}/observation-docs/
</micrometer-docs-generator.outputPath>
</properties>

<dependencies>
<dependency>
<groupId>io.smallrye.opentelemetry</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.util.Nonbinding;

import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.annotation.Observed;

public class ObservationExtension implements Extension {
public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
beforeBeanDiscovery.addInterceptorBinding(
new ObservedAnnotatedType(beanManager.createAnnotatedType(Observed.class)));

beforeBeanDiscovery.addAnnotatedType(ObservationRegistry.class, ObservationRegistry.class.getName());
// beforeBeanDiscovery.addAnnotatedType(OpenTelemetryObservationHandler.class,
// OpenTelemetryObservationHandler.class.getName());
beforeBeanDiscovery.addAnnotatedType(ObservationRegistryProducer.class, ObservationRegistryProducer.class.getName());
}

public void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.smallrye.opentelemetry.instrumentation.observation;
package io.smallrye.opentelemetry.instrumentation.observation.cdi;

import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
Expand All @@ -23,15 +23,12 @@ public class ObservationRegistryProducer {
OpenTelemetry openTelemetry;

@Inject
OpenTelemetryObservationHandler openTelemetryObservationHandler;

@Inject
MeterRegistry registry;
MeterRegistry meterRegistry;

@Produces
@Singleton
public ObservationRegistry registry() {
ObservationRegistry observationRegistry = ObservationRegistry.create();
final ObservationRegistry observationRegistry = ObservationRegistry.create();

observationRegistry.observationConfig()
// .observationFilter(new CloudObservationFilter()) // Where global filters go
Expand All @@ -41,9 +38,9 @@ public ObservationRegistry registry() {
openTelemetry.getPropagators().getTextMapPropagator()),
new PropagatingReceiverTracingObservationHandler(tracer,
openTelemetry.getPropagators().getTextMapPropagator()),
// new TracingAwareMeterObservationHandler(tracer) // For exemplars... Maybe not be needed
openTelemetryObservationHandler))
.observationHandler(new DefaultMeterObservationHandler(registry));
// new TracingAwareMeterObservationHandler(tracer) // For exemplars...
new OpenTelemetryObservationHandler(tracer)))
.observationHandler(new DefaultMeterObservationHandler(meterRegistry));
// .observationHandler(new PrintOutHandler()) // Can be implemented for debugging. Other handlers for future frameworks can also be added.
return observationRegistry;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static io.opentelemetry.semconv.SemanticAttributes.NET_SOCK_PEER_ADDR;
import static io.opentelemetry.semconv.SemanticAttributes.NET_SOCK_PEER_PORT;
import static io.opentelemetry.semconv.SemanticAttributes.PEER_SERVICE;
import static io.smallrye.opentelemetry.instrumentation.observation.handler.HandlerUtil.HIGH_CARD_ATTRIBUTES;
import static io.smallrye.opentelemetry.instrumentation.observation.handler.HandlerUtil.LOW_CARD_ATTRIBUTES;

import java.net.URI;
import java.util.logging.Logger;
Expand Down Expand Up @@ -108,16 +110,37 @@ protected Span getParentSpan(T context) {
return null;
}

@SuppressWarnings("unchecked")
protected void tagSpan(T context, Span span) {
final Attributes highCardAttributes = context.get(HIGH_CARD_ATTRIBUTES);
setOtelAttributes(span, highCardAttributes);

final Attributes lowCardAttributes = context.get(LOW_CARD_ATTRIBUTES);
setOtelAttributes(span, lowCardAttributes);

for (KeyValue keyValue : context.getAllKeyValues()) {
if (!keyValue.getKey().equalsIgnoreCase("ERROR")) {
span.setAttribute(keyValue.getKey(), keyValue.getValue());

} else {
span.recordException(new RuntimeException(keyValue.getValue()));
}
}
}

private void setOtelAttributes(Span span, Attributes contextAttributes) {
if (contextAttributes != null) {
contextAttributes.forEach((key, value) -> {
// FIXME this is a bit of a hack because KeyValue only allows String values
if (key.getKey().equalsIgnoreCase("ERROR")) {
span.recordException(new RuntimeException(value.toString()));
} else {
span.setAttribute((AttributeKey<Object>) key, value);
}
});
}
}

protected SpanBuilder remoteSpanBuilder(Kind kind,
String remoteServiceName,
String remoteServiceAddress,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.smallrye.opentelemetry.instrumentation.observation.handler;

public class HandlerUtil {
public static final String LOW_CARD_ATTRIBUTES = "low_card_attributes";
public static final String HIGH_CARD_ATTRIBUTES = "high_card_attributes";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

import java.util.logging.Logger;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import io.micrometer.common.util.StringUtils;
import io.micrometer.observation.Observation;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.smallrye.opentelemetry.instrumentation.observation.context.TracingObservationContext;

@Singleton
public class OpenTelemetryObservationHandler extends AbstractTracingObservationHandler<Observation.Context> {

private static final Logger logger = Logger.getLogger(OpenTelemetryObservationHandler.class.getName());
private final Tracer tracer;

@Inject
Tracer tracer;
public OpenTelemetryObservationHandler(Tracer tracer) {
this.tracer = tracer;
}

@Override
public void onStart(Observation.Context context) {
Expand Down Expand Up @@ -52,7 +50,8 @@ private Span nextSpan(Tracer tracer, Span parent) {
}

private Span nextSpan(Tracer tracer) {
return tracer.spanBuilder("").startSpan();
return tracer.spanBuilder("")
.startSpan();
}

private String getSpanName(Observation.Context context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
otel.logs.exporter=none
#otel.logs.exporter=none
otel.metric.export.interval=1000
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@
import io.smallrye.opentelemetry.implementation.cdi.OpenTelemetryExtension;
import io.smallrye.opentelemetry.implementation.config.OpenTelemetryConfigProducer;
import io.smallrye.opentelemetry.implementation.micrometer.cdi.MicrometerExtension;
import io.smallrye.opentelemetry.instrumentation.observation.ObservationRegistryProducer;
import io.smallrye.opentelemetry.instrumentation.observation.cdi.ObservationExtension;
import io.smallrye.opentelemetry.instrumentation.observation.handler.OpenTelemetryObservationHandler;
import io.smallrye.opentelemetry.test.InMemoryExporter;
import io.smallrye.opentelemetry.test.InMemoryExporterProducer;

@EnableAutoWeld
@AddExtensions({ OpenTelemetryExtension.class, ConfigExtension.class, ObservationExtension.class, MicrometerExtension.class })
@AddBeanClasses({ OpenTelemetryConfigProducer.class, ObservationRegistryProducer.class, OpenTelemetryObservationHandler.class,
@AddBeanClasses({ OpenTelemetryConfigProducer.class,
InMemoryExporter.class, InMemoryExporterProducer.class })
class ObservationOTelTest {
@Inject
Expand Down
45 changes: 45 additions & 0 deletions implementation/rest-observation/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.smallrye.opentelemetry</groupId>
<artifactId>smallrye-opentelemetry-parent</artifactId>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>smallrye-opentelemetry-rest-observation</artifactId>
<name>SmallRye OpenTelemetry: REST Observation</name>

<dependencies>
<dependency>
<groupId>io.smallrye.opentelemetry</groupId>
<artifactId>smallrye-opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.opentelemetry</groupId>
<artifactId>smallrye-opentelemetry-micrometer-otel-bridge</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.opentelemetry</groupId>
<artifactId>smallrye-opentelemetry-observation-otel-bridge</artifactId>
</dependency>

<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.opentelemetry.semconv</groupId>
<artifactId>opentelemetry-semconv</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package io.smallrye.opentelemetry.implementation.rest.observation;

import io.micrometer.common.docs.KeyName;
import io.micrometer.observation.docs.ObservationDocumentation;
import io.smallrye.opentelemetry.implementation.rest.observation.client.ClientFilterConvention;
import io.smallrye.opentelemetry.implementation.rest.observation.client.DefaultClientFilterConvention;
import io.smallrye.opentelemetry.implementation.rest.observation.server.DefaultServerFilterConvention;
import io.smallrye.opentelemetry.implementation.rest.observation.server.ServerFilterConvention;

public enum FilterDocumentation implements ObservationDocumentation {
SERVER {
@Override
public Class<? extends ServerFilterConvention> getDefaultConvention() {
return DefaultServerFilterConvention.class;
}

@Override
public KeyName[] getLowCardinalityKeyNames() {
return LowCardinalityValues.values();
}

@Override
public KeyName[] getHighCardinalityKeyNames() {
return KeyName.merge(HighCardinalityValues.values(), ServerHighCardinalityValues.values());
}
},
CLIENT {
@Override
public Class<? extends ClientFilterConvention> getDefaultConvention() {
return DefaultClientFilterConvention.class;
}

@Override
public KeyName[] getLowCardinalityKeyNames() {
return LowCardinalityValues.values();
}

@Override
public KeyName[] getHighCardinalityKeyNames() {
return KeyName.merge(HighCardinalityValues.values(), ClientHighCardinalityValues.values());
}
};

public enum LowCardinalityValues implements KeyName {
/**
* The HTTP method of the request.
*/
HTTP_REQUEST_METHOD {
@Override
public String asString() {
return "http.request.method";
}
},
HTTP_ROUTE {
@Override
public String asString() {
return "http.route";
}
},
URL_SCHEME {
@Override
public String asString() {
return "url.scheme";
}
},
HTTP_RESPONSE_STATUS_CODE {
@Override
public String asString() {
return "http.response.status_code";
}
},
NETWORK_PROTOCOL_NAME {
@Override
public String asString() {
return "network.protocol.name";
}
},
NETWORK_PROTOCOL_VERSION {
@Override
public String asString() {
return "network.protocol.version";
}
}
}

public enum ServerHighCardinalityValues implements KeyName {
SERVER_PORT {
@Override
public String asString() {
return "server.port";
}
},
SERVER_ADDRESS {
@Override
public String asString() {
return "server.address";
}
}
}

public enum ClientHighCardinalityValues implements KeyName {
CLIENT_ADDRESS {
@Override
public String asString() {
return "client.address";
}
},
CLIENT_PORT {
@Override
public String asString() {
return "client.port";
}
}
}

public enum HighCardinalityValues implements KeyName {
URL_PATH {
@Override
public String asString() {
return "url.path";
}
},
URL_QUERY {
@Override
public String asString() {
return "url.query";
}
},
ERROR {
@Override
public String asString() {
return "error";
}
},
URL_FULL {
@Override
public String asString() {
return "url.full";
}
},
USER_AGENT_ORIGINAL {
@Override
public String asString() {
return "user_agent.original";
}
}
}
}
Loading

0 comments on commit 664a2d9

Please sign in to comment.