Skip to content

Commit

Permalink
support install Otel agent in Sermant
Browse files Browse the repository at this point in the history
Signed-off-by: lilai <[email protected]>
  • Loading branch information
lilai23 committed Dec 17, 2024
1 parent 214a423 commit 63af395
Show file tree
Hide file tree
Showing 21 changed files with 892 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ agent.config.enhancedClassesOutputPath=
# Enable the host service instance class to be loaded by the thread context classloader during interceptor execution. If enabled, the host class is loaded by the context classloader during interceptor execution for service governance logic use. The default value is true.
agent.config.useContextLoader=true
# List of class prefixes that need be ignored when bytecode enhancement is performed.
agent.config.ignoredPrefixes=io.sermant
agent.config.ignoredPrefixes=io.sermant,io.opentelemetry
# List of interfaces that need to be ignored when bytecode enhancement is used to search for a class. If all implementation classes of an interface do not want to be bytecode enhanced, you can configure this configuration item
agent.config.ignoredInterfaces=org.springframework.cglib.proxy.Factory
# Specifies which classes in the plugins are allowed to be bytecode enhanced (classes in the plugins are not allowed to be bytecode enhanced by default)
Expand All @@ -21,6 +21,12 @@ agent.config.preFilter.enable=false
agent.config.preFilter.path=
# File name of unmatched class name, the default file is 'unmatched_class_name.txt'
agent.config.preFilter.file=
# External agent injection
agent.config.externalAgent.injection=false
# External agent name, OTEL is tested and supported. Other agents need to be tested by developers
agent.config.externalAgent.name=OTEL
# File of external agent, example: /user/opentelemetry-javaagent.jar
agent.config.externalAgent.file=
#============================= core service configuration =============================#
# Heartbeat service switch
agent.service.heartbeat.enable=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ agent.config.enhancedClassesOutputPath=
# Enable the host service instance class to be loaded by the thread context classloader during interceptor execution. If enabled, the host class is loaded by the context classloader during interceptor execution for service governance logic use. The default value is true.
agent.config.useContextLoader=true
# List of class prefixes that need be ignored when bytecode enhancement is performed.
agent.config.ignoredPrefixes=io.sermant
agent.config.ignoredPrefixes=io.sermant,io.opentelemetry
# List of interfaces that need to be ignored when bytecode enhancement is used to search for a class. If all implementation classes of an interface do not want to be bytecode enhanced, you can configure this configuration item
agent.config.ignoredInterfaces=org.springframework.cglib.proxy.Factory
# Specifies which classes in the plugins are allowed to be bytecode enhanced (classes in the plugins are not allowed to be bytecode enhanced by default)
Expand All @@ -21,6 +21,12 @@ agent.config.preFilter.enable=false
agent.config.preFilter.path=
# File name of unmatched class name, the default file is 'unmatched_class_name.txt'
agent.config.preFilter.file=
# External agent injection
agent.config.externalAgent.injection=false
# External agent name, OTEL is tested and supported. Other agents need to be tested by developers
agent.config.externalAgent.name=OTEL
# File of external agent, example: /user/opentelemetry-javaagent.jar
agent.config.externalAgent.file=
#============================= core service configuration =============================#
# Heartbeat service switch
agent.service.heartbeat.enable=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
package io.sermant.core;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.command.CommandProcessor;
import io.sermant.core.common.AgentType;
import io.sermant.core.common.BootArgsIndexer;
import io.sermant.core.common.CommonConstant;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.config.ConfigManager;
import io.sermant.core.event.EventManager;
import io.sermant.core.event.collector.FrameworkEventCollector;
import io.sermant.core.ext.ExternalAgentManager;
import io.sermant.core.notification.NotificationInfo;
import io.sermant.core.notification.NotificationManager;
import io.sermant.core.notification.SermantNotificationType;
Expand All @@ -33,6 +35,7 @@
import io.sermant.core.plugin.agent.ByteEnhanceManager;
import io.sermant.core.plugin.agent.adviser.AdviserInterface;
import io.sermant.core.plugin.agent.adviser.AdviserScheduler;
import io.sermant.core.plugin.agent.config.AgentConfig;
import io.sermant.core.plugin.agent.info.EnhancementManager;
import io.sermant.core.plugin.agent.template.DefaultAdviser;
import io.sermant.core.service.ServiceManager;
Expand Down Expand Up @@ -136,6 +139,16 @@ public static void install(String artifact, Map<String, Object> argsMap, Instrum
if (NotificationManager.isEnable()) {
NotificationManager.doNotify(new NotificationInfo(SermantNotificationType.LOAD_COMPLETE, null));
}

// cache instrumentation
CommandProcessor.cacheInstrumentation(instrumentation);

// install OpenTelemetry Agent
AgentConfig agentConfig = ConfigManager.getConfig(AgentConfig.class);
if (agentConfig.isExternalAgentInjection()) {
ExternalAgentManager.handleAgentInstallation(false, agentConfig.getExternalAgentName(),
agentConfig.getExternalAgentFile(), null, instrumentation);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ public enum Command {
/**
* Enhancement query instruction
*/
CHECK_ENHANCEMENT("CHECK-ENHANCEMENT");
CHECK_ENHANCEMENT("CHECK-ENHANCEMENT"),

/**
* Install external agent instruction
*/
INSTALL_EXTERNAL_AGENT("INSTALL-EXTERNAL-AGENT");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.utils.StringUtils;

import java.lang.instrument.Instrumentation;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
Expand All @@ -41,12 +42,15 @@ public class CommandProcessor {

private static final String COMMAND = "command";

private static Instrumentation instrumentation;

static {
COMMAND_EXECUTOR_MAP.put(Command.INSTALL_PLUGINS.getValue(), new PluginsInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_AGENT.getValue(), new AgentUnInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UNINSTALL_PLUGINS.getValue(), new PluginsUnInstallCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.UPDATE_PLUGINS.getValue(), new PluginsUpdateCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.CHECK_ENHANCEMENT.getValue(), new CheckEnhancementsCommandExecutor());
COMMAND_EXECUTOR_MAP.put(Command.INSTALL_EXTERNAL_AGENT.getValue(), new ExternalAgentInstallCommandExecutor());
}

/**
Expand Down Expand Up @@ -81,4 +85,22 @@ public static void process(Map<String, String> agentArgsMap) {
DynamicAgentArgsManager.refreshAgentArgs(agentArgsMap);
commandExecutor.execute(commandArgs);
}

/**
* cache instrumentation for dynamic agent installation
*
* @param inst instrumentation
*/
public static void cacheInstrumentation(Instrumentation inst) {
instrumentation = inst;
}

/**
* get instrumentation for dynamic agent installation
*
* @return instrumentation
*/
public static Instrumentation getInstrumentation() {
return instrumentation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,13 @@ public static void refreshAgentArgs(Map<String, String> newAgentArgs) {
public static String getAgentArg(String key) {
return AGENT_ARGS.get(key);
}

/**
* get AGENT_ARGS map
*
* @return dynamical args
*/
public static Map<String, String> getAgentArgsMap() {
return AGENT_ARGS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2024-2024 Sermant Authors. All rights reserved.
*
* 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 io.sermant.core.command;

import io.sermant.core.common.LoggerFactory;
import io.sermant.core.event.collector.FrameworkEventCollector;
import io.sermant.core.event.collector.FrameworkEventDefinitions;
import io.sermant.core.ext.ExternalAgentManager;
import io.sermant.core.utils.StringUtils;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.logging.Logger;

/**
* The command executor of external agent installation
*
* @author lilai
* @since 2024-12-14
*/
public class ExternalAgentInstallCommandExecutor implements CommandExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger();

private static final String AGENT_FILE_KEY = "AGENT_FILE";

@Override
public void execute(String args) {
Map<String, String> agentArgsMap = DynamicAgentArgsManager.getAgentArgsMap();
String agentPath = agentArgsMap.get(AGENT_FILE_KEY);
if (StringUtils.isEmpty(agentPath)) {
LOGGER.severe("Failed to install external agent: AGENT_FILE in command args is empty");
return;
}

try {
ExternalAgentManager.handleAgentInstallation(true, args, agentPath, agentArgsMap,
CommandProcessor.getInstrumentation());
FrameworkEventCollector.getInstance()
.collectdHotPluggingEvent(FrameworkEventDefinitions.EXTERNAL_AGENT_INSTALL,
"Hot plugging command[INSTALL-EXTERNAL-AGENT] has been processed");
} catch (IOException | NoSuchMethodException | ClassNotFoundException | InvocationTargetException
| IllegalAccessException e) {
LOGGER.severe("Failed to install external agent: " + e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,20 @@ public void collectdHotPluggingEvent(FrameworkEventDefinitions frameworkEventDef
frameworkEventDefinitions.getEventType(),
new EventInfo(frameworkEventDefinitions.getName(), description)));
}

/**
* Collect OpenTelemetry Agent start event
*
* @param startMethod the method name OpenTelemetry Agent starts by
*/
public void collectOtelStartEvent(String startMethod) {
if (!eventConfig.isEnable()) {
return;
}
String description = "OpenTelemetry Agent starts by " + startMethod;
offerEvent(new Event(FrameworkEventDefinitions.OTEL_START.getScope(),
FrameworkEventDefinitions.OTEL_START.getEventLevel(),
FrameworkEventDefinitions.OTEL_START.getEventType(),
new EventInfo(FrameworkEventDefinitions.OTEL_START.getName(), description)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,17 @@ public enum FrameworkEventDefinitions {
/**
* Sermant plugin update event definition
*/
SERMANT_PLUGIN_UPDATE("SERMANT_PLUGIN_UPDATE", EventType.OPERATION, EventLevel.NORMAL);
SERMANT_PLUGIN_UPDATE("SERMANT_PLUGIN_UPDATE", EventType.OPERATION, EventLevel.NORMAL),

/**
* External agent install event definition
*/
EXTERNAL_AGENT_INSTALL("EXTERNAL_AGENT_INSTALL", EventType.OPERATION, EventLevel.NORMAL),

/**
* OpenTelemetry agent start event definition
*/
OTEL_START("OTEL_START", EventType.OPERATION, EventLevel.NORMAL);

/**
* event name
Expand Down
Loading

0 comments on commit 63af395

Please sign in to comment.