fetch memory metrics for process

This commit is contained in:
V Udayani
2022-10-10 21:00:53 +05:30
committed by aboyko
parent cf228adf04
commit c6f905bd0f
19 changed files with 622 additions and 16 deletions

View File

@@ -45,6 +45,12 @@ public interface STS4LanguageClient extends LanguageClient {
@JsonNotification("sts/liveprocess/updated")
void liveProcessDataUpdated(LiveProcessSummary processKey);
@JsonNotification("sts/liveprocess/memory/metrics/updated")
void liveProcessMemoryMetricsDataUpdated(LiveProcessSummary processKey);
@JsonNotification("sts/liveprocess/gcpauses/metrics/updated")
void liveProcessGcPausesMetricsDataUpdated(LiveProcessSummary processKey);
@JsonNotification("sts/highlight")
void highlight(HighlightParams highlights);

View File

@@ -414,6 +414,15 @@ public class LanguageServerHarness {
@Override
public void liveProcessDataUpdated(LiveProcessSummary process) {
}
@Override
public void liveProcessMemoryMetricsDataUpdated(LiveProcessSummary processKey) {
}
@Override
public void liveProcessGcPausesMetricsDataUpdated(LiveProcessSummary processKey) {
}
});
}

View File

@@ -31,4 +31,8 @@ public interface ActuatorConnection {
String getMetrics(String metric, Map<String, String> tags) throws IOException;
Map<?, ?> getStartup() throws IOException;
// String getGcPausesMetrics() throws IOException;
// String getMemoryMetrics(String metricName) throws IOException;
}

View File

@@ -0,0 +1,26 @@
package org.springframework.ide.vscode.boot.java.livehover.v2;
import java.util.Arrays;
/**
* @author Udayani V
*/
public class AvailableTags {
private String tag;
private String[] values;
public String getTag() {
return tag;
}
public String[] getValues() {
return values;
}
@Override
public String toString() {
return "AvailableTags [tag=" + tag + ", values=" + Arrays.toString(values) + "]";
}
}

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
/**
* @author Udayani V
*/
public class LiveMemoryMetricsModel {
private String name;
private String description;
private Measurements[] measurements;
private String baseUnit;
private AvailableTags[] availableTags;
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Measurements[] getMeasurements() {
return measurements;
}
public String getBaseUnit() {
return baseUnit;
}
public AvailableTags[] getAvailableTags() {
return availableTags;
}
}

View File

@@ -0,0 +1,22 @@
package org.springframework.ide.vscode.boot.java.livehover.v2;
public class Measurements {
private String statistic;
private Long value;
public String getStatistic() {
return statistic;
}
public Long getValue() {
return value;
}
@Override
public String toString() {
return "Measurements [statistic=" + statistic + ", value=" + value + "]";
}
}

View File

@@ -41,6 +41,8 @@ public class SpringProcessCommandHandler {
private static final String COMMAND_DISCONNECT = "sts/livedata/disconnect";
private static final String COMMAND_GET = "sts/livedata/get";
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 final SpringProcessConnectorService connectorService;
private final SpringProcessConnectorLocal localProcessConnector;
@@ -77,6 +79,16 @@ public class SpringProcessCommandHandler {
});
log.info("Registered command handler: {}",COMMAND_GET);
server.onCommand(COMMAND_GET_METRICS, (params) -> {
return handleLiveMetricsProcessRequest(params);
});
log.info("Registered command handler: {}",COMMAND_GET_METRICS);
server.onCommand(COMMAND_GET_REFRESH_METRICS, (params) -> {
return refreshMetrics(params);
});
log.info("Registered command handler: {}",COMMAND_GET_METRICS);
server.onCommand(COMMAND_LIST_CONNECTED, (params) -> {
List<LiveProcessSummary> result = new ArrayList<>();
for (SpringProcessConnector process : connectorService.getConnectedProcesses()) {
@@ -136,8 +148,20 @@ public class SpringProcessCommandHandler {
private CompletableFuture<Object> refresh(ExecuteCommandParams params) {
String processKey = getProcessKey(params);
String endpoint = getArgumentByKey(params, "endpoint");
if (processKey != null) {
connectorService.refreshProcess(processKey);
connectorService.refreshProcess(processKey, endpoint, "");
}
return CompletableFuture.completedFuture(null);
}
private CompletableFuture<Object> refreshMetrics(ExecuteCommandParams params) {
String processKey = getProcessKey(params);
String endpoint = getArgumentByKey(params, "endpoint");
String metricName = getArgumentByKey(params, "metricName");
if (processKey != null) {
connectorService.refreshProcess(processKey, endpoint, metricName);
}
return CompletableFuture.completedFuture(null);
@@ -266,5 +290,25 @@ public class SpringProcessCommandHandler {
return CompletableFuture.completedFuture(null);
}
private CompletableFuture<Object> handleLiveMetricsProcessRequest(ExecuteCommandParams params) {
String processKey = getProcessKey(params);
String metricName = getArgumentByKey(params, "metricName");
if (processKey != null) {
switch(metricName) {
case "gcPauses": {
SpringProcessGcPausesMetricsLiveData data = connectorService.getGcPausesMetricsLiveData(processKey);
return CompletableFuture.completedFuture(data.getGcPausesMetrics());
}
case "memory": {
SpringProcessMemoryMetricsLiveData data = connectorService.getMemoryMetricsLiveData(processKey);
return CompletableFuture.completedFuture(data.getMemoryMetrics());
}
default: {}
}
}
return CompletableFuture.completedFuture(null);
}
}

View File

@@ -27,4 +27,6 @@ public interface SpringProcessConnector {
String getProjectName();
String getProcessId();
String getProcessName();
SpringProcessGcPausesMetricsLiveData refreshGcPausesMetrics(SpringProcessLiveData current, String metricName) throws Exception;
SpringProcessMemoryMetricsLiveData refreshMemoryMetrics(SpringProcessLiveData current, String metricName) throws Exception;
}

View File

@@ -102,4 +102,18 @@ public class SpringProcessConnectorOverHttp implements SpringProcessConnector {
public String toString() {
return "SpringProcessConnectorOverHttp [actuatorURL=" + actuatorUrl + "]";
}
@Override
public SpringProcessGcPausesMetricsLiveData refreshGcPausesMetrics(SpringProcessLiveData current, String metricName)
throws Exception {
return null;
}
@Override
public SpringProcessMemoryMetricsLiveData refreshMemoryMetrics(SpringProcessLiveData current, String metricName)
throws Exception {
return null;
}
}

View File

@@ -147,6 +147,52 @@ public class SpringProcessConnectorOverJMX implements SpringProcessConnector {
throw new Exception("no live data received, lets try again");
}
@Override
public SpringProcessMemoryMetricsLiveData refreshMemoryMetrics(SpringProcessLiveData currentData, String metricName) 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);
SpringProcessMemoryMetricsLiveData liveData = springJMXConnector.retrieveLiveMemoryMetricsData(getProcessType(), jmxConnection, processID, processName, currentData, metricName);
if (liveData != null && liveData.getMemoryMetrics() != null && liveData.getMemoryMetrics().length > 0) {
return liveData;
}
}
catch (Exception e) {
log.error("exception while connecting to jmx: " + jmxURL, e);
}
}
throw new Exception("no live data received, lets try again");
}
@Override
public SpringProcessGcPausesMetricsLiveData refreshGcPausesMetrics(SpringProcessLiveData currentData, String metricName) 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);
SpringProcessGcPausesMetricsLiveData liveData = springJMXConnector.retrieveLiveGcPausesMetricsData(getProcessType(), jmxConnection, processID, processName, currentData, metricName);
if (liveData != null && liveData.getGcPausesMetrics() != null && liveData.getGcPausesMetrics().length > 0) {
return liveData;
}
}
catch (Exception e) {
log.error("exception while connecting to jmx: " + jmxURL, e);
}
}
throw new Exception("no live data received, lets try again");
}
@Override
public void disconnect() throws Exception {

View File

@@ -99,7 +99,7 @@ public class SpringProcessConnectorService {
}
}
public void refreshProcess(String processKey) {
public void refreshProcess(String processKey, String endpoint, String metricName) {
log.info("refresh process: " + processKey);
SpringProcessConnector connector = this.connectors.get(processKey);
@@ -109,13 +109,21 @@ public class SpringProcessConnectorService {
progressTask.progressBegin("Refresh", null);
scheduleRefresh(progressTask, processKey, connector, 0, TimeUnit.SECONDS, 0);
scheduleRefresh(progressTask, processKey, connector, 0, TimeUnit.SECONDS, 0, endpoint, metricName);
}
}
public SpringProcessLiveData getLiveData(String processKey) {
return this.liveDataProvider.getCurrent(processKey);
}
public SpringProcessMemoryMetricsLiveData getMemoryMetricsLiveData(String processKey) {
return this.liveDataProvider.getMemoryMetrics(processKey);
}
public SpringProcessGcPausesMetricsLiveData getGcPausesMetricsLiveData(String processKey) {
return this.liveDataProvider.getGcPausesMetrics(processKey);
}
public void disconnectProcess(String processKey) {
log.info("disconnect from process: " + processKey);
@@ -162,7 +170,9 @@ public class SpringProcessConnectorService {
connector.connect();
progressTask.progressDone();
refreshProcess(processKey);
refreshProcess(processKey, "", "");
refreshProcess(processKey, "metrics", "memory");
refreshProcess(processKey, "metrics", "gcPauses");
}
catch (Exception e) {
log.info("problem occured during process connect", e);
@@ -210,7 +220,7 @@ public class SpringProcessConnectorService {
}, delay, unit);
}
private void scheduleRefresh(ProgressTask progressTask, String processKey, SpringProcessConnector connector, long delay, TimeUnit unit, int retryNo) {
private void scheduleRefresh(ProgressTask progressTask, String processKey, SpringProcessConnector connector, long delay, TimeUnit unit, int retryNo, String endpoint, String metricName) {
String progressMessage = "Refreshing data from Spring process: " + processKey + " - retry no: " + retryNo;
log.info(progressMessage);
@@ -219,14 +229,38 @@ public class SpringProcessConnectorService {
try {
progressTask.progressEvent(progressMessage);
SpringProcessLiveData newLiveData = connector.refresh(this.liveDataProvider.getCurrent(processKey));
if (newLiveData != null) {
if (!this.liveDataProvider.add(processKey, newLiveData)) {
this.liveDataProvider.update(processKey, newLiveData);
if(endpoint.equals("metrics") && metricName.equals("memory")) {
SpringProcessMemoryMetricsLiveData newMetricsLiveData = connector.refreshMemoryMetrics(this.liveDataProvider.getCurrent(processKey), metricName);
if (newMetricsLiveData != null) {
if (!this.liveDataProvider.addMemoryMetrics(processKey, newMetricsLiveData)) {
this.liveDataProvider.updateMemoryMetrics(processKey, newMetricsLiveData);
}
this.connectedSuccess.put(processKey, true);
}
this.connectedSuccess.put(processKey, true);
} else if(endpoint.equals("metrics") && metricName.equals("gcPauses")) {
SpringProcessGcPausesMetricsLiveData newMetricsLiveData = connector.refreshGcPausesMetrics(this.liveDataProvider.getCurrent(processKey), metricName);
if (newMetricsLiveData != null) {
if (!this.liveDataProvider.addGcPausesMetrics(processKey, newMetricsLiveData)) {
this.liveDataProvider.updateGcPausesMetrics(processKey, newMetricsLiveData);
}
this.connectedSuccess.put(processKey, true);
}
} else {
SpringProcessLiveData newLiveData = connector.refresh(this.liveDataProvider.getCurrent(processKey));
if (newLiveData != null) {
if (!this.liveDataProvider.add(processKey, newLiveData)) {
this.liveDataProvider.update(processKey, newLiveData);
}
this.connectedSuccess.put(processKey, true);
}
}
progressTask.progressDone();
}
@@ -236,7 +270,7 @@ public class SpringProcessConnectorService {
if (retryNo < maxRetryCount && isKnownProcessKey(processKey)) {
scheduleRefresh(progressTask, processKey, connector, retryDelayInSeconds, TimeUnit.SECONDS,
retryNo + 1);
retryNo + 1, endpoint, metricName);
}
else {
progressTask.progressDone();

View File

@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
/**
* @author V Udayani
*/
public class SpringProcessGcPausesMetricsLiveData {
private final ProcessType processType;
private final String processName;
private final String processID;
private final LiveMemoryMetricsModel[] gcPausesMetrics;
public SpringProcessGcPausesMetricsLiveData(ProcessType processType, String processName, String processID, LiveMemoryMetricsModel[] gcPausesMetrics) {
super();
this.processType = processType;
this.processName = processName;
this.processID = processID;
this.gcPausesMetrics = gcPausesMetrics;
}
public ProcessType getProcessType() {
return processType;
}
public String getProcessName() {
return this.processName;
}
public String getProcessID() {
return this.processID;
}
public LiveMemoryMetricsModel[] getGcPausesMetrics() {
return this.gcPausesMetrics;
}
}

View File

@@ -76,6 +76,8 @@ public class SpringProcessLiveDataExtractorOverHttp {
LiveBeansModel beans = getBeans(connection);
LiveMetricsModel metrics = getMetrics(connection);
StartupMetricsModel startup = getStartupMetrics(connection, currentData == null ? null : currentData.getStartupMetrics());
// LiveMemoryMetricsModel[] memoryMetrics = getMemoryMetrics(connection);
// LiveMemoryMetricsModel gcPausesMetrics = getGcPausesMetrics(connection);
if (contextPath == null) {
contextPath = getContextPath(environment);
@@ -99,7 +101,10 @@ public class SpringProcessLiveDataExtractorOverHttp {
conditionals,
properties,
metrics,
startup);
startup
);
// memoryMetrics,
// gcPausesMetrics);
}
catch (Exception e) {
log.error("error reading live data from: " + processID + " - " + processName, e);

View File

@@ -14,6 +14,7 @@ import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -36,6 +37,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.util.StringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -95,6 +97,8 @@ public class SpringProcessLiveDataExtractorOverJMX {
LiveBeansModel beans = getBeans(connection, domain);
LiveMetricsModel metrics = getMetrics(connection, domain);
StartupMetricsModel startup = getStartupMetrics(connection, domain, currentData == null ? null : currentData.getStartupMetrics());
// LiveMemoryMetricsModel[] memoryMetrics = getLiveMemoryMetrics(connection, domain);
// LiveMemoryMetricsModel gcPausesMetrics = getGcPausesMetrics(connection, domain);
if (contextPath == null) {
contextPath = getContextPath(connection, domain, environment);
@@ -118,7 +122,10 @@ public class SpringProcessLiveDataExtractorOverJMX {
conditionals,
properties,
metrics,
startup);
startup
// memoryMetrics,
// gcPausesMetrics
);
}
catch (Exception e) {
log.error("error reading live data from: " + processID + " - " + processName, e);
@@ -127,6 +134,108 @@ public class SpringProcessLiveDataExtractorOverJMX {
return null;
}
/**
* @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
*/
public SpringProcessMemoryMetricsLiveData retrieveLiveMemoryMetricsData(ProcessType processType, JMXConnector jmxConnector, String processID, String processName,
SpringProcessLiveData currentData, String metricName) {
List<String> memoryTags = Arrays.asList( "jvm.memory.used", "jvm.memory.committed", "jvm.memory.max");
try {
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
List<LiveMemoryMetricsModel> memoryMetricsList = new ArrayList<>();
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);
}
}
// if(metricName.equals("memory")) {
for(String metric : memoryTags) {
LiveMemoryMetricsModel metrics = getLiveMetrics(connection, domain, metric);
if(metrics != null) {
memoryMetricsList.add(metrics);
}
}
// }
LiveMemoryMetricsModel[] res = (LiveMemoryMetricsModel[]) memoryMetricsList.toArray(new LiveMemoryMetricsModel[memoryMetricsList.size()]);
return new SpringProcessMemoryMetricsLiveData(
processType,
processName,
processID,
res
);
}
catch (Exception e) {
log.error("error reading live metrics data from: " + processID + " - " + processName, e);
}
return null;
}
/**
* @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
*/
public SpringProcessGcPausesMetricsLiveData retrieveLiveGcPausesMetricsData(ProcessType processType, JMXConnector jmxConnector, String processID, String processName,
SpringProcessLiveData currentData, String metricName) {
try {
MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
List<LiveMemoryMetricsModel> memoryMetricsList = new ArrayList<>();
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);
}
}
LiveMemoryMetricsModel metrics = getLiveMetrics(connection, domain, "jvm.gc.pause");
if(metrics != null) {
memoryMetricsList.add(getLiveMetrics(connection, domain, "jvm.gc.pause"));
}
LiveMemoryMetricsModel[] res = (LiveMemoryMetricsModel[]) memoryMetricsList.toArray(new LiveMemoryMetricsModel[memoryMetricsList.size()]);
return new SpringProcessGcPausesMetricsLiveData(
processType,
processName,
processID,
res
);
}
catch (Exception e) {
log.error("error reading live metrics data from: " + processID + " - " + processName, e);
}
return null;
}
private LiveMetricsModel getMetrics(MBeanServerConnection connection, String domain) {
return new LiveMetricsModel() {
@@ -257,6 +366,31 @@ public class SpringProcessLiveDataExtractorOverJMX {
}
return LiveBeansModel.builder().build();
}
public LiveMemoryMetricsModel getLiveMetrics(MBeanServerConnection connection, String domain, String metricName) {
List<Object> tags = new ArrayList<>();
Object[] params1 = new Object[] {metricName, tags};
String[] signature = new String[] {String.class.getName(), List.class.getName()};
try {
Object metricsData = getActuatorDataFromOperation(connection,
getObjectName(domain, "type=Endpoint,name=Metrics"),
"metric",
params1,
signature);
if (metricsData instanceof String) {
return gson.fromJson((String)metricsData, LiveMemoryMetricsModel.class);
} else if(metricsData != null){
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(metricsData, LiveMemoryMetricsModel.class);
}
} catch (Exception e) {
log.error("", e);
}
return null;
}
protected Object getBeansFromNonBootMBean(MBeanServerConnection connection) throws Exception {
Set<ObjectName> nonBootSpringLiveMBeans = getNonBootSpringLiveMBeans(connection);

View File

@@ -27,12 +27,16 @@ import org.springframework.ide.vscode.commons.util.Assert;
public class SpringProcessLiveDataProvider {
private final ConcurrentMap<String, SpringProcessLiveData> liveData;
private final ConcurrentMap<String, SpringProcessMemoryMetricsLiveData> memoryMetricsLiveData;
private final ConcurrentMap<String, SpringProcessGcPausesMetricsLiveData> gcPausesMetricsLiveData;
private final List<SpringProcessLiveDataChangeListener> listeners;
private final SimpleLanguageServer server;
public SpringProcessLiveDataProvider(SimpleLanguageServer server) {
this.server = server;
this.liveData = new ConcurrentHashMap<>();
this.memoryMetricsLiveData = new ConcurrentHashMap<>();
this.gcPausesMetricsLiveData = new ConcurrentHashMap<>();
this.listeners = new CopyOnWriteArrayList<>();
}
@@ -54,6 +58,22 @@ public class SpringProcessLiveDataProvider {
return oldData == null;
}
public boolean addMemoryMetrics(String processKey, SpringProcessMemoryMetricsLiveData liveData) {
SpringProcessMemoryMetricsLiveData oldData = this.memoryMetricsLiveData.putIfAbsent(processKey, liveData);
if (oldData == null) {
getClient().liveProcessMemoryMetricsDataUpdated(createProcessSummaryForMetrics(processKey, liveData.getProcessType().jsonName(),liveData.getProcessName(),liveData.getProcessID()));
}
return oldData == null;
}
public boolean addGcPausesMetrics(String processKey, SpringProcessGcPausesMetricsLiveData liveData) {
SpringProcessGcPausesMetricsLiveData oldData = this.gcPausesMetricsLiveData.putIfAbsent(processKey, liveData);
if (oldData == null) {
getClient().liveProcessGcPausesMetricsDataUpdated(createProcessSummaryForMetrics(processKey, liveData.getProcessType().jsonName(),liveData.getProcessName(),liveData.getProcessID()));
}
return oldData == null;
}
private STS4LanguageClient getClient() {
STS4LanguageClient client = server.getClient();
Assert.isLegal(client!=null, "Client is null. Language server not yet initialized?");
@@ -74,6 +94,16 @@ public class SpringProcessLiveDataProvider {
getClient().liveProcessDataUpdated(createProcessSummary(processKey, liveData));
}
public void updateMemoryMetrics(String processKey, SpringProcessMemoryMetricsLiveData liveData) {
this.memoryMetricsLiveData.put(processKey, liveData);
getClient().liveProcessMemoryMetricsDataUpdated(createProcessSummaryForMetrics(processKey, liveData.getProcessType().jsonName(),liveData.getProcessName(),liveData.getProcessID()));
}
public void updateGcPausesMetrics(String processKey, SpringProcessGcPausesMetricsLiveData liveData) {
this.gcPausesMetricsLiveData.put(processKey, liveData);
getClient().liveProcessGcPausesMetricsDataUpdated(createProcessSummaryForMetrics(processKey, liveData.getProcessType().jsonName(),liveData.getProcessName(),liveData.getProcessID()));
}
public void addLiveDataChangeListener(SpringProcessLiveDataChangeListener listener) {
this.listeners.add(listener);
}
@@ -93,6 +123,14 @@ public class SpringProcessLiveDataProvider {
public SpringProcessLiveData getCurrent(String processKey) {
return this.liveData.get(processKey);
}
public SpringProcessMemoryMetricsLiveData getMemoryMetrics(String processKey) {
return this.memoryMetricsLiveData.get(processKey);
}
public SpringProcessGcPausesMetricsLiveData getGcPausesMetrics(String processKey) {
return this.gcPausesMetricsLiveData.get(processKey);
}
public static LiveProcessSummary createProcessSummary(String processKey, SpringProcessLiveData liveData) {
LiveProcessSummary p = new LiveProcessSummary();
@@ -102,5 +140,15 @@ public class SpringProcessLiveDataProvider {
p.setPid(liveData.getProcessID());
return p;
}
public static LiveProcessSummary createProcessSummaryForMetrics(String processKey, String processType, String processName,
String processID) {
LiveProcessSummary p = new LiveProcessSummary();
p.setType(processType);
p.setProcessKey(processKey);
p.setProcessName(processName);
p.setPid(processID);
return p;
}
}

View File

@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover.v2;
/**
* @author V Udayani
*/
public class SpringProcessMemoryMetricsLiveData {
private final ProcessType processType;
private final String processName;
private final String processID;
private final LiveMemoryMetricsModel[] memoryMetrics;
public SpringProcessMemoryMetricsLiveData(ProcessType processType, String processName, String processID, LiveMemoryMetricsModel[] memoryMetrics) {
super();
this.processType = processType;
this.processName = processName;
this.processID = processID;
this.memoryMetrics = memoryMetrics;
}
public ProcessType getProcessType() {
return processType;
}
public String getProcessName() {
return this.processName;
}
public String getProcessID() {
return this.processID;
}
public LiveMemoryMetricsModel[] getMemoryMetrics() {
return this.memoryMetrics;
}
}

View File

@@ -20,10 +20,35 @@ export interface ExtensionAPI {
*/
readonly onDidLiveProcessUpdate: Event<LiveProcess>
/**
* An event which fires on live process gcpauses metrics data change. Payload is processKey.
*/
readonly onDidLiveProcessGcPausesMetricsUpdate: Event<LiveProcess>
/**
* An event which fires on live process memory metrics data change. Payload is processKey.
*/
readonly onDidLiveProcessMemoryMetricsUpdate: Event<LiveProcess>
/**
* A command to get live process data.
*/
readonly getLiveProcessData: (query: SimpleQuery | BeansQuery) => Promise<any>
readonly getLiveProcessData: (query: SimpleQuery | BeansQuery ) => Promise<any>
/**
* A command to refresh live process data.
*/
readonly refreshLiveProcessData: (query: SimpleQuery | BeansQuery) => Promise<any>;
/**
* A command to get live process metrics data.
*/
readonly getLiveProcessMetricsData: (query: MetricsQuery) => Promise<any>;
/**
* A command to refresh live process metrics data.
*/
readonly refreshLiveProcessMetricsData: (query: MetricsQuery) => Promise<any>;
/**
* A command to list all currently connected processes.
@@ -52,3 +77,10 @@ interface BeansQuery extends LiveProcessDataQuery {
beanName?: string;
dependingOn?: string;
}
interface MetricsQuery extends LiveProcessDataQuery {
endpoint: "metrics";
metricName: string;
tag?: { key: string; value: string };
}

View File

@@ -1,39 +1,68 @@
import { commands, Uri } from "vscode";
import { Emitter, LanguageClient } from "vscode-languageclient/node";
import { ExtensionAPI } from "./api";
import { LiveProcess, LiveProcessConnectedNotification, LiveProcessDisconnectedNotification, LiveProcessUpdatedNotification } from "./notification";
import { LiveProcess, LiveProcessConnectedNotification, LiveProcessDisconnectedNotification, LiveProcessUpdatedNotification, LiveProcessGcPausesMetricsUpdatedNotification, LiveProcessMemoryMetricsUpdatedNotification } from "./notification";
export class ApiManager {
public api: ExtensionAPI;
private onDidLiveProcessConnectEmitter: Emitter<LiveProcess> = new Emitter<LiveProcess>();
private onDidLiveProcessDisconnectEmitter: Emitter<LiveProcess> = new Emitter<LiveProcess>();
private onDidLiveProcessUpdateEmitter: Emitter<LiveProcess> = new Emitter<LiveProcess>();
private onDidLiveProcessGcPausesMetricsUpdateEmitter: Emitter<LiveProcess> = new Emitter<LiveProcess>();
private onDidLiveProcessMemoryMetricsUpdateEmitter: Emitter<LiveProcess> = new Emitter<LiveProcess>();
public constructor(client: LanguageClient) {
const onDidLiveProcessConnect = this.onDidLiveProcessConnectEmitter.event;
const onDidLiveProcessDisconnect = this.onDidLiveProcessDisconnectEmitter.event;
const onDidLiveProcessUpdate = this.onDidLiveProcessUpdateEmitter.event;
const onDidLiveProcessGcPausesMetricsUpdate = this.onDidLiveProcessGcPausesMetricsUpdateEmitter.event;
const onDidLiveProcessMemoryMetricsUpdate = this.onDidLiveProcessMemoryMetricsUpdateEmitter.event;
const COMMAND_LIVEDATA_GET = "sts/livedata/get";
const getLiveProcessData = async (query) => {
return await commands.executeCommand(COMMAND_LIVEDATA_GET, query);
}
const COMMAND_LIVEDATA_REFRESH = "sts/livedata/refresh";
const refreshLiveProcessData = async (query) => {
return await commands.executeCommand(COMMAND_LIVEDATA_REFRESH, query);
}
const COMMAND_LIVEDATA_LIST_CONNECTED = "sts/livedata/listConnected"
const listConnectedProcesses = async () : Promise<LiveProcess[]> => {
return await commands.executeCommand(COMMAND_LIVEDATA_LIST_CONNECTED);
}
const COMMAND_LIVEDATA_GET_METRICS = "sts/livedata/get/metrics"
const getLiveProcessMetricsData = async (query) : Promise<LiveProcess[]> => {
console.log(query);
console.log("in get live metrics function");
return await commands.executeCommand(COMMAND_LIVEDATA_GET_METRICS, query);
}
const COMMAND_LIVEDATA_REFRESH_METRICS = "sts/livedata/refresh/metrics";
const refreshLiveProcessMetricsData = async (query) => {
console.log("in get live metrics refresh function");
return await commands.executeCommand(COMMAND_LIVEDATA_REFRESH_METRICS, query);
}
client.onNotification(LiveProcessConnectedNotification.type, (process: LiveProcess) => this.onDidLiveProcessConnectEmitter.fire(process));
client.onNotification(LiveProcessDisconnectedNotification.type, (process: LiveProcess) => this.onDidLiveProcessDisconnectEmitter.fire(process));
client.onNotification(LiveProcessUpdatedNotification.type, (process: LiveProcess) => this.onDidLiveProcessUpdateEmitter.fire(process));
client.onNotification(LiveProcessGcPausesMetricsUpdatedNotification.type, (process: LiveProcess) => this.onDidLiveProcessGcPausesMetricsUpdateEmitter.fire(process));
client.onNotification(LiveProcessMemoryMetricsUpdatedNotification.type, (process: LiveProcess) => this.onDidLiveProcessMemoryMetricsUpdateEmitter.fire(process));
this.api = {
client,
onDidLiveProcessConnect,
onDidLiveProcessDisconnect,
onDidLiveProcessUpdate,
onDidLiveProcessMemoryMetricsUpdate,
onDidLiveProcessGcPausesMetricsUpdate,
getLiveProcessData,
refreshLiveProcessData,
getLiveProcessMetricsData,
refreshLiveProcessMetricsData,
listConnectedProcesses,
};
}

View File

@@ -28,4 +28,12 @@ export namespace LiveProcessDisconnectedNotification {
export namespace LiveProcessUpdatedNotification {
export const type = new NotificationType<LiveProcess>('sts/liveprocess/updated');
}
export namespace LiveProcessGcPausesMetricsUpdatedNotification {
export const type = new NotificationType<LiveProcess>('sts/liveprocess/gcpauses/metrics/updated');
}
export namespace LiveProcessMemoryMetricsUpdatedNotification {
export const type = new NotificationType<LiveProcess>('sts/liveprocess/memory/metrics/updated');
}