Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .fossa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ targets:
- type: gradle
path: ./
target: ':instrumentation:gwt-2.0:javaagent'
- type: gradle
path: ./
target: ':instrumentation:helidon-4.3:javaagent'
- type: gradle
path: ./
target: ':instrumentation:helidon-4.3:library'
- type: gradle
path: ./
target: ':instrumentation:hikaricp-3.0:javaagent'
Expand Down
2 changes: 2 additions & 0 deletions .github/config/lychee.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ exclude = [
'^http://code.google.com/p/concurrentlinkedhashmap$',
'^https://softwareengineering.stackexchange.com/questions/29727.*',
'^https://central.sonatype.com/service/rest/repository/browse/maven-snapshots/io/opentelemetry/$',
# new artifact, remove after 2.21.0 release
'^https://central.sonatype.com/artifact/io.opentelemetry.instrumentation/opentelemetry-helidon-4.3$',
]
1 change: 1 addition & 0 deletions docs/supported-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ These are the supported libraries and frameworks:
| [gRPC](https://github.com/grpc/grpc-java) | 1.6+ | [opentelemetry-grpc-1.6](../instrumentation/grpc-1.6/library) | [RPC Client Spans], [RPC Client Metrics], [RPC Server Spans], [RPC Server Metrics] |
| [Guava ListenableFuture](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/ListenableFuture.html) | 10.0+ | [opentelemetry-guava-10.0](../instrumentation/guava-10.0/library) | Context propagation |
| [GWT](https://www.gwtproject.org/) | 2.0+ | N/A | [RPC Server Spans] |
| [Helidon](https://helidon.io/) | 4.3+ | [opentelemetry-helidon-4.3](../instrumentation/helidon-4.3/library) | [HTTP Server Spans], [HTTP Server Metrics], Provides `http.route` [2] |
| [Hibernate](https://github.com/hibernate/hibernate-orm) | 3.3+ | N/A | none |
| [Hibernate Reactive](https://hibernate.org/reactive) | 1.0+ | N/A | none |
| [HikariCP](https://github.com/brettwooldridge/HikariCP) | 3.0+ | [opentelemetry-hikaricp-3.0](../instrumentation/hikaricp-3.0/library) | [Database Pool Metrics] |
Expand Down
22 changes: 22 additions & 0 deletions instrumentation/helidon-4.3/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("io.helidon.webserver")
module.set("helidon-webserver")
versions.set("[4.3.0,)")
assertInverse.set(true)
}
}

otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_21)
}

dependencies {
library("io.helidon.webserver:helidon-webserver:4.3.0")
implementation(project(":instrumentation:helidon-4.3:library"))
testImplementation(project(":instrumentation:helidon-4.3:testing"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.isStatic;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.helidon.webserver.http.HttpRouting;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class HelidonInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("io.helidon.webserver.http.HttpRouting");
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod().and(isPublic()).and(isStatic()).and(named("builder")),
HelidonInstrumentation.class.getName() + "$BuildAdvice");
}

@SuppressWarnings("unused")
public static class BuildAdvice {

@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.Return HttpRouting.Builder httpContext) {
HelidonSingletons.FILTERS.forEach(httpContext::addFilter);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import static java.util.Collections.singletonList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class HelidonInstrumentationModule extends InstrumentationModule {
public HelidonInstrumentationModule() {
super("helidon", "helidon-4.3");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new HelidonInstrumentation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import io.helidon.webserver.http.ServerResponse;
import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseMutator;

enum HelidonServerResponseMutator implements HttpServerResponseMutator<ServerResponse> {
INSTANCE;

@Override
public void appendHeader(ServerResponse res, String name, String value) {
res.header(name, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import io.helidon.webserver.http.Filter;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.helidon.v4_3.HelidonTelemetry;
import io.opentelemetry.instrumentation.helidon.v4_3.internal.HelidonInstrumenterBuilderUtil;
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
import java.util.List;

public final class HelidonSingletons {

public static final List<Filter> FILTERS;

static {
var serverBuilder = HelidonTelemetry.builder(GlobalOpenTelemetry.get());
HelidonInstrumenterBuilderUtil.getServerBuilderExtractor()
.apply(serverBuilder)
.configure(AgentCommonConfig.get());
var serverTelemetry = serverBuilder.build();

FILTERS = List.of(serverTelemetry.createFilter(), new ResponseCustomizingFilter());
}

private HelidonSingletons() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import io.helidon.webserver.http.Filter;
import io.helidon.webserver.http.FilterChain;
import io.helidon.webserver.http.RoutingRequest;
import io.helidon.webserver.http.RoutingResponse;
import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseCustomizerHolder;

final class ResponseCustomizingFilter implements Filter {

ResponseCustomizingFilter() {}

@Override
public void filter(FilterChain chain, RoutingRequest req, RoutingResponse res) {

var context = Context.current();
HttpServerResponseCustomizerHolder.getCustomizer()
.customize(context, res, HelidonServerResponseMutator.INSTANCE);
chain.proceed();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.helidon.v4_3;

import io.opentelemetry.instrumentation.helidon.v4_3.AbstractHelidonTest;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
import org.junit.jupiter.api.extension.RegisterExtension;

class HelidonServerTest extends AbstractHelidonTest {

@RegisterExtension
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();

@Override
protected void configure(HttpServerTestOptions options) {
super.configure(options);
options.setHasResponseCustomizer(serverEndpoint -> true);

options.setTestNotFound(false);
}
}
56 changes: 56 additions & 0 deletions instrumentation/helidon-4.3/library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Library Instrumentation for Helidon

Provides OpenTelemetry instrumentation for [Helidon](https://helidon.io/).

## Quickstart

### Add these dependencies to your project

Replace `OPENTELEMETRY_VERSION` with the [latest
release](https://central.sonatype.com/artifact/io.opentelemetry.instrumentation/opentelemetry-helidon-4.3).

For Maven, add to your `pom.xml` dependencies:

```xml
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-helidon-4.3</artifactId>
<version>OPENTELEMETRY_VERSION</version>
</dependency>
</dependencies>
```

For Gradle, add to your dependencies:

```groovy
implementation("io.opentelemetry.instrumentation:opentelemetry-helidon-4.3:OPENTELEMETRY_VERSION")
```

### Usage

The instrumentation library contains an `HttpFeature` that provides OpenTelemetry-based spans
and context propagation.

```java
import java.io.IOException;

import io.helidon.webserver.WebServer;
import io.helidon.webserver.http.HttpRouting;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.helidon.v4_3.HelidonTelemetry;

public class Application {

static void main(String args) throws IOException {

OpenTelemetry openTelemetry = // ...
WebServer.builder()
.addRouting(
HttpRouting.builder()
.addFeature(HelidonTelemetry.create(openTelemetry))
.get("/greet", (req, res) -> res.send("Hello World!")))
.build();
}
}
```
12 changes: 12 additions & 0 deletions instrumentation/helidon-4.3/library/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
id("otel.library-instrumentation")
}

otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_21)
}

dependencies {
library("io.helidon.webserver:helidon-webserver:4.3.0")
testImplementation(project(":instrumentation:helidon-4.3:testing"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.helidon.v4_3;

import io.helidon.http.HeaderNames;
import io.helidon.webserver.http.ServerRequest;
import io.helidon.webserver.http.ServerResponse;
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesGetter;
import java.net.InetSocketAddress;
import java.util.List;
import javax.annotation.Nullable;

enum HelidonAttributesGetter implements HttpServerAttributesGetter<ServerRequest, ServerResponse> {
INSTANCE;

@Override
public String getHttpRequestMethod(ServerRequest req) {
return req.prologue().method().text();
}

@Override
public String getUrlScheme(ServerRequest req) {
return req.requestedUri().scheme();
}

@Override
public String getUrlPath(ServerRequest req) {
return req.path().rawPath();
}

@Nullable
@Override
public String getUrlQuery(ServerRequest req) {
return req.query().rawValue();
}

@Override
public List<String> getHttpRequestHeader(ServerRequest req, String name) {
return req.headers().values(HeaderNames.create(name));
}

@Override
public Integer getHttpResponseStatusCode(
ServerRequest req, ServerResponse res, @Nullable Throwable error) {
return res.status().code();
}

@Override
public List<String> getHttpResponseHeader(ServerRequest req, ServerResponse res, String name) {
return res.headers().values(HeaderNames.create(name));
}

@Override
public String getNetworkProtocolName(ServerRequest req, @Nullable ServerResponse res) {
return req.prologue().protocol();
}

@Override
public String getNetworkProtocolVersion(ServerRequest req, @Nullable ServerResponse res) {
return req.prologue().protocolVersion();
}

@Override
public InetSocketAddress getNetworkPeerInetSocketAddress(
ServerRequest req, @Nullable ServerResponse res) {
var address = req.remotePeer().address();
return address instanceof InetSocketAddress s ? s : null;
}

@Override
public InetSocketAddress getNetworkLocalInetSocketAddress(
ServerRequest req, @Nullable ServerResponse res) {
var address = req.localPeer().address();
return address instanceof InetSocketAddress s ? s : null;
}
}
Loading
Loading