Connect to Spring process directly, no tracking

This commit is contained in:
BoykoAlex
2022-02-16 12:13:42 -05:00
parent 5d0bed47e4
commit 15722b017c
7 changed files with 83 additions and 33 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2019 Pivotal, Inc.
* Copyright (c) 2017, 2022 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
@@ -30,7 +30,7 @@ import org.springframework.stereotype.Component;
@Component
public class BootJavaConfig implements InitializingBean {
public static final boolean LIVE_INFORMATION_AUTOMATIC_TRACKING_ENABLED_DEFAULT = true;
public static final boolean LIVE_INFORMATION_AUTOMATIC_TRACKING_ENABLED_DEFAULT = false;
public static final int LIVE_INFORMATION_AUTOMATIC_TRACKING_DELAY_DEFAULT = 5000;
public static final int LIVE_INFORMATION_FETCH_DATA_RETRY_MAX_NO_DEFAULT = 10;

View File

@@ -17,7 +17,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -93,6 +92,8 @@ public class SpringProcessCommandHandler {
// try local processes
if (SpringProcessConnectorLocal.isAvailable()) {
// Try cached processes.
SpringProcessDescriptor[] processes = localProcessConnector.getProcesses(false, SpringProcessStatus.REGULAR, SpringProcessStatus.AUTO_CONNECT);
for (SpringProcessDescriptor process : processes) {
if (process.getProcessKey().equals(processKey)) {
@@ -100,6 +101,15 @@ public class SpringProcessCommandHandler {
return CompletableFuture.completedFuture(null);
}
}
processes = localProcessConnector.getProcesses(true, SpringProcessStatus.REGULAR, SpringProcessStatus.AUTO_CONNECT);
for (SpringProcessDescriptor process : processes) {
if (process.getProcessKey().equals(processKey)) {
localProcessConnector.connectProcess(process);
return CompletableFuture.completedFuture(null);
}
}
}
// try remote processes

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, Inc.
* Copyright (c) 2019, 2022 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
@@ -142,7 +142,7 @@ public class SpringProcessConnectorService {
* common method to generate process keys from process IDs and process names
*/
public static String getProcessKey(String processID, String processName) {
return processID + " - " + processName;
return processID;
}
private void scheduleConnect(ProgressTask progressTask, String processKey, SpringProcessConnector connector, long delay, TimeUnit unit, int retryNo) {

View File

@@ -2,6 +2,7 @@ import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, Prov
import * as path from "path";
import * as VSCode from "vscode";
import { Disposable } from "vscode";
import psList from 'ps-list';
const JMX_VM_ARG = '-Dspring.jmx.enabled='
const ADMIN_VM_ARG = '-Dspring.application.admin.enabled='
@@ -10,7 +11,7 @@ const BOOT_PROJECT_ARG = '-Dspring.boot.project.name=';
class SpringBootDebugConfigProvider implements DebugConfigurationProvider {
resolveDebugConfigurationWithSubstitutedVariables(folder: WorkspaceFolder | undefined, debugConfiguration: DebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration> {
if (isAutoConnect() && this.isActuatorOnClasspath(debugConfiguration)) {
if (isAutoConnect() && isActuatorOnClasspath(debugConfiguration)) {
if (debugConfiguration.vmArgs) {
if (debugConfiguration.vmArgs.indexOf(JMX_VM_ARG) < 0) {
debugConfiguration.vmArgs += ` ${JMX_VM_ARG}true`;
@@ -28,28 +29,69 @@ class SpringBootDebugConfigProvider implements DebugConfigurationProvider {
return debugConfiguration;
}
private isActuatorOnClasspath(debugConfiguration: DebugConfiguration): boolean {
if (Array.isArray(debugConfiguration.classPaths)) {
return !!debugConfiguration.classPaths.find(this.isActuatorJarFile);
}
return false;
}
private isActuatorJarFile(f: string): boolean {
const fileName = path.basename(f || "");
if (/^spring-boot-actuator-\d+\.\d+\.\d+(.*)?.jar$/.test(fileName)) {
return true;
}
return false;
}
}
interface ProcessEvent {
type: string;
pid: number;
shellProcessId: number
}
export function startDebugSupport(): Disposable {
// VSCode.debug.onDidStartDebugSession(handleDebugSessionStarted);
VSCode.debug.onDidReceiveDebugSessionCustomEvent(handleCustomDebugEvent);
return VSCode.debug.registerDebugConfigurationProvider('java', new SpringBootDebugConfigProvider(), VSCode.DebugConfigurationProviderTriggerKind.Initial);
}
function isAutoConnect(): boolean {
return VSCode.workspace.getConfiguration("boot-java.live-information.automatic-tracking")?.get('on');
async function handleCustomDebugEvent(e: VSCode.DebugSessionCustomEvent): Promise<void> {
if (e.session?.type === 'java' && e?.body?.type === 'processid') {
const debugConfiguration: DebugConfiguration = e.session.configuration;
if (isBootAppWithJmxSetup(debugConfiguration)) {
setTimeout(async () => {
const pid = await getAppPid(e.body as ProcessEvent);
const processKey = pid.toString();
VSCode.commands.executeCommand('sts/livedata/connect', { processKey });
}, 500);
}
}
}
async function getAppPid(e: ProcessEvent): Promise<number> {
if (e.pid) {
return e.pid;
} else if (e.shellProcessId) {
const processes = await psList();
const appProcess = processes.find(p => p.ppid === e.shellProcessId);
if (appProcess) {
return appProcess.pid;
}
throw Error(`No child process found for parent shell process with pid = ${e.shellProcessId}`);
} else {
throw Error('No pid or parent shell process id available');
}
}
function isActuatorOnClasspath(debugConfiguration: DebugConfiguration): boolean {
if (Array.isArray(debugConfiguration.classPaths)) {
return !!debugConfiguration.classPaths.find(isActuatorJarFile);
}
return false;
}
function isActuatorJarFile(f: string): boolean {
const fileName = path.basename(f || "");
if (/^spring-boot-actuator-\d+\.\d+\.\d+(.*)?.jar$/.test(fileName)) {
return true;
}
return false;
}
function isBootAppWithJmxSetup(debugConfiguration: DebugConfiguration): boolean {
return debugConfiguration.vmArgs.indexOf(`${JMX_VM_ARG}true`) >= 0
&& debugConfiguration.vmArgs.indexOf(`${ADMIN_VM_ARG}true`) >= 0
&& debugConfiguration.vmArgs.indexOf(`${BOOT_PROJECT_ARG}${debugConfiguration.projectName}`) >= 0
&& isActuatorOnClasspath(debugConfiguration);
}
function isAutoConnect(): boolean {
return VSCode.workspace.getConfiguration("boot-java.live-information.automatic-connection")?.get('on');
}

View File

@@ -7,7 +7,8 @@ import { ActivatorOptions } from '@pivotal-tools/commons-vscode';
interface ProcessCommandInfo {
processKey : string;
label: string;
action: string
action: string;
projectName: string;
}
async function liveHoverConnectHandler() {

View File

@@ -75,15 +75,10 @@
"type": "object",
"title": "Boot-Java Configuration",
"properties": {
"boot-java.live-information.automatic-tracking.on": {
"boot-java.live-information.automatic-connection.on": {
"type": "boolean",
"default": true,
"description": "Live Information - Automatic Process Tracking Enabled"
},
"boot-java.live-information.automatic-tracking.delay": {
"type": "number",
"default": 5000,
"description": "Live Information - Automatic Process Tracking Delay in ms"
"description": "Live Information - Automatic Process Connection Enabled"
},
"boot-java.live-information.fetch-data.max-retries": {
"type": "number",
@@ -518,13 +513,14 @@
},
"dependencies": {
"@pivotal-tools/commons-vscode": "file:../commons-vscode/pivotal-tools-commons-vscode-0.2.4.tgz",
"ps-list": "^7.2.0",
"vscode-languageclient": "^7.0.0"
},
"devDependencies": {
"@types/node": "^16.11.11",
"@types/vscode": "^1.53.0",
"typescript": "^4.1.2",
"vsce": "^2.5.1"
"vsce": "^2.6.7"
},
"extensionDependencies": [
"redhat.java"

View File

@@ -9,7 +9,8 @@
"declaration": true,
"outDir": "out",
"sourceMap": true,
"rootDir": "."
"rootDir": ".",
"esModuleInterop": true
},
"include": [
"typings/*.d.ts",