Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.Closeable;
import javax.annotation.Nullable;
import opamp.proto.AgentDescription;
import opamp.proto.ComponentHealth;
import opamp.proto.RemoteConfigStatus;
import opamp.proto.ServerErrorResponse;

Expand All @@ -35,6 +36,13 @@ static OpampClientBuilder builder() {
*/
void setRemoteConfigStatus(RemoteConfigStatus remoteConfigStatus);

/**
* Sets the current Agent health which will be sent in the next agent to server request.
*
* @param health The new component health.
*/
void setHealth(ComponentHealth health);
Comment thread
robsunday marked this conversation as resolved.

interface Callbacks {
/**
* Called when the connection is successfully established to the Server. For WebSocket clients
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import opamp.proto.AgentCapabilities;
import opamp.proto.AgentDescription;
import opamp.proto.AnyValue;
import opamp.proto.ArrayValue;
import opamp.proto.ComponentHealth;
import opamp.proto.KeyValue;
import opamp.proto.RemoteConfigStatus;

Expand All @@ -37,6 +40,7 @@ public final class OpampClientBuilder {
HttpRequestService.create(OkHttpSender.create("http://localhost:4320/v1/opamp"));
@Nullable private byte[] instanceUid;
@Nullable private State.EffectiveConfig effectiveConfigState;
@Nullable private ComponentHealth initialHealth;

OpampClientBuilder() {}

Expand Down Expand Up @@ -341,10 +345,8 @@ public OpampClientBuilder putNonIdentifyingAttribute(String key, double... value
*/
@CanIgnoreReturnValue
public OpampClientBuilder enableRemoteConfig() {
capabilities =
capabilities
| AgentCapabilities.AgentCapabilities_AcceptsRemoteConfig.getValue()
| AgentCapabilities.AgentCapabilities_ReportsRemoteConfig.getValue();
enableCapability(AgentCapabilities.AgentCapabilities_AcceptsRemoteConfig);
enableCapability(AgentCapabilities.AgentCapabilities_ReportsRemoteConfig);
return this;
}

Expand All @@ -357,8 +359,7 @@ public OpampClientBuilder enableRemoteConfig() {
*/
@CanIgnoreReturnValue
public OpampClientBuilder enableEffectiveConfigReporting() {
capabilities =
capabilities | AgentCapabilities.AgentCapabilities_ReportsEffectiveConfig.getValue();
enableCapability(AgentCapabilities.AgentCapabilities_ReportsEffectiveConfig);
return this;
}

Expand All @@ -376,6 +377,20 @@ public OpampClientBuilder setEffectiveConfigState(State.EffectiveConfig effectiv
return this;
}

/**
* Enables health reporting and sets the initial health object that is then passed to the
* corresponding state implementation.
*
* @param initialHealth The component health
* @return this
*/
@CanIgnoreReturnValue
public OpampClientBuilder enableHealthReporting(@Nonnull ComponentHealth initialHealth) {
this.initialHealth = Objects.requireNonNull(initialHealth);
enableCapability(AgentCapabilities.AgentCapabilities_ReportsHealth);
return this;
}
Comment thread
robsunday marked this conversation as resolved.

public OpampClient build(OpampClient.Callbacks callbacks) {
List<KeyValue> protoIdentifyingAttributes = new ArrayList<>();
List<KeyValue> protoNonIdentifyingAttributes = new ArrayList<>();
Expand All @@ -399,12 +414,17 @@ public OpampClient build(OpampClient.Callbacks callbacks) {
.non_identifying_attributes(protoNonIdentifyingAttributes)
.build()),
new State.Capabilities(capabilities),
new State.Health(initialHealth),
new State.InstanceUid(instanceUid),
new State.Flags(0L),
effectiveConfigState);
return OpampClientImpl.create(service, state, callbacks);
}

private void enableCapability(AgentCapabilities capability) {
capabilities = capabilities | capability.getValue();
}

private static State.EffectiveConfig createEffectiveConfigNoop() {
return new State.EffectiveConfig() {
@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.CapabilitiesAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.EffectiveConfigAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.FlagsAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.HealthAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.InstanceUidAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.RemoteConfigStatusAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.SequenceNumberAppender;
Expand All @@ -32,8 +33,10 @@
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import okio.ByteString;
import opamp.proto.AgentCapabilities;
import opamp.proto.AgentDescription;
import opamp.proto.AgentToServer;
import opamp.proto.ComponentHealth;
import opamp.proto.RemoteConfigStatus;
import opamp.proto.ServerErrorResponse;
import opamp.proto.ServerToAgent;
Expand Down Expand Up @@ -76,6 +79,7 @@ public final class OpampClientImpl
// Compressable fields init
List<Field> compressableFields = new ArrayList<>();
compressableFields.add(Field.AGENT_DESCRIPTION);
compressableFields.add(Field.HEALTH);
compressableFields.add(Field.EFFECTIVE_CONFIG);
compressableFields.add(Field.REMOTE_CONFIG_STATUS);
COMPRESSABLE_FIELDS = Collections.unmodifiableList(compressableFields);
Expand All @@ -90,6 +94,7 @@ public static OpampClientImpl create(
RemoteConfigStatusAppender.create(state.remoteConfigStatus),
SequenceNumberAppender.create(state.sequenceNum),
CapabilitiesAppender.create(state.capabilities),
HealthAppender.create(state.health),
InstanceUidAppender.create(state.instanceUid),
FlagsAppender.create(state.flags),
AgentDisconnectAppender.create());
Expand Down Expand Up @@ -130,20 +135,27 @@ public void close() {

@Override
public void setAgentDescription(@Nonnull AgentDescription agentDescription) {
if (!state.agentDescription.get().equals(agentDescription)) {
state.agentDescription.set(agentDescription);
if (state.agentDescription.set(agentDescription)) {
addFieldAndSend(Field.AGENT_DESCRIPTION);
}
}

@Override
public void setRemoteConfigStatus(@Nonnull RemoteConfigStatus remoteConfigStatus) {
if (!state.remoteConfigStatus.get().equals(remoteConfigStatus)) {
state.remoteConfigStatus.set(remoteConfigStatus);
verifyCapability(AgentCapabilities.AgentCapabilities_ReportsRemoteConfig);
if (state.remoteConfigStatus.set(remoteConfigStatus)) {
addFieldAndSend(Field.REMOTE_CONFIG_STATUS);
}
}

@Override
public void setHealth(@Nonnull ComponentHealth health) {
verifyCapability(AgentCapabilities.AgentCapabilities_ReportsHealth);
if (state.health.set(health)) {
addFieldAndSend(Field.HEALTH);
}
}
Comment thread
robsunday marked this conversation as resolved.

@Override
public void onConnectionSuccess() {
callbacks.onConnect(this);
Expand Down Expand Up @@ -252,4 +264,11 @@ private void addFieldAndSend(Field field) {
recipeManager.next().addField(field);
requestService.sendRequest();
}

private void verifyCapability(AgentCapabilities capabilityToCheck) {
if ((state.capabilities.mustGet() & capabilityToCheck.getValue()) == 0) {
throw new IllegalStateException(
"Required capability " + capabilityToCheck + " is not enabled");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class OpampClientState {
public final State.SequenceNum sequenceNum;
public final State.AgentDescription agentDescription;
public final State.Capabilities capabilities;
public final State.Health health;
public final State.InstanceUid instanceUid;
public final State.Flags flags;
public final State.EffectiveConfig effectiveConfig;
Expand All @@ -29,13 +30,15 @@ public OpampClientState(
State.SequenceNum sequenceNum,
State.AgentDescription agentDescription,
State.Capabilities capabilities,
State.Health health,
State.InstanceUid instanceUid,
State.Flags flags,
State.EffectiveConfig effectiveConfig) {
this.remoteConfigStatus = remoteConfigStatus;
this.sequenceNum = sequenceNum;
this.agentDescription = agentDescription;
this.capabilities = capabilities;
this.health = health;
this.instanceUid = instanceUid;
this.flags = flags;
this.effectiveConfig = effectiveConfig;
Expand All @@ -45,6 +48,7 @@ public OpampClientState(
providedItems.add(sequenceNum);
providedItems.add(agentDescription);
providedItems.add(capabilities);
providedItems.add(health);
providedItems.add(instanceUid);
providedItems.add(flags);
providedItems.add(effectiveConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.CapabilitiesAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.EffectiveConfigAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.FlagsAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.HealthAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.InstanceUidAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.RemoteConfigStatusAppender;
import io.opentelemetry.opamp.client.internal.impl.recipe.appenders.SequenceNumberAppender;
Expand All @@ -29,17 +30,20 @@ public final class AgentToServerAppenders {
public final RemoteConfigStatusAppender remoteConfigStatusAppender;
public final SequenceNumberAppender sequenceNumberAppender;
public final CapabilitiesAppender capabilitiesAppender;
public final HealthAppender healthAppender;
public final InstanceUidAppender instanceUidAppender;
public final FlagsAppender flagsAppender;
public final AgentDisconnectAppender agentDisconnectAppender;
private final Map<Field, AgentToServerAppender> allAppenders;

@SuppressWarnings("TooManyParameters")
public AgentToServerAppenders(
AgentDescriptionAppender agentDescriptionAppender,
EffectiveConfigAppender effectiveConfigAppender,
RemoteConfigStatusAppender remoteConfigStatusAppender,
SequenceNumberAppender sequenceNumberAppender,
CapabilitiesAppender capabilitiesAppender,
HealthAppender healthAppender,
InstanceUidAppender instanceUidAppender,
FlagsAppender flagsAppender,
AgentDisconnectAppender agentDisconnectAppender) {
Expand All @@ -48,6 +52,7 @@ public AgentToServerAppenders(
this.remoteConfigStatusAppender = remoteConfigStatusAppender;
this.sequenceNumberAppender = sequenceNumberAppender;
this.capabilitiesAppender = capabilitiesAppender;
this.healthAppender = healthAppender;
this.instanceUidAppender = instanceUidAppender;
this.flagsAppender = flagsAppender;
this.agentDisconnectAppender = agentDisconnectAppender;
Expand All @@ -58,6 +63,7 @@ public AgentToServerAppenders(
appenders.put(Field.REMOTE_CONFIG_STATUS, remoteConfigStatusAppender);
appenders.put(Field.SEQUENCE_NUM, sequenceNumberAppender);
appenders.put(Field.CAPABILITIES, capabilitiesAppender);
appenders.put(Field.HEALTH, healthAppender);
appenders.put(Field.INSTANCE_UID, instanceUidAppender);
appenders.put(Field.FLAGS, flagsAppender);
appenders.put(Field.AGENT_DISCONNECT, agentDisconnectAppender);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.opamp.client.internal.impl.recipe.appenders;

import java.util.function.Supplier;
import opamp.proto.AgentToServer;
import opamp.proto.ComponentHealth;

/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class HealthAppender implements AgentToServerAppender {
private final Supplier<ComponentHealth> health;

public static HealthAppender create(Supplier<ComponentHealth> health) {
return new HealthAppender(health);
}

private HealthAppender(Supplier<ComponentHealth> health) {
this.health = health;
}

@Override
public void appendTo(AgentToServer.Builder builder) {
ComponentHealth currentHealth = health.get();
if (currentHealth != null) {
builder.health(currentHealth);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum Field {
SEQUENCE_NUM,
AGENT_DESCRIPTION,
CAPABILITIES,
HEALTH,
EFFECTIVE_CONFIG,
REMOTE_CONFIG_STATUS,
AGENT_DISCONNECT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@

package io.opentelemetry.opamp.client.internal.state;

import static java.util.Objects.requireNonNull;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
Expand All @@ -17,23 +16,28 @@
abstract class InMemoryState<T> implements State<T> {
private final AtomicReference<T> state = new AtomicReference<>();

public InMemoryState(T initialValue) {
if (initialValue == null) {
throw new IllegalArgumentException("The value must not be null");
}
public InMemoryState(@Nullable T initialValue) {
state.set(initialValue);
}

public void set(T value) {
/**
* Set a new state's value in a thread safe way.
*
* @param value a new value stored in the state
* @return <code>true</code> if new value is different that the previous one, <code>false</code>
* otherwise.
*/
public boolean set(T value) {
if (value == null) {
throw new IllegalArgumentException("The value must not be null");
}
state.set(value);
T previousValue = state.getAndSet(value);
return !Objects.equals(previousValue, value);
}

@Nonnull
@Nullable
@Override
public T get() {
return requireNonNull(state.get());
return state.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import java.util.Objects;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import opamp.proto.ComponentHealth;

/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
Expand Down Expand Up @@ -75,6 +77,17 @@ public Field getFieldType() {
}
}

final class Health extends InMemoryState<ComponentHealth> {
public Health(@Nullable ComponentHealth initialValue) {
super(initialValue);
}

@Override
public Field getFieldType() {
return Field.HEALTH;
}
}

final class RemoteConfigStatus extends InMemoryState<opamp.proto.RemoteConfigStatus> {

public RemoteConfigStatus(opamp.proto.RemoteConfigStatus initialValue) {
Expand Down
Loading
Loading