Automatically show language server logs in Eclipse console

This commit is contained in:
Kris De Volder
2018-02-01 13:49:06 -08:00
parent 176a40b4b3
commit 42fc5da462
9 changed files with 273 additions and 10 deletions

View File

@@ -32,6 +32,7 @@ import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessS
public class SpringBootJavaLanguageServer extends STS4LanguageServerProcessStreamConnector {
public SpringBootJavaLanguageServer() {
super("Boot Java Language Server");
List<String> commands = new ArrayList<>();
JRE jre = getJRE();
commands.add(jre.getJavaExecutable());
@@ -74,12 +75,13 @@ public class SpringBootJavaLanguageServer extends STS4LanguageServerProcessStrea
String languageServerLocalCopy = bundleVersion + "-" + languageServer;
File dataFile = bundle.getDataFile(languageServerLocalCopy);
Exception error = null;
if (!dataFile.exists() || bundleVersion.endsWith("qualifier")) { // qualifier check to get the language server always copied in dev mode
try {
copyLanguageServerJAR(languageServer, languageServerLocalCopy);
}
catch (Exception e) {
e.printStackTrace();
error = e;
}
}
if (!dataFile.exists()) {
@@ -91,6 +93,9 @@ public class SpringBootJavaLanguageServer extends STS4LanguageServerProcessStrea
if (locallyBuiltJar.exists()) {
return locallyBuiltJar.getAbsolutePath();
}
if (error!=null) {
error.printStackTrace();
}
}
return dataFile.getAbsolutePath();
}

View File

@@ -30,6 +30,7 @@ import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessS
public class BoshLanguageServer extends STS4LanguageServerProcessStreamConnector {
public BoshLanguageServer() {
super("Bosh Language Server");
List<String> commands = new ArrayList<>();
commands.add(JRE.currentJRE().getJavaExecutable());

View File

@@ -43,6 +43,7 @@ public class CloudFoundryManifestLanguageServer extends STS4LanguageServerProces
private static List<CloudFoundryManifestLanguageServer> servers = new CopyOnWriteArrayList<>();
public CloudFoundryManifestLanguageServer() {
super("Cloudfoundry Language Server");
List<String> commands = new ArrayList<>();
commands.add(JRE.currentJRE().getJavaExecutable());

View File

@@ -30,6 +30,7 @@ import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessS
public class ConcourseLanguageServer extends STS4LanguageServerProcessStreamConnector {
public ConcourseLanguageServer() {
super("Concourse Language Server");
List<String> commands = new ArrayList<>();
commands.add(JRE.currentJRE().getJavaExecutable());

View File

@@ -12,7 +12,9 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.8.0",
org.eclipse.lsp4j;bundle-version="0.4.0",
org.eclipse.ui.workbench.texteditor,
org.eclipse.jface.text,
com.google.guava
com.google.guava,
org.eclipse.debug.ui,
org.eclipse.ui.console
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Export-Package: org.springframework.tooling.ls.eclipse.commons

View File

@@ -12,18 +12,99 @@ package org.springframework.tooling.ls.eclipse.commons;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.io.InputStream;
import java.io.OutputStream;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider;
import org.springframework.tooling.ls.eclipse.commons.console.ConsoleUtil.Console;
import org.springframework.tooling.ls.eclipse.commons.console.LanguageServerConsoles;
import com.google.common.base.Charsets;
import com.google.common.base.Supplier;
public class STS4LanguageServerProcessStreamConnector extends ProcessStreamConnectionProvider {
private static LanguageServerProcessReaper processReaper = new LanguageServerProcessReaper();
private Supplier<Console> consoles = null;
public STS4LanguageServerProcessStreamConnector(String consoleLabel) {
if (consoleLabel!=null) {
this.consoles = LanguageServerConsoles.getConsoleFactory(consoleLabel);
}
}
@Override
public void start() throws IOException {
super.start();
processReaper.addProcess(LanguageServerProcessReaper.getProcess(this));
Process process = LanguageServerProcessReaper.getProcess(this);
processReaper.addProcess(process);
if (consoles!=null) {
forwardTo(getLanguageServerLog(), consoles.get().out);
}
}
@Override
protected ProcessBuilder createProcessBuilder() {
if (consoles==null) {
return super.createProcessBuilder();
}
ProcessBuilder builder = new ProcessBuilder(getCommands());
builder.directory(new File(getWorkingDirectory()));
//builder.redirectError(ProcessBuilder.Redirect.INHERIT);
return builder;
}
private void forwardTo(InputStream is, OutputStream os) {
Job consoleJob = new Job("Forward Language Server log output to console") {
@Override
protected IStatus run(IProgressMonitor arg0) {
try {
pipe(is, os);
os.write("==== Process Terminated====\n".getBytes(Charsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
os.close();
} catch (IOException e) {
}
}
return Status.OK_STATUS;
}
void pipe(InputStream input, OutputStream output) throws IOException {
try {
byte[] buf = new byte[1024*4];
int n = input.read(buf);
while (n >= 0) {
output.write(buf, 0, n);
n = input.read(buf);
}
output.flush();
} finally {
input.close();
}
}
};
consoleJob.setSystem(true);
consoleJob.schedule();
}
private InputStream getLanguageServerLog() {
return super.getErrorStream();
}
@Override
public InputStream getErrorStream() {
// lsp4e doesn't do anything with it. So don't pass it on. (Once they do start reading it it might actually break us otherwise)
return null;
}
@Override

View File

@@ -0,0 +1,115 @@
/*******************************************************************************
* Copyright (c) 2012, 2018 Pivotal Software, 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.ls.eclipse.commons.console;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.swt.graphics.Color;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleInputStream;
import org.eclipse.ui.console.IOConsoleOutputStream;
/**
* @author Kris De Volder
*/
@SuppressWarnings("restriction")
public class ConsoleUtil {
public static class Console {
public final InputStream in;
public final OutputStream out;
public final OutputStream err;
public Console(IOConsoleInputStream in, IOConsoleOutputStream out,
IOConsoleOutputStream err) {
this.in = in;
this.out = out;
this.err = err;
}
public void close() {
try {
out.close();
} catch (IOException e) {
}
try {
err.close();
} catch (IOException e) {
}
try {
in.close();
} catch (IOException e) {
}
}
}
/**
* Maximum number of old consoles to keep open. If this number is exceeded the oldest console will
* be removed from the UI.
*/
private final int MAX_SIZE = 3;
public static Color getOutputColor() {
return DebugUIPlugin.getPreferenceColor(IDebugPreferenceConstants.CONSOLE_SYS_OUT_COLOR);
}
public static Color getErrorColor() {
return DebugUIPlugin.getPreferenceColor(IDebugPreferenceConstants.CONSOLE_SYS_ERR_COLOR);
}
public static Color getInputColor() {
return DebugUIPlugin.getPreferenceColor(IDebugPreferenceConstants.CONSOLE_SYS_IN_COLOR);
}
private LinkedList<IOConsole> history = new LinkedList<IOConsole>();
private void add(IOConsole console) {
IOConsole toClose = null;
synchronized (history) {
history.addLast(console);
if (history.size()>MAX_SIZE) {
toClose = history.removeFirst();
}
}
if (toClose!=null) {
close(toClose);
}
console.activate();
ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[]{ console });
}
private static void close(IOConsole console) {
ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new IConsole[] {console});
}
public Console getConsole(String title) {
final IOConsole console = new IOConsole(title, null);
final IOConsoleInputStream in = console.getInputStream();
final IOConsoleOutputStream out = console.newOutputStream();
final IOConsoleOutputStream err = console.newOutputStream();
in.setColor(getInputColor());
out.setColor(getOutputColor());
err.setColor(getErrorColor());
add(console);
return new Console(in, out, err);
}
}

View File

@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.tooling.ls.eclipse.commons.console;
import java.util.HashMap;
import java.util.Map;
import org.springframework.tooling.ls.eclipse.commons.console.ConsoleUtil.Console;
import com.google.common.base.Supplier;
public class LanguageServerConsoles {
private static Map<String, Supplier<Console>> managers;
public static synchronized Supplier<Console> getConsoleFactory(String languageServerName) {
if (managers==null) {
managers = new HashMap<>();
}
return managers.computeIfAbsent(languageServerName, label -> new Supplier<Console>() {
ConsoleUtil consoleMgr = new ConsoleUtil(); //one console manager per language server type. This way each has their
// own history (which limits number of open consoles per type)
int consoleCounter = 0;
@Override
public Console get() {
return consoleMgr.getConsole(languageServerName+" "+consoleCounter());
}
private synchronized int consoleCounter() {
return ++consoleCounter;
}
});
}
}

View File

@@ -30,6 +30,7 @@ import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessS
public class SpringBootPropertiesLanguageServer extends STS4LanguageServerProcessStreamConnector {
public SpringBootPropertiesLanguageServer() {
super("Boot Properties Language Server");
List<String> commands = new ArrayList<>();
commands.add(JRE.currentJRE().getJavaExecutable());
@@ -53,14 +54,26 @@ public class SpringBootPropertiesLanguageServer extends STS4LanguageServerProces
Bundle bundle = Platform.getBundle(Constants.PLUGIN_ID);
File dataFile = bundle.getDataFile(languageServer);
// if (!dataFile.exists()) {
try {
copyLanguageServerJAR(languageServer);
Exception error = null;
try {
copyLanguageServerJAR(languageServer);
}
catch (Exception e) {
error = e;
}
if (!dataFile.exists()) {
File userHome = new File(System.getProperty("user.home"));
File locallyBuiltJar = new File(
userHome,
"git/sts4/headless-services/boot-properties-language-server/target/boot-properties-language-server-"+Constants.LANGUAGE_SERVER_VERSION + ".jar"
);
if (locallyBuiltJar.exists()) {
return locallyBuiltJar.getAbsolutePath();
}
catch (Exception e) {
e.printStackTrace();
if (error!=null) {
error.printStackTrace();
}
// }
}
return dataFile.getAbsolutePath();
}