Skip to content

Opamp first iteration completion #2067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
implementation("net.ltgt.gradle:gradle-errorprone-plugin:4.3.0")
implementation("net.ltgt.gradle:gradle-nullaway-plugin:2.2.0")
implementation("org.owasp:dependency-check-gradle:12.1.3")
implementation("ru.vyarus.animalsniffer:ru.vyarus.animalsniffer.gradle.plugin:2.0.1")
}

spotless {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import ru.vyarus.gradle.plugin.animalsniffer.AnimalSniffer

plugins {
id("otel.java-conventions")
id("ru.vyarus.animalsniffer")
}

dependencies {
signature("com.toasttab.android:gummy-bears-api-21:0.12.0:coreLib@signature")
}

animalsniffer {
sourceSets = listOf(java.sourceSets.main.get())
}

// Always having declared output makes this task properly participate in tasks up-to-date checks
tasks.withType<AnimalSniffer> {
reports.text.required.set(true)
}
18 changes: 1 addition & 17 deletions disk-buffering/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import ru.vyarus.gradle.plugin.animalsniffer.AnimalSniffer

plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
id("otel.animalsniffer-conventions")
id("com.gradleup.shadow")
id("me.champeau.jmh") version "0.7.3"
id("ru.vyarus.animalsniffer") version "2.0.1"
id("com.squareup.wire") version "5.3.11"
}

Expand All @@ -20,27 +19,12 @@ dependencies {
implementation("io.opentelemetry:opentelemetry-api-incubator")
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
signature("com.toasttab.android:gummy-bears-api-21:0.12.0:coreLib@signature")
testImplementation("org.mockito:mockito-inline")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")

protos("io.opentelemetry.proto:opentelemetry-proto:1.7.0-alpha@jar")
}

animalsniffer {
sourceSets = listOf(java.sourceSets.main.get())
}

// Always having declared output makes this task properly participate in tasks up-to-date checks
tasks.withType<AnimalSniffer> {
reports.text.required.set(true)
}

// Attaching animalsniffer check to the compilation process.
tasks.named("classes").configure {
finalizedBy("animalsnifferMain")
}

jmh {
warmupIterations.set(0)
fork.set(2)
Expand Down
50 changes: 50 additions & 0 deletions opamp-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,56 @@
Java implementation of the OpAMP
client [spec](https://github.com/open-telemetry/opamp-spec/blob/main/specification.md).

> [!WARNING]
> This is an incubating feature. Breaking changes can happen on a new release without previous
> notice and without backward compatibility guarantees.

## Usage

```java
// Initializing it

RequestService requestService = HttpRequestService.create(OkHttpSender.create("[OPAMP_SERVICE_URL]"));
// RequestService requestService = WebSocketRequestService.create(OkHttpWebSocket.create("[OPAMP_SERVICE_URL]")); // Use this instead to connect to the server via WebSocket.
OpampClient client =
OpampClient.builder()
.putIdentifyingAttribute("service.name", "My service name")
.enableRemoteConfig()
.setRequestService(requestService)
.build(
new OpampClient.Callbacks() {
@Override
public void onConnect() {}

@Override
public void onConnectFailed(@Nullable Throwable throwable) {}

@Override
public void onErrorResponse(ServerErrorResponse errorResponse) {}

@Override
public void onMessage(MessageData messageData) {
AgentRemoteConfig remoteConfig = messageData.getRemoteConfig();
if (remoteConfig != null) {
// A remote config was received

// After applying it...
client.setRemoteConfigStatus(
new RemoteConfigStatus.Builder()
.status(RemoteConfigStatuses.RemoteConfigStatuses_APPLIED)
.build());
}
}
});

// State update
client.setAgentDescription(new AgentDescription.Builder().build());

// App shutdown
client.close();

```

## Component owners

- [Cesar Munoz](https://github.com/LikeTheSalad), Elastic
Expand Down
3 changes: 3 additions & 0 deletions opamp-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import java.net.URL

plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
id("otel.animalsniffer-conventions")
id("de.undercouch.download") version "5.6.0"
id("com.squareup.wire") version "5.3.11"
}
Expand All @@ -14,6 +16,7 @@ otelJava.moduleName.set("io.opentelemetry.contrib.opamp.client")
dependencies {
implementation("com.squareup.okhttp3:okhttp")
implementation("com.github.f4b6a3:uuid-creator")
implementation("io.opentelemetry:opentelemetry-api")
annotationProcessor("com.google.auto.value:auto-value")
compileOnly("com.google.auto.value:auto-value-annotations")
testImplementation("org.mockito:mockito-inline")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,23 @@
package io.opentelemetry.opamp.client.internal;

import io.opentelemetry.opamp.client.internal.response.MessageData;
import java.io.Closeable;
import javax.annotation.Nullable;
import opamp.proto.AgentDescription;
import opamp.proto.RemoteConfigStatus;
import opamp.proto.ServerErrorResponse;

public interface OpampClient {
public interface OpampClient extends Closeable {

static OpampClientBuilder builder() {
return new OpampClientBuilder();
}

/**
* Starts the client and begin attempts to connect to the Server. Once connection is established
* the client will attempt to maintain it by reconnecting if the connection is lost. All failed
* connection attempts will be reported via {@link Callbacks#onConnectFailed(Throwable)} callback.
*
* <p>This method does not wait until the connection to the Server is established and will likely
* return before the connection attempts are even made.
*
* <p>This method may be called only once.
*
* @param callbacks The Callback to which the Client will notify about any Server requests and
* responses.
*/
void start(Callbacks callbacks);

/**
* Stops the client. May be called only after {@link #start(Callbacks)}. May be called only once.
* After this call returns successfully it is guaranteed that no callbacks will be called. Once
* stopped, the client cannot be started again.
*/
void stop();

/**
* Sets attributes of the Agent. The attributes will be included in the next status report sent to
* the Server. When called after {@link #start(Callbacks)}, the attributes will be included in the
* next outgoing status report. This is typically used by Agents which allow their
* AgentDescription to change dynamically while the OpAMPClient is started. May be also called
* from {@link Callbacks#onMessage(MessageData)}.
* Sets attributes of the Agent. The attributes will be included in the next outgoing status
* report. This is typically used by Agents which allow their AgentDescription to change
* dynamically while the OpAMPClient is started. May be also called from {@link
* Callbacks#onMessage(MessageData)}.
*
* @param agentDescription The new agent description.
*/
Expand All @@ -59,16 +37,14 @@ static OpampClientBuilder builder() {

interface Callbacks {
/**
* Called when the connection is successfully established to the Server. May be called after
* {@link #start(Callbacks)} is called and every time a connection is established to the Server.
* For WebSocket clients this is called after the handshake is completed without any error. For
* HTTP clients this is called for any request if the response status is OK.
* Called when the connection is successfully established to the Server. For WebSocket clients
* this is called after the handshake is completed without any error. For HTTP clients this is
* called for any request if the response status is OK.
*/
void onConnect();

/**
* Called when the connection to the Server cannot be established. May be called after {@link
* #start(Callbacks)} is called and tries to connect to the Server. May also be called if the
* Called when the connection to the Server cannot be established. May also be called if the
* connection is lost and reconnection attempt fails.
*
* @param throwable The exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,7 @@ public OpampClientBuilder setEffectiveConfigState(State.EffectiveConfig effectiv
return this;
}

public OpampClient build() {
if (service == null) {
throw new IllegalStateException(
"The request service is not set. You must provide it by calling setRequestService()");
}
public OpampClient build(OpampClient.Callbacks callbacks) {
List<KeyValue> protoIdentifyingAttributes = new ArrayList<>();
List<KeyValue> protoNonIdentifyingAttributes = new ArrayList<>();
identifyingAttributes.forEach(
Expand All @@ -411,7 +407,7 @@ public OpampClient build() {
new State.InstanceUid(instanceUid),
new State.Flags(0L),
effectiveConfigState);
return OpampClientImpl.create(service, state);
return OpampClientImpl.create(service, state, callbacks);
}

private static State.EffectiveConfig createEffectiveConfigNoop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.opamp.client.internal.connectivity.http;

import io.opentelemetry.api.internal.InstrumentationUtil;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;
Expand All @@ -13,6 +14,7 @@
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okio.BufferedSink;

Expand Down Expand Up @@ -45,8 +47,16 @@ public CompletableFuture<Response> send(BodyWriter writer, int contentLength) {
RequestBody body = new RawRequestBody(writer, contentLength, MEDIA_TYPE);
builder.post(body);

// By suppressing instrumentations, we prevent automatic instrumentations for the okhttp request
// that polls the opamp server.
InstrumentationUtil.suppressInstrumentation(() -> doSendRequest(builder.build(), future));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps there should be a comment explaining that this prevents automatic instrumentation from tracing the underlying okhttp request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I've just added a comment.


return future;
}

private void doSendRequest(Request request, CompletableFuture<Response> future) {
client
.newCall(builder.build())
.newCall(request)
.enqueue(
new Callback() {
@Override
Expand All @@ -59,8 +69,6 @@ public void onFailure(Call call, IOException e) {
future.completeExceptionally(e);
}
});

return future;
}

private static class OkHttpResponse implements Response {
Expand Down
Loading
Loading