Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static OpenTelemetryConfigurationModel getConfigurationModel() {
}

@VisibleForTesting
static void reset() {
public static void reset() {
configurationModel = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
package com.splunk.opentelemetry.opamp;

import static io.opentelemetry.opamp.client.internal.request.service.HttpRequestService.DEFAULT_DELAY_BETWEEN_RETRIES;
import static io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil.getConfig;
import static io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil.getResource;
import static java.util.logging.Level.WARNING;

import com.google.auto.service.AutoService;
import com.splunk.opentelemetry.opamp.effectiveconfig.EffectiveConfigReporter;
import com.splunk.opentelemetry.opamp.effectiveconfig.UpdatableEffectiveConfigState;
import com.splunk.opentelemetry.profiler.ProfilingSupervisor;
import io.opentelemetry.javaagent.extension.AgentListener;
import io.opentelemetry.opamp.client.OpampClient;
Expand All @@ -31,7 +32,6 @@
import io.opentelemetry.opamp.client.internal.request.service.HttpRequestService;
import io.opentelemetry.opamp.client.internal.response.MessageData;
import io.opentelemetry.opamp.client.internal.state.State;
import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import java.io.IOException;
Expand All @@ -55,18 +55,20 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetr
}

Resource resource = getResource(autoConfiguredOpenTelemetrySdk);
EffectiveConfigFactory effectiveConfigFactory =
createEffectiveConfigFactory(autoConfiguredOpenTelemetrySdk);
State.EffectiveConfig effectiveConfig = buildEffectiveConfig(effectiveConfigFactory);
UpdatableEffectiveConfigState effectiveConfigState = new UpdatableEffectiveConfigState();
EffectiveConfigReporter effectiveConfigReporter =
EffectiveConfigReporter.create(autoConfiguredOpenTelemetrySdk, effectiveConfigState);
effectiveConfigReporter.reportEffectiveConfigIfChanged();

ServerToAgentMessageHandler serverToAgentMessageHandler =
new ServerToAgentMessageHandler(ProfilingSupervisor.SUPPLIER.get());
new ServerToAgentMessageHandler(
ProfilingSupervisor.SUPPLIER.get(), effectiveConfigReporter);

OpampClient client =
startOpampClient(
opampClientConfiguration,
resource,
effectiveConfig,
effectiveConfigState,
new OpampClient.Callbacks() {
@Override
public void onConnect(OpampClient opampClient) {
Expand Down Expand Up @@ -108,13 +110,6 @@ public int order() {
return Integer.MAX_VALUE;
}

private EffectiveConfigFactory createEffectiveConfigFactory(AutoConfiguredOpenTelemetrySdk sdk) {
if (AutoConfigureUtil.isDeclarativeConfig(sdk)) {
return new DeclarativeEffectiveConfigFileFactory();
}
return new EnvVarsEffectiveConfigFileFactory(getConfig(sdk));
}

static OpampClient startOpampClient(
OpampClientConfiguration opampClientConfiguration,
Resource resource,
Expand Down Expand Up @@ -146,15 +141,6 @@ static OpampClient startOpampClient(
return builder.build(callbacks);
}

static State.EffectiveConfig buildEffectiveConfig(EffectiveConfigFactory effectiveConfigFactory) {
return new State.EffectiveConfig() {
@Override
public opamp.proto.EffectiveConfig get() {
return new opamp.proto.EffectiveConfig(effectiveConfigFactory.createEffectiveConfigMap());
}
};
}

private static ComponentHealth createInitialHealthReport() {
Instant now = Instant.now();
long nowNanos = now.getEpochSecond() * 1_000_000_000L + now.getNano();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;

import com.google.common.annotations.VisibleForTesting;
import com.splunk.opentelemetry.opamp.effectiveconfig.EffectiveConfigReporter;
import com.splunk.opentelemetry.profiler.ProfilerConfiguration;
import com.splunk.opentelemetry.profiler.ProfilerDeclarativeConfigurationFactory;
import com.splunk.opentelemetry.profiler.ProfilingSupervisor;
Expand All @@ -28,7 +29,9 @@
import java.io.ByteArrayInputStream;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import okio.ByteString;
import opamp.proto.AgentConfigFile;
import opamp.proto.AgentRemoteConfig;
import opamp.proto.RemoteConfigStatus;
Expand All @@ -40,10 +43,13 @@ public class RemoteConfigProcessor {
private static final String REMOTE_CONFIG_FILE_NAME = "splunk.remote.config";
private static final String PROFILING_NODE_NAME = "profiling";

public ProfilingSupervisor profilingSupervisor;
private final ProfilingSupervisor profilingSupervisor;
private final EffectiveConfigReporter effectiveConfigReporter;

public RemoteConfigProcessor(ProfilingSupervisor profilingSupervisor) {
public RemoteConfigProcessor(
ProfilingSupervisor profilingSupervisor, EffectiveConfigReporter effectiveConfigReporter) {
this.profilingSupervisor = Objects.requireNonNull(profilingSupervisor);
this.effectiveConfigReporter = Objects.requireNonNull(effectiveConfigReporter);
}

public void applyConfig(AgentRemoteConfig remoteConfig, OpampClient opampClient) {
Expand All @@ -60,39 +66,69 @@ public void applyConfig(AgentRemoteConfig remoteConfig, OpampClient opampClient)
return;
}

DeclarativeConfigProperties remoteConfigProperties = toDeclarativeConfigProperties(configFile);
DeclarativeConfigProperties splunkDistributionConfigProperties =
remoteConfigProperties
.getStructured("distribution", empty())
.getStructured("splunk", empty());

// Update profiler configuration only when profiling node exists
if (splunkDistributionConfigProperties.getPropertyKeys().contains(PROFILING_NODE_NAME)) {
DeclarativeConfigProperties profilingConfigProperties =
splunkDistributionConfigProperties.getStructured(PROFILING_NODE_NAME, empty());
ProfilerConfiguration profilingConfig =
ProfilerDeclarativeConfigurationFactory.create(profilingConfigProperties);
// TODO: should be merged with current profiling config. Probably we will need profiler
// configuration refactoring and some listeners implemented for profiler configuration
// changes. For POC use this temporary solution
if (profilingConfig.isEnabled()) {
profilingSupervisor.requestStartProfiling();
} else {
profilingSupervisor.requestStopProfiling();
try {
DeclarativeConfigProperties remoteConfigProperties =
toDeclarativeConfigProperties(configFile);
DeclarativeConfigProperties distributionRemoteConfigProperties =
remoteConfigProperties
.getStructured("distribution", empty())
.getStructured("splunk", empty());

// Update profiler configuration only when profiling node exists
if (distributionRemoteConfigProperties.getPropertyKeys().contains(PROFILING_NODE_NAME)) {
ProfilerConfiguration receivedProfilerConfig =
ProfilerDeclarativeConfigurationFactory.create(
distributionRemoteConfigProperties.getStructured(PROFILING_NODE_NAME, empty()));

ProfilerConfiguration currentProfilerConfiguration = ProfilerConfiguration.SUPPLIER.get();
ProfilerConfiguration updatedProfilerConfig =
currentProfilerConfiguration.toBuilder()
.setEnabled(receivedProfilerConfig.isEnabled())
.setCallStackInterval(receivedProfilerConfig.getCallStackInterval())
.build();

if (!currentProfilerConfiguration.equals(updatedProfilerConfig)) {
ProfilerConfiguration.SUPPLIER.configure(updatedProfilerConfig);
profilingSupervisor.requestReinitializeProfiling();
}
}

// Confirm to the OpAMP Server that remote config has been applied.
reportRemoteConfigStatus(
remoteConfig.config_hash,
RemoteConfigStatuses.RemoteConfigStatuses_APPLIED,
"",
opampClient);

} catch (Exception e) {
logger.log(Level.WARNING, "Remote config not applied due to exception", e);
reportRemoteConfigStatus(
remoteConfig.config_hash,
RemoteConfigStatuses.RemoteConfigStatuses_FAILED,
"Exception occurred: " + e.getMessage(),
opampClient);
}

// Confirm to the OpAMP Server that remote config has been applied.
opampClient.setRemoteConfigStatus(
new RemoteConfigStatus.Builder()
.last_remote_config_hash(remoteConfig.config_hash)
.status(RemoteConfigStatuses.RemoteConfigStatuses_APPLIED)
.build());
// TODO: Maybe should be postponed after profiler is enabled/disabled?
effectiveConfigReporter.reportEffectiveConfigIfChanged();
}

@VisibleForTesting
static DeclarativeConfigProperties toDeclarativeConfigProperties(AgentConfigFile configFile) {
return DeclarativeConfiguration.toConfigProperties(
new ByteArrayInputStream(configFile.body.toByteArray()));
}

private void reportRemoteConfigStatus(
ByteString configHash,
RemoteConfigStatuses status,
String errorMessage,
OpampClient opampClient) {
opampClient.setRemoteConfigStatus(
new RemoteConfigStatus.Builder()
.last_remote_config_hash(configHash)
.error_message(errorMessage)
.status(status)
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@
package com.splunk.opentelemetry.opamp;

import com.google.common.annotations.VisibleForTesting;
import com.splunk.opentelemetry.opamp.effectiveconfig.EffectiveConfigReporter;
import com.splunk.opentelemetry.profiler.ProfilingSupervisor;
import io.opentelemetry.opamp.client.OpampClient;
import io.opentelemetry.opamp.client.internal.response.MessageData;

public class ServerToAgentMessageHandler {
private final RemoteConfigProcessor remoteConfigProcessor;

public ServerToAgentMessageHandler(ProfilingSupervisor profilingSupervisor) {
this(new RemoteConfigProcessor(profilingSupervisor));
public ServerToAgentMessageHandler(
ProfilingSupervisor profilingSupervisor, EffectiveConfigReporter effectiveConfigReporter) {
this(new RemoteConfigProcessor(profilingSupervisor, effectiveConfigReporter));
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp;
package com.splunk.opentelemetry.opamp.effectiveconfig;

import com.google.common.annotations.VisibleForTesting;
import com.splunk.opentelemetry.opamp.DeclarativeConfigurationInterceptor;
import com.splunk.opentelemetry.profiler.ProfilerConfiguration;
import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration;
import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingDeclarativeConfiguration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp;
package com.splunk.opentelemetry.opamp.effectiveconfig;

import java.time.Duration;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp;
package com.splunk.opentelemetry.opamp.effectiveconfig;

import static java.nio.charset.StandardCharsets.UTF_8;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp.effectiveconfig;

import static io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil.getConfig;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.annotations.VisibleForTesting;
import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import java.util.HashMap;
import java.util.Map;
import okio.ByteString;
import opamp.proto.AgentConfigFile;
import opamp.proto.AgentConfigMap;

public class EffectiveConfigReporter {
private final UpdatableEffectiveConfigState effectiveConfigState;
private final EffectiveConfigFactory effectiveConfigFactory;
private String lastReportedConfigContent;

@VisibleForTesting
EffectiveConfigReporter(
EffectiveConfigFactory effectiveConfigFactory,
UpdatableEffectiveConfigState effectiveConfigState) {
this.effectiveConfigFactory = effectiveConfigFactory;
this.effectiveConfigState = effectiveConfigState;
}

public static EffectiveConfigReporter create(
AutoConfiguredOpenTelemetrySdk sdk, UpdatableEffectiveConfigState effectiveConfigState) {
return new EffectiveConfigReporter(createEffectiveConfigFactory(sdk), effectiveConfigState);
}

public boolean reportEffectiveConfigIfChanged() {
// Detect if effectiveConfig changed and needs to be reported
String configContent = effectiveConfigFactory.createEffectiveConfigContent();
if (configContent.equals(lastReportedConfigContent)) {
return false;
}

Map<String, AgentConfigFile> configMap = new HashMap<>();
AgentConfigFile configFile =
new AgentConfigFile(
new ByteString(configContent.getBytes(UTF_8)), effectiveConfigFactory.getContentType());
configMap.put(effectiveConfigFactory.getFileName(), configFile);

effectiveConfigState.set(new AgentConfigMap(configMap));
lastReportedConfigContent = configContent;

return true;
}

private static EffectiveConfigFactory createEffectiveConfigFactory(
AutoConfiguredOpenTelemetrySdk sdk) {
if (AutoConfigureUtil.isDeclarativeConfig(sdk)) {
return new DeclarativeEffectiveConfigFileFactory();
}
return new EnvVarsEffectiveConfigFileFactory(getConfig(sdk));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp;
package com.splunk.opentelemetry.opamp.effectiveconfig;

import com.splunk.opentelemetry.profiler.ProfilerConfiguration;
import com.splunk.opentelemetry.profiler.ProfilerEnvVarsConfigurationFactory;
import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration;
import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingEnvVarsConfiguration;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
Expand Down Expand Up @@ -49,8 +48,7 @@ public String createEffectiveConfigContent() {
}

private void addSplunkEnvVars(EffectiveConfigBuilder builder) {
ProfilerConfiguration profilerConfiguration =
ProfilerEnvVarsConfigurationFactory.create(config);
ProfilerConfiguration profilerConfiguration = ProfilerConfiguration.SUPPLIER.get();
SnapshotProfilingConfiguration snapshotConfiguration =
new SnapshotProfilingEnvVarsConfiguration(config);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Splunk Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.splunk.opentelemetry.opamp.effectiveconfig;

import io.opentelemetry.opamp.client.internal.state.State;
import opamp.proto.AgentConfigMap;

public class UpdatableEffectiveConfigState extends State.EffectiveConfig {
private AgentConfigMap agentConfigMap;

public void set(AgentConfigMap configMap) {
agentConfigMap = configMap;
notifyUpdate();
}

@Override
public opamp.proto.EffectiveConfig get() {
return new opamp.proto.EffectiveConfig(agentConfigMap);
}
}
Loading
Loading