From 364d0f33d4d18a1d69fb17c5cf6c1b1d00439eb8 Mon Sep 17 00:00:00 2001 From: ShootingStarDragons Date: Tue, 21 Jan 2025 10:58:37 +0900 Subject: [PATCH] feat: add tcpDebug option and tracing log support --- server/build.gradle.kts | 5 ++- .../org/javacs/kt/KotlinLanguageServer.kt | 7 +++- server/src/main/kotlin/org/javacs/kt/Main.kt | 13 ++++-- .../src/main/kotlin/org/javacs/kt/Logger.kt | 40 ++++++++++++++++--- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 915dcc767..b3ce3219c 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -9,8 +9,9 @@ plugins { id("kotlin-language-server.kotlin-conventions") } +val serverDebugPort = 4000 val debugPort = 8000 -val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y" +val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=$debugPort,suspend=n,quiet=y" val serverMainClassName = "org.javacs.kt.MainKt" val applicationName = "kotlin-language-server" @@ -88,6 +89,8 @@ tasks.register("debugRun") { standardInput = System.`in` jvmArgs(debugArgs) + args(listOf("--tcpServerPort", serverDebugPort, "--level", "trace", "--tcpDebug")) + doLast { println("Using debug port $debugPort") } } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index e8da0ff99..8dbb1bb49 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -23,7 +23,8 @@ import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture.completedFuture class KotlinLanguageServer( - val config: Configuration = Configuration() + val config: Configuration = Configuration(), + private val tcpDebug: Boolean = false ) : LanguageServer, LanguageClientAware, Closeable { val databaseService = DatabaseService() val classPath = CompilerClassPath(config.compiler, config.scripts, config.codegen, databaseService) @@ -56,7 +57,9 @@ class KotlinLanguageServer( override fun connect(client: LanguageClient) { this.client = client - connectLoggingBackend() + if (!tcpDebug) { + connectLoggingBackend() + } workspaces.connect(client) textDocuments.connect(client) diff --git a/server/src/main/kotlin/org/javacs/kt/Main.kt b/server/src/main/kotlin/org/javacs/kt/Main.kt index 7e19897c9..db0e5d1bc 100644 --- a/server/src/main/kotlin/org/javacs/kt/Main.kt +++ b/server/src/main/kotlin/org/javacs/kt/Main.kt @@ -7,7 +7,6 @@ import org.eclipse.lsp4j.launch.LSPLauncher import org.javacs.kt.util.ExitingInputStream import org.javacs.kt.util.tcpStartServer import org.javacs.kt.util.tcpConnectToClient - class Args { /* * The language server can currently be launched in three modes: @@ -15,13 +14,20 @@ class Args { * - TCP Server, in which case the client has to connect to the specified tcpServerPort (used by the Docker image) * - TCP Client, in which case the server will connect to the specified tcpClientPort/tcpClientHost (optionally used by VSCode) */ - @Parameter(names = ["--tcpServerPort", "-sp"]) var tcpServerPort: Int? = null + @Parameter(names = ["--tcpClientPort", "-p"]) var tcpClientPort: Int? = null + @Parameter(names = ["--tcpClientHost", "-h"]) var tcpClientHost: String = "localhost" + + @Parameter(names = ["--level"]) + var logLevel: String = "info" + + @Parameter(names = ["--tcpDebug"]) + var tcpDebug: Boolean = false } fun main(argv: Array) { @@ -39,7 +45,8 @@ fun main(argv: Array) { tcpStartServer(it) } ?: Pair(System.`in`, System.out) - val server = KotlinLanguageServer() + LOG.setLogLevel(args.logLevel) + val server = KotlinLanguageServer(tcpDebug = args.tcpDebug) val threads = Executors.newSingleThreadExecutor { Thread(it, "client") } val launcher = LSPLauncher.createServerLauncher(server, ExitingInputStream(inStream), outStream, threads) { it } diff --git a/shared/src/main/kotlin/org/javacs/kt/Logger.kt b/shared/src/main/kotlin/org/javacs/kt/Logger.kt index 68359f27a..c379ee130 100644 --- a/shared/src/main/kotlin/org/javacs/kt/Logger.kt +++ b/shared/src/main/kotlin/org/javacs/kt/Logger.kt @@ -12,7 +12,7 @@ import org.javacs.kt.util.DelegatePrintStream val LOG = Logger() -private class JULRedirector(private val downstream: Logger): Handler() { +private class JULRedirector(private val downstream: Logger) : Handler() { override fun publish(record: LogRecord) { when (record.level) { Level.SEVERE -> downstream.error(record.message) @@ -41,12 +41,23 @@ enum class LogLevel(val value: Int) { ALL(-100) } +fun String.toLogLevel(): LogLevel { + return when (this) { + "error" -> LogLevel.ERROR + "warn" -> LogLevel.WARN + "debug" -> LogLevel.DEBUG + "trace" -> LogLevel.TRACE + else -> LogLevel.INFO + } +} + class LogMessage( val level: LogLevel, - val message: String + val message: String, + private val funName: String? = null, ) { val formatted: String - get() = "[$level] $message" + get() = "[$level] ${funName?.let { "$it " } ?: ""}$message" } class Logger { @@ -60,6 +71,7 @@ class Logger { private val newline = System.lineSeparator() val logTime = false var level = LogLevel.INFO + var stackTracing = false; fun logError(msg: LogMessage) { if (errBackend == null) { @@ -78,14 +90,24 @@ class Logger { } private fun logWithPlaceholdersAt(msgLevel: LogLevel, msg: String, placeholders: Array) { + val stackTraceElement = if (stackTracing) { + Throwable("Capturing stack trace for logging").stackTrace.firstOrNull { it.className != this::class.java.name } + } else { + null + } if (level.value <= msgLevel.value) { - log(LogMessage(msgLevel, format(insertPlaceholders(msg, placeholders)))) + log(LogMessage(msgLevel, format(insertPlaceholders(msg, placeholders)), stackTraceElement?.className)) } } inline fun logWithLambdaAt(msgLevel: LogLevel, msg: () -> String) { + val stackTraceElement = if (stackTracing) { + Throwable("Capturing stack trace for logging").stackTrace.firstOrNull { it.className != this::class.java.name } + } else { + null + } if (level.value <= msgLevel.value) { - log(LogMessage(msgLevel, msg())) + log(LogMessage(msgLevel, msg(), stackTraceElement?.className)) } } @@ -119,6 +141,14 @@ class Logger { inline fun deepTrace(msg: () -> String) = logWithLambdaAt(LogLevel.DEEP_TRACE, msg) + fun setLogLevel(level: String) { + val logLevel = level.toLogLevel() + if (logLevel.value <= LogLevel.TRACE.value) { + stackTracing = true + } + this.level = logLevel + } + fun connectJULFrontend() { val rootLogger = java.util.logging.Logger.getLogger("") rootLogger.addHandler(JULRedirector(this))