Log Levels View
* fetch and display loglevels * change log levels for packages * clean up logs * address review comments * switch the CONNECT_TO_LS key * Avoid caching loggers data * add copyright headers --------- Co-authored-by: V Udayani <vudayani@vudayaniSMD6M.vmware.com>
This commit is contained in:
@@ -33,4 +33,8 @@ public interface ActuatorConnection {
|
||||
Map<?, ?> getStartup() throws IOException;
|
||||
|
||||
String getLiveMetrics(String metricName, String tags) throws IOException;
|
||||
|
||||
String getLoggers() throws IOException;
|
||||
|
||||
String configureLogLevel(Map<String, String> args) throws IOException;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,21 @@ public class HttpActuatorConnection implements ActuatorConnection {
|
||||
return restTemplate.getForObject("/beans", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoggers() throws IOException {
|
||||
return restTemplate.getForObject("/loggers", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String configureLogLevel(Map<String, String> args) throws IOException {
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromPath("/loggers/"+args.get("packageName"));
|
||||
if (args != null) {
|
||||
uriBuilder.queryParam("configuredLevel", args.get("configuredLevel"));
|
||||
}
|
||||
String url = actuatorUrl + uriBuilder.toUriString();
|
||||
return restTemplate.postForObject(URI.create(url), null, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLiveMetrics(String metricName, String tags) throws IOException {
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromPath("/metrics/"+metricName);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
/**
|
||||
* @author Udayani V
|
||||
*/
|
||||
public class LoggerInfo {
|
||||
|
||||
private String configuredLevel;
|
||||
|
||||
private String effectiveLevel;
|
||||
|
||||
public String getConfiguredLevel() {
|
||||
return configuredLevel;
|
||||
}
|
||||
public String getEffectiveLevel() {
|
||||
return effectiveLevel;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* @author Udayani V
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Loggers {
|
||||
|
||||
private List<String> levels;
|
||||
private Map<String, LoggerInfo> loggers;
|
||||
|
||||
public List<String> getLevels() {
|
||||
return levels;
|
||||
}
|
||||
|
||||
public Map<String, LoggerInfo> getLoggers() {
|
||||
return loggers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -43,6 +44,8 @@ public class SpringProcessCommandHandler {
|
||||
private static final String COMMAND_LIST_CONNECTED = "sts/livedata/listConnected";
|
||||
private static final String COMMAND_GET_METRICS = "sts/livedata/get/metrics";
|
||||
private static final String COMMAND_GET_REFRESH_METRICS = "sts/livedata/refresh/metrics";
|
||||
private static final String COMMAND_GET_LOGGERS = "sts/livedata/getLoggers";
|
||||
private static final String COMMAND_CONFIGURE_LOGLEVEL = "sts/livedata/configure/logLevel";
|
||||
|
||||
private final SpringProcessConnectorService connectorService;
|
||||
private final SpringProcessConnectorLocal localProcessConnector;
|
||||
@@ -88,6 +91,16 @@ public class SpringProcessCommandHandler {
|
||||
return refreshMetrics(params);
|
||||
});
|
||||
log.info("Registered command handler: {}",COMMAND_GET_METRICS);
|
||||
|
||||
server.onCommand(COMMAND_GET_LOGGERS, (params) -> {
|
||||
return getLoggers(params);
|
||||
});
|
||||
log.info("Registered command handler: {}",COMMAND_GET_LOGGERS);
|
||||
|
||||
server.onCommand(COMMAND_CONFIGURE_LOGLEVEL, (params) -> {
|
||||
return configureLogLevel(params);
|
||||
});
|
||||
log.info("Registered command handler: {}",COMMAND_CONFIGURE_LOGLEVEL);
|
||||
|
||||
server.onCommand(COMMAND_LIST_CONNECTED, (params) -> {
|
||||
List<LiveProcessSummary> result = new ArrayList<>();
|
||||
@@ -320,4 +333,34 @@ public class SpringProcessCommandHandler {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
||||
private CompletableFuture<Object> getLoggers(ExecuteCommandParams params) {
|
||||
SpringProcessLoggersData loggersData = null;
|
||||
SpringProcessParams springProcessParams = new SpringProcessParams();
|
||||
springProcessParams.setProcessKey(getProcessKey(params));
|
||||
springProcessParams.setEndpoint(getArgumentByKey(params, "endpoint"));
|
||||
if (springProcessParams.getProcessKey() != null) {
|
||||
loggersData = connectorService.getLoggers(springProcessParams);
|
||||
return CompletableFuture.completedFuture(loggersData);
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(loggersData);
|
||||
}
|
||||
|
||||
private CompletableFuture<Object> configureLogLevel(ExecuteCommandParams params) {
|
||||
Map<String, String> args = new HashMap<>();
|
||||
args.put("packageName", getArgumentByKey(params, "packageName"));
|
||||
args.put("configuredLevel", getArgumentByKey(params, "configuredLevel"));
|
||||
args.put("effectiveLevel", getArgumentByKey(params, "effectiveLevel"));
|
||||
SpringProcessParams springProcessParams = new SpringProcessParams();
|
||||
springProcessParams.setProcessKey(getProcessKey(params));
|
||||
springProcessParams.setArgs(args);
|
||||
|
||||
if (springProcessParams.getProcessKey() != null) {
|
||||
connectorService.configureLogLevel(springProcessParams);
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -29,4 +31,6 @@ public interface SpringProcessConnector {
|
||||
String getProcessName();
|
||||
SpringProcessGcPausesMetricsLiveData refreshGcPausesMetrics(SpringProcessLiveData current, String metricName, String tags) throws Exception;
|
||||
SpringProcessMemoryMetricsLiveData refreshMemoryMetrics(SpringProcessLiveData current, String metricName, String tags) throws Exception;
|
||||
SpringProcessLoggersData getLoggers(SpringProcessLiveData currentData) throws Exception;
|
||||
SpringProcessUpdatedLogLevelData configureLogLevel(SpringProcessLiveData currentData, Map<String, String> args) throws Exception;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SpringProcessConnectorOverHttp implements SpringProcessConnector {
|
||||
|
||||
private final ProcessType processType;
|
||||
@@ -157,6 +159,49 @@ public class SpringProcessConnectorOverHttp implements SpringProcessConnector {
|
||||
|
||||
throw new Exception("no live memory metrics data received, lets try again");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SpringProcessLoggersData getLoggers(SpringProcessLiveData currentData)
|
||||
throws Exception {
|
||||
if (actuatorConnection != null) {
|
||||
SpringProcessLoggersData loggersData = new SpringProcessLiveDataExtractorOverHttp().retrieveLoggersData(getProcessType(), actuatorConnection, processID, processName, currentData);
|
||||
|
||||
if (this.processID == null) {
|
||||
this.processID = loggersData.getProcessID();
|
||||
}
|
||||
|
||||
if (this.processName == null) {
|
||||
this.processName = loggersData.getProcessName();
|
||||
}
|
||||
|
||||
if (loggersData != null && loggersData.getLoggers() != null) {
|
||||
return loggersData;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("no loggers data received, lets try again");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SpringProcessUpdatedLogLevelData configureLogLevel(SpringProcessLiveData currentData, Map<String, String> args) throws Exception {
|
||||
if (actuatorConnection != null) {
|
||||
SpringProcessUpdatedLogLevelData springProcessUpdatedLoggersData = new SpringProcessLiveDataExtractorOverHttp().configureLogLevel(getProcessType(), actuatorConnection, processID, processName, currentData, args);
|
||||
|
||||
if (this.processID == null) {
|
||||
this.processID = springProcessUpdatedLoggersData.getProcessID();
|
||||
}
|
||||
|
||||
if (this.processName == null) {
|
||||
this.processName = springProcessUpdatedLoggersData.getProcessName();
|
||||
return springProcessUpdatedLoggersData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new Exception("configure log levels failed, lets try again");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -210,6 +210,50 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
|
||||
log.error("error closing the JMX connection for: " + jmxURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringProcessLoggersData getLoggers(SpringProcessLiveData currentData) throws Exception {
|
||||
log.info("try to open JMX connection to: " + jmxURL);
|
||||
|
||||
if (jmxConnection != null) {
|
||||
try {
|
||||
SpringProcessLiveDataExtractorOverJMX springJMXConnector = new SpringProcessLiveDataExtractorOverJMX();
|
||||
|
||||
log.info("retrieve live data from: " + jmxURL);
|
||||
SpringProcessLoggersData loggersData = springJMXConnector.retrieveLoggersData(getProcessType(), jmxConnection, processID, processName, currentData);
|
||||
|
||||
if (loggersData != null) {
|
||||
return loggersData;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("exception while connecting to jmx: " + jmxURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("no loggers data received, lets try again");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringProcessUpdatedLogLevelData configureLogLevel(SpringProcessLiveData currentData, Map<String, String> args) throws Exception {
|
||||
log.info("try to open JMX connection to: " + jmxURL);
|
||||
|
||||
if (jmxConnection != null) {
|
||||
try {
|
||||
SpringProcessLiveDataExtractorOverJMX springJMXConnector = new SpringProcessLiveDataExtractorOverJMX();
|
||||
|
||||
log.info("retrieve live data from: " + jmxURL);
|
||||
SpringProcessUpdatedLogLevelData springProcessUpdatedLoggersData = springJMXConnector.configureLogLevel(getProcessType(), jmxConnection, processID, processName, currentData, args);
|
||||
|
||||
return springProcessUpdatedLoggersData;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("exception while connecting to jmx: " + jmxURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("configure log level failed, lets try again");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConnectorChangeListener(SpringProcessConnectionChangeListener listener) {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -34,6 +36,7 @@ public class SpringProcessConnectorService {
|
||||
public static final String MEMORY = "memory";
|
||||
public static final String HEAP_MEMORY = "heapMemory";
|
||||
public static final String NON_HEAP_MEMORY = "nonHeapMemory";
|
||||
private static final String LOGGERS = "loggers";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringProcessConnectorService.class);
|
||||
|
||||
@@ -292,4 +295,129 @@ public class SpringProcessConnectorService {
|
||||
private IndefiniteProgressTask getProgressTask(String prefixId, String title, String message) {
|
||||
return this.progressService.createIndefiniteProgressTask(prefixId + progressIdKey++, title, message);
|
||||
}
|
||||
|
||||
public SpringProcessLoggersData getLoggers(SpringProcessParams springProcessParams) {
|
||||
log.info("get loggers data: " + springProcessParams.getProcessKey());
|
||||
CompletableFuture<SpringProcessLoggersData> loggerData = new CompletableFuture<>();
|
||||
SpringProcessConnector connector = this.connectors.get(springProcessParams.getProcessKey());
|
||||
if (connector != null) {
|
||||
final IndefiniteProgressTask progressTask = getProgressTask(
|
||||
"spring-process-connector-service-get-loggers-data" + springProcessParams.getProcessKey(), "Loggers", null);
|
||||
getLoggersData(progressTask, springProcessParams, connector, loggerData, 0, TimeUnit.SECONDS, 0);
|
||||
try {
|
||||
return loggerData.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("Failed to fetch loggers data for the process "+ springProcessParams.getProcessKey());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void getLoggersData(IndefiniteProgressTask progressTask, SpringProcessParams springProcessParams, SpringProcessConnector connector, CompletableFuture<SpringProcessLoggersData> loggerData, long delay, TimeUnit unit, int retryNo) {
|
||||
String processKey = springProcessParams.getProcessKey();
|
||||
String endpoint = springProcessParams.getEndpoint();
|
||||
|
||||
String progressMessage = "Get loggers for Spring process: " + processKey + " - retry no: " + retryNo;
|
||||
log.info(progressMessage);
|
||||
|
||||
this.scheduler.schedule(() -> {
|
||||
|
||||
try {
|
||||
progressTask.progressEvent(progressMessage);
|
||||
if(LOGGERS.equals(endpoint)) {
|
||||
SpringProcessLoggersData loggersData = connector.getLoggers(this.liveDataProvider.getCurrent(processKey));
|
||||
|
||||
if (loggersData != null) {
|
||||
loggerData.complete(loggersData);
|
||||
this.connectedSuccess.put(processKey, true);
|
||||
}
|
||||
|
||||
}
|
||||
progressTask.done();
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
log.info("problem occured during process live data refresh", e);
|
||||
|
||||
if (retryNo < maxRetryCount && isKnownProcessKey(processKey)) {
|
||||
getLoggersData(progressTask, springProcessParams, connector, loggerData, retryDelayInSeconds, TimeUnit.SECONDS,
|
||||
retryNo + 1);
|
||||
}
|
||||
else {
|
||||
progressTask.done();
|
||||
|
||||
// Send message to client if maximum retries reached on error
|
||||
if (isKnownProcessKey(processKey)) {
|
||||
diagnosticService.diagnosticEvent(ShowMessageException
|
||||
.error("Failed to refresh live data from process " + processKey + " after retries: " + retryNo, e));
|
||||
|
||||
if (!connectedSuccess.containsKey(connector.getProcessKey())) {
|
||||
loggerData.complete(null);
|
||||
disconnectProcess(processKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
|
||||
}
|
||||
|
||||
public void configureLogLevel(SpringProcessParams springProcessParams) {
|
||||
log.info("change log level: " + springProcessParams.getProcessKey());
|
||||
|
||||
SpringProcessConnector connector = this.connectors.get(springProcessParams.getProcessKey());
|
||||
if (connector != null) {
|
||||
final IndefiniteProgressTask progressTask = getProgressTask(
|
||||
"spring-process-connector-service-configure-log-level" + springProcessParams.getProcessKey(), "Loggers", null);
|
||||
configureLogLevel(progressTask, springProcessParams, connector, 0, TimeUnit.SECONDS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureLogLevel(IndefiniteProgressTask progressTask, SpringProcessParams springProcessParams,
|
||||
SpringProcessConnector connector, long delay, TimeUnit unit, int retryNo) {
|
||||
String processKey = springProcessParams.getProcessKey();
|
||||
|
||||
String progressMessage = "configure log level for Spring process: " + processKey + " - retry no: " + retryNo;
|
||||
log.info(progressMessage);
|
||||
|
||||
this.scheduler.schedule(() -> {
|
||||
|
||||
try {
|
||||
progressTask.progressEvent(progressMessage);
|
||||
SpringProcessUpdatedLogLevelData springProcessUpdatedLoggersData = connector.configureLogLevel(this.liveDataProvider.getCurrent(processKey), springProcessParams.getArgs());
|
||||
|
||||
if(springProcessUpdatedLoggersData != null) {
|
||||
this.liveDataProvider.updateLogLevel(processKey, springProcessUpdatedLoggersData);
|
||||
this.connectedSuccess.put(processKey, true);
|
||||
}
|
||||
|
||||
progressTask.done();
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
log.info("problem occured during process live data refresh", e);
|
||||
|
||||
if (retryNo < maxRetryCount && isKnownProcessKey(processKey)) {
|
||||
configureLogLevel(progressTask, springProcessParams, connector, retryDelayInSeconds, TimeUnit.SECONDS,
|
||||
retryNo + 1);
|
||||
}
|
||||
else {
|
||||
progressTask.done();
|
||||
|
||||
// Send message to client if maximum retries reached on error
|
||||
if (isKnownProcessKey(processKey)) {
|
||||
diagnosticService.diagnosticEvent(ShowMessageException
|
||||
.error("Failed to refresh live data from process " + processKey + " after retries: " + retryNo, e));
|
||||
|
||||
if (!connectedSuccess.containsKey(connector.getProcessKey())) {
|
||||
disconnectProcess(processKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -269,6 +269,114 @@ public class SpringProcessLiveDataExtractorOverHttp {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param processType
|
||||
* @param processID if null, will be determined searching existing mbeans for that information (for remote processes via platform beans runtime name)
|
||||
* @param processName if null, will be determined searching existing mbeans for that information (for remote processes inferring the java command from the system properties)
|
||||
* @param currentData currently stored live data
|
||||
* @param metricName
|
||||
* @param tags
|
||||
*/
|
||||
public SpringProcessLoggersData retrieveLoggersData(ProcessType processType, ActuatorConnection connection, String processID, String processName,
|
||||
SpringProcessLiveData currentData) {
|
||||
|
||||
try {
|
||||
|
||||
if (processID == null) {
|
||||
processID = connection.getProcessID();
|
||||
}
|
||||
|
||||
if (processName == null) {
|
||||
Properties systemProperties = connection.getSystemProperties();
|
||||
if (systemProperties != null) {
|
||||
String javaCommand = getJavaCommand(systemProperties);
|
||||
processName = getProcessName(javaCommand);
|
||||
}
|
||||
}
|
||||
|
||||
Loggers loggers = getLoggers(connection);
|
||||
|
||||
return new SpringProcessLoggersData(
|
||||
processType,
|
||||
processName,
|
||||
processID,
|
||||
loggers
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error reading live metrics data from: " + processID + " - " + processName, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public Loggers getLoggers(ActuatorConnection connection) {
|
||||
try {
|
||||
String result = connection.getLoggers();
|
||||
|
||||
if (result instanceof String) {
|
||||
return gson.fromJson((String)result, Loggers.class);
|
||||
} else if(result != null){
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
return mapper.convertValue(result, Loggers.class);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
} catch (Exception e) {
|
||||
log.error("Error parsing loggers", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SpringProcessUpdatedLogLevelData configureLogLevel(ProcessType processType, ActuatorConnection connection, String processID, String processName,
|
||||
SpringProcessLiveData currentData, Map<String, String> args) {
|
||||
|
||||
try {
|
||||
|
||||
if (processID == null) {
|
||||
processID = connection.getProcessID();
|
||||
}
|
||||
|
||||
if (processName == null) {
|
||||
Properties systemProperties = connection.getSystemProperties();
|
||||
if (systemProperties != null) {
|
||||
String javaCommand = getJavaCommand(systemProperties);
|
||||
processName = getProcessName(javaCommand);
|
||||
}
|
||||
}
|
||||
|
||||
configureLogLevel(connection, args);
|
||||
return new SpringProcessUpdatedLogLevelData(
|
||||
processType,
|
||||
processName,
|
||||
processID,
|
||||
args.get("packageName"),
|
||||
args.get("effectiveLevel"),
|
||||
args.get("configuredLevel")
|
||||
);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error reading live metrics data from: " + processID + " - " + processName + " : "+ args.get("packageName"), e);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public void configureLogLevel(ActuatorConnection connection, Map<String, String> args) {
|
||||
try {
|
||||
connection.configureLogLevel(args);
|
||||
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
} catch (Exception e) {
|
||||
log.error("Error parsing response", e);
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private StartupMetricsModel getStartupMetrics(ActuatorConnection connection, StartupMetricsModel currentStartup) {
|
||||
if (currentStartup != null) {
|
||||
return currentStartup;
|
||||
@@ -415,7 +523,7 @@ public class SpringProcessLiveDataExtractorOverHttp {
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
} catch (Exception e) {
|
||||
log.error("Error parsing beans", e);
|
||||
log.error("Error parsing live metrics", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,124 @@ public class SpringProcessLiveDataExtractorOverJMX {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param processType
|
||||
* @param processID if null, will be determined searching existing mbeans for that information (for remote processes via platform beans runtime name)
|
||||
* @param processName if null, will be determined searching existing mbeans for that information (for remote processes inferring the java command from the system properties)
|
||||
* @param currentData currently stored live data
|
||||
*/
|
||||
public SpringProcessLoggersData retrieveLoggersData(ProcessType processType, JMXConnector jmxConnector, String processID, String processName,
|
||||
SpringProcessLiveData currentData) {
|
||||
|
||||
try {
|
||||
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
|
||||
String domain = getDomainForActuator(connection);
|
||||
|
||||
if (processID == null) {
|
||||
processID = getProcessID(connection);
|
||||
}
|
||||
|
||||
if (processName == null) {
|
||||
Properties systemProperties = getSystemProperties(connection);
|
||||
if (systemProperties != null) {
|
||||
String javaCommand = getJavaCommand(systemProperties);
|
||||
processName = getProcessName(javaCommand);
|
||||
}
|
||||
}
|
||||
|
||||
Loggers loggers = getLoggers(connection, domain);
|
||||
|
||||
return new SpringProcessLoggersData(
|
||||
processType,
|
||||
processName,
|
||||
processID,
|
||||
loggers
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error reading live metrics data from: " + processID + " - " + processName, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Loggers getLoggers(MBeanServerConnection connection, String domain) {
|
||||
|
||||
Object[] params1 = new Object[] {};
|
||||
String[] signature = new String[] {String.class.getName(), List.class.getName()};
|
||||
|
||||
try {
|
||||
Object loggersData = getActuatorDataFromOperation(connection,
|
||||
getObjectName(domain, "type=Endpoint,name=Loggers"),
|
||||
"loggers",
|
||||
params1,
|
||||
signature);
|
||||
if (loggersData instanceof String) {
|
||||
return gson.fromJson((String)loggersData, Loggers.class);
|
||||
} else if(loggersData != null){
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.convertValue(loggersData, Loggers.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SpringProcessUpdatedLogLevelData configureLogLevel(ProcessType processType, JMXConnector jmxConnector,
|
||||
String processID, String processName, SpringProcessLiveData currentData, Map<String, String> args) {
|
||||
try {
|
||||
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
|
||||
String domain = getDomainForActuator(connection);
|
||||
|
||||
if (processID == null) {
|
||||
processID = getProcessID(connection);
|
||||
}
|
||||
|
||||
if (processName == null) {
|
||||
Properties systemProperties = getSystemProperties(connection);
|
||||
if (systemProperties != null) {
|
||||
String javaCommand = getJavaCommand(systemProperties);
|
||||
processName = getProcessName(javaCommand);
|
||||
}
|
||||
}
|
||||
|
||||
changeLogLevel(connection, domain, args);
|
||||
return new SpringProcessUpdatedLogLevelData(
|
||||
processType,
|
||||
processName,
|
||||
processID,
|
||||
args.get("packageName"),
|
||||
args.get("effectiveLevel"),
|
||||
args.get("configuredLevel")
|
||||
);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error changing log level : " + processID + " - " + processName + " : "+args.get("packageName"), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void changeLogLevel(MBeanServerConnection connection, String domain, Map<String, String> args) throws Exception {
|
||||
|
||||
Object[] params = new Object[] {args.get("packageName"), args.get("configuredLevel")};
|
||||
String[] signature = new String[] {String.class.getName(), List.class.getName()};
|
||||
|
||||
try {
|
||||
getActuatorDataFromOperation(connection,
|
||||
getObjectName(domain, "type=Endpoint,name=Loggers"),
|
||||
"configureLogLevel",
|
||||
params,
|
||||
signature);
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private StartupMetricsModel getStartupMetrics(MBeanServerConnection connection, String domain, StartupMetricsModel currentStartup) {
|
||||
if (currentStartup != null) {
|
||||
return currentStartup;
|
||||
@@ -751,6 +869,4 @@ public class SpringProcessLiveDataExtractorOverJMX {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.protocol.LiveProcessLoggersSummary;
|
||||
import org.springframework.ide.vscode.commons.protocol.LiveProcessSummary;
|
||||
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
@@ -29,6 +30,7 @@ public class SpringProcessLiveDataProvider {
|
||||
private final ConcurrentMap<String, SpringProcessLiveData> liveData;
|
||||
private final ConcurrentMap<String, SpringProcessMemoryMetricsLiveData> memoryMetricsLiveData;
|
||||
private final ConcurrentMap<String, SpringProcessGcPausesMetricsLiveData> gcPausesMetricsLiveData;
|
||||
private final ConcurrentMap<String, SpringProcessLoggersData> loggersData;
|
||||
private final List<SpringProcessLiveDataChangeListener> listeners;
|
||||
private final SimpleLanguageServer server;
|
||||
|
||||
@@ -37,6 +39,7 @@ public class SpringProcessLiveDataProvider {
|
||||
this.liveData = new ConcurrentHashMap<>();
|
||||
this.memoryMetricsLiveData = new ConcurrentHashMap<>();
|
||||
this.gcPausesMetricsLiveData = new ConcurrentHashMap<>();
|
||||
this.loggersData = new ConcurrentHashMap<>();
|
||||
this.listeners = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
@@ -104,6 +107,11 @@ public class SpringProcessLiveDataProvider {
|
||||
getClient().liveProcessGcPausesMetricsDataUpdated(createGcPausesMetricsSummary(processKey, liveData));
|
||||
}
|
||||
|
||||
public void updateLogLevel(String processKey, SpringProcessUpdatedLogLevelData updatedLogLevelData) {
|
||||
getClient().liveProcessLogLevelUpdated(createUpdatedLogLevelSummary(processKey, updatedLogLevelData));
|
||||
}
|
||||
|
||||
|
||||
public void addLiveDataChangeListener(SpringProcessLiveDataChangeListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
@@ -131,6 +139,10 @@ public class SpringProcessLiveDataProvider {
|
||||
public SpringProcessGcPausesMetricsLiveData getGcPausesMetrics(String processKey) {
|
||||
return this.gcPausesMetricsLiveData.get(processKey);
|
||||
}
|
||||
|
||||
public SpringProcessLoggersData getLoggersData(String processKey) {
|
||||
return this.loggersData.get(processKey);
|
||||
}
|
||||
|
||||
public static LiveProcessSummary createProcessSummary(String processKey, SpringProcessLiveData liveData) {
|
||||
LiveProcessSummary p = new LiveProcessSummary();
|
||||
@@ -159,4 +171,11 @@ public class SpringProcessLiveDataProvider {
|
||||
return p;
|
||||
}
|
||||
|
||||
public static LiveProcessLoggersSummary createUpdatedLogLevelSummary(String processKey, SpringProcessUpdatedLogLevelData updatedLogLevelData) {
|
||||
LiveProcessLoggersSummary p = new LiveProcessLoggersSummary(updatedLogLevelData.getProcessType().jsonName(),
|
||||
processKey, updatedLogLevelData.getProcessName(), updatedLogLevelData.getProcessID(),
|
||||
updatedLogLevelData.getPackageName(), updatedLogLevelData.getEffectiveLevel(),
|
||||
updatedLogLevelData.getConfiguredLevel());
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
/**
|
||||
* @author Udayani V
|
||||
*/
|
||||
public class SpringProcessLoggersData {
|
||||
|
||||
private final ProcessType processType;
|
||||
private final String processName;
|
||||
private final String processID;
|
||||
private final Loggers loggers;
|
||||
|
||||
public SpringProcessLoggersData(ProcessType processType, String processName, String processID,
|
||||
Loggers loggers) {
|
||||
super();
|
||||
this.processType = processType;
|
||||
this.processName = processName;
|
||||
this.processID = processID;
|
||||
this.loggers = loggers;
|
||||
|
||||
}
|
||||
|
||||
public ProcessType getProcessType() {
|
||||
return processType;
|
||||
}
|
||||
|
||||
public String getProcessName() {
|
||||
return processName;
|
||||
}
|
||||
|
||||
public String getProcessID() {
|
||||
return processID;
|
||||
}
|
||||
|
||||
public Loggers getLoggers() {
|
||||
return loggers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author V Udayani
|
||||
*/
|
||||
@@ -19,7 +21,7 @@ public class SpringProcessParams {
|
||||
private String endpoint;
|
||||
private String metricName;
|
||||
private String tags;
|
||||
|
||||
private Map<String, String> args;
|
||||
public SpringProcessParams() {
|
||||
}
|
||||
|
||||
@@ -62,4 +64,12 @@ public class SpringProcessParams {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public Map<String, String> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(Map<String, String> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2023 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover.v2;
|
||||
|
||||
public class SpringProcessUpdatedLogLevelData {
|
||||
|
||||
private final ProcessType processType;
|
||||
private final String processName;
|
||||
private final String processID;
|
||||
private final String packageName;
|
||||
private final String effectiveLevel;
|
||||
private final String configuredLevel;
|
||||
|
||||
public SpringProcessUpdatedLogLevelData(ProcessType processType, String processName, String processID,
|
||||
String packageName, String effectiveLevel, String configuredLevel) {
|
||||
super();
|
||||
this.processType = processType;
|
||||
this.processName = processName;
|
||||
this.processID = processID;
|
||||
this.packageName = packageName;
|
||||
this.effectiveLevel = effectiveLevel;
|
||||
this.configuredLevel = configuredLevel;
|
||||
|
||||
}
|
||||
|
||||
public ProcessType getProcessType() {
|
||||
return processType;
|
||||
}
|
||||
|
||||
public String getProcessName() {
|
||||
return processName;
|
||||
}
|
||||
|
||||
public String getProcessID() {
|
||||
return processID;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getEffectiveLevel() {
|
||||
return effectiveLevel;
|
||||
}
|
||||
|
||||
public String getConfiguredLevel() {
|
||||
return configuredLevel;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user