Skip to content

Commit f7711b8

Browse files
committed
Adding opamp builder
1 parent d05396a commit f7711b8

File tree

3 files changed

+191
-0
lines changed

3 files changed

+191
-0
lines changed

dependencyManagement/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,6 @@ dependencies {
5858
api("tools.profiler:async-profiler:4.0")
5959
api("com.blogspot.mydailyjava:weak-lock-free:0.18")
6060
api("org.agrona:agrona:1.22.0")
61+
api("com.github.f4b6a3:uuid-creator:6.0.0")
6162
}
6263
}

opamp-client/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ otelJava.moduleName.set("io.opentelemetry.contrib.opamp.client")
1313

1414
dependencies {
1515
implementation("com.squareup.okhttp3:okhttp")
16+
implementation("com.github.f4b6a3:uuid-creator")
1617
annotationProcessor("com.google.auto.value:auto-value")
1718
compileOnly("com.google.auto.value:auto-value-annotations")
1819
testImplementation("org.mockito:mockito-inline")
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package io.opentelemetry.opamp.client.internal;
2+
3+
import com.github.f4b6a3.uuid.UuidCreator;
4+
import io.opentelemetry.opamp.client.internal.impl.OpampClientImpl;
5+
import io.opentelemetry.opamp.client.internal.impl.OpampClientState;
6+
import io.opentelemetry.opamp.client.internal.request.service.HttpRequestService;
7+
import io.opentelemetry.opamp.client.internal.request.service.RequestService;
8+
import io.opentelemetry.opamp.client.internal.request.service.WebSocketRequestService;
9+
import io.opentelemetry.opamp.client.internal.state.State;
10+
import java.nio.ByteBuffer;
11+
import java.util.ArrayList;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.UUID;
16+
import opamp.proto.AgentCapabilities;
17+
import opamp.proto.AgentDescription;
18+
import opamp.proto.AnyValue;
19+
import opamp.proto.KeyValue;
20+
import opamp.proto.RemoteConfigStatus;
21+
22+
/**
23+
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
24+
* any time.
25+
*
26+
* <p>Builds an {@link OpampClient} instance.
27+
*/
28+
public final class OpampClientBuilder {
29+
private final Map<String, String> identifyingAttributes = new HashMap<>();
30+
private final Map<String, String> nonIdentifyingAttributes = new HashMap<>();
31+
private byte[] instanceUid;
32+
private long capabilities = 0;
33+
private State.EffectiveConfig effectiveConfigState;
34+
private RequestService service;
35+
36+
OpampClientBuilder() {}
37+
38+
/**
39+
* Sets an implementation of a {@link RequestService} to handle the request's sending process.
40+
* There are 2 possible options, either {@link HttpRequestService} to use HTTP, or {@link
41+
* WebSocketRequestService} to use WebSocket.
42+
*
43+
* @param service The request service implementation.
44+
* @return this
45+
*/
46+
public OpampClientBuilder setRequestService(RequestService service) {
47+
this.service = service;
48+
return this;
49+
}
50+
51+
/**
52+
* Sets the Agent's <a
53+
* href="https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agenttoserverinstance_uid">instance_uid</a>
54+
* value. A random one is generated by default.
55+
*
56+
* @param value The AgentToServer.instance_uid value.
57+
* @return this
58+
*/
59+
public OpampClientBuilder setInstanceUid(byte[] value) {
60+
this.instanceUid = value;
61+
return this;
62+
}
63+
64+
/**
65+
* Sets a string attribute into the <a
66+
* href="https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agentdescriptionidentifying_attributes">identifying_attributes</a>
67+
* field.
68+
*
69+
* @param key The attribute key.
70+
* @param value The attribute value.
71+
* @return this
72+
*/
73+
public OpampClientBuilder setIdentifyingAttribute(String key, String value) {
74+
identifyingAttributes.put(key, value);
75+
return this;
76+
}
77+
78+
/**
79+
* Sets an attribute into the <a
80+
* href="https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agentdescriptionnon_identifying_attributes">non_identifying_attributes</a>
81+
* field.
82+
*
83+
* @param key The attribute key
84+
* @param value The attribute value.
85+
* @return this
86+
*/
87+
public OpampClientBuilder setNonIdentifyingAttribute(String key, String value) {
88+
nonIdentifyingAttributes.put(key, value);
89+
return this;
90+
}
91+
92+
/**
93+
* Adds the AcceptsRemoteConfig and ReportsRemoteConfig capabilities to the Client so that the
94+
* Server can offer remote config values as explained <a
95+
* href="https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agentdescriptionidentifying_attributes">here</a>.
96+
*
97+
* @return this
98+
*/
99+
public OpampClientBuilder enableRemoteConfig() {
100+
capabilities =
101+
capabilities
102+
| AgentCapabilities.AgentCapabilities_AcceptsRemoteConfig.getValue()
103+
| AgentCapabilities.AgentCapabilities_ReportsRemoteConfig.getValue();
104+
return this;
105+
}
106+
107+
/**
108+
* Adds the ReportsEffectiveConfig capability to the Client so that the Server expects the
109+
* Client's effective config report, as explained <a
110+
* href="https://github.com/open-telemetry/opamp-spec/blob/main/specification.md#agentdescriptionidentifying_attributes">here</a>.
111+
*
112+
* @return this
113+
*/
114+
public OpampClientBuilder enableEffectiveConfigReporting() {
115+
capabilities =
116+
capabilities | AgentCapabilities.AgentCapabilities_ReportsEffectiveConfig.getValue();
117+
return this;
118+
}
119+
120+
/**
121+
* Sets the effective config state implementation. It should call {@link
122+
* State.EffectiveConfig#notifyUpdate()} whenever it has changes that have not been sent to the
123+
* server.
124+
*
125+
* @param effectiveConfigState The state implementation.
126+
* @return this
127+
*/
128+
public OpampClientBuilder setEffectiveConfigState(State.EffectiveConfig effectiveConfigState) {
129+
this.effectiveConfigState = effectiveConfigState;
130+
return this;
131+
}
132+
133+
public OpampClient build() {
134+
if (service == null) {
135+
throw new NullPointerException(
136+
"The request service is not set. You must provide it by calling setRequestService()");
137+
}
138+
List<KeyValue> protoIdentifyingAttributes = new ArrayList<>();
139+
List<KeyValue> protoNonIdentifyingAttributes = new ArrayList<>();
140+
identifyingAttributes.forEach(
141+
(key, value) -> protoIdentifyingAttributes.add(createKeyValue(key, value)));
142+
nonIdentifyingAttributes.forEach(
143+
(key, value) -> protoNonIdentifyingAttributes.add(createKeyValue(key, value)));
144+
if (instanceUid == null) {
145+
instanceUid = createRandomInstanceUid();
146+
}
147+
if (effectiveConfigState == null) {
148+
effectiveConfigState = createEffectiveConfigNoop();
149+
}
150+
OpampClientState state =
151+
new OpampClientState(
152+
new State.RemoteConfigStatus(new RemoteConfigStatus.Builder().build()),
153+
new State.SequenceNum(1L),
154+
new State.AgentDescription(
155+
new AgentDescription.Builder()
156+
.identifying_attributes(protoIdentifyingAttributes)
157+
.non_identifying_attributes(protoNonIdentifyingAttributes)
158+
.build()),
159+
new State.Capabilities(capabilities),
160+
new State.InstanceUid(instanceUid),
161+
new State.Flags(0L),
162+
effectiveConfigState);
163+
return OpampClientImpl.create(service, state);
164+
}
165+
166+
private State.EffectiveConfig createEffectiveConfigNoop() {
167+
return new State.EffectiveConfig() {
168+
@Override
169+
public opamp.proto.EffectiveConfig get() {
170+
return null;
171+
}
172+
};
173+
}
174+
175+
private KeyValue createKeyValue(String key, String value) {
176+
return new KeyValue.Builder()
177+
.key(key)
178+
.value(new AnyValue.Builder().string_value(value).build())
179+
.build();
180+
}
181+
182+
public static byte[] createRandomInstanceUid() {
183+
UUID uuid = UuidCreator.getTimeOrderedEpoch();
184+
ByteBuffer buffer = ByteBuffer.allocate(16);
185+
buffer.putLong(uuid.getMostSignificantBits());
186+
buffer.putLong(uuid.getLeastSignificantBits());
187+
return buffer.array();
188+
}
189+
}

0 commit comments

Comments
 (0)