Skip to content

Commit 2ea49b1

Browse files
committed
feat: add tcpDebug option and tracing
this made me easier to debug the project and fix some warning
1 parent 18e65bc commit 2ea49b1

File tree

5 files changed

+124
-75
lines changed

5 files changed

+124
-75
lines changed

server/build.gradle.kts

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ plugins {
99
id("kotlin-language-server.kotlin-conventions")
1010
}
1111

12+
val serverDebugPort = 4000
1213
val debugPort = 8000
13-
val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"
14+
val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=$debugPort,suspend=n,quiet=y"
1415

1516
val serverMainClassName = "org.javacs.kt.MainKt"
1617
val applicationName = "kotlin-language-server"
@@ -91,6 +92,7 @@ tasks.register<JavaExec>("debugRun") {
9192
standardInput = System.`in`
9293

9394
jvmArgs(debugArgs)
95+
args(listOf("--tcpServerPort", serverDebugPort, "--tcpDebug", "--tracingLog"))
9496
doLast { println("Using debug port $debugPort") }
9597
}
9698

server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt

+28-12
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,29 @@ import java.util.concurrent.CompletableFuture
2323
import java.util.concurrent.CompletableFuture.completedFuture
2424

2525
class KotlinLanguageServer(
26-
val config: Configuration = Configuration()
26+
val config: Configuration = Configuration(),
27+
private val tcpDebug: Boolean = false
2728
) : LanguageServer, LanguageClientAware, Closeable {
28-
val databaseService = DatabaseService()
29+
private val databaseService = DatabaseService()
2930
val classPath = CompilerClassPath(config.compiler, config.scripts, config.codegen, databaseService)
3031

3132
private val tempDirectory = TemporaryDirectory()
32-
private val uriContentProvider = URIContentProvider(ClassContentProvider(config.externalSources, classPath, tempDirectory, CompositeSourceArchiveProvider(JdkSourceArchiveProvider(classPath), ClassPathSourceArchiveProvider(classPath))))
33+
private val uriContentProvider = URIContentProvider(
34+
ClassContentProvider(
35+
config.externalSources,
36+
classPath,
37+
tempDirectory,
38+
CompositeSourceArchiveProvider(
39+
JdkSourceArchiveProvider(classPath),
40+
ClassPathSourceArchiveProvider(classPath)
41+
)
42+
)
43+
)
3344
val sourcePath = SourcePath(classPath, uriContentProvider, config.indexing, databaseService)
34-
val sourceFiles = SourceFiles(sourcePath, uriContentProvider, config.scripts)
45+
private val sourceFiles = SourceFiles(sourcePath, uriContentProvider, config.scripts)
3546

36-
private val textDocuments = KotlinTextDocumentService(sourceFiles, sourcePath, config, tempDirectory, uriContentProvider, classPath)
47+
private val textDocuments =
48+
KotlinTextDocumentService(sourceFiles, sourcePath, config, tempDirectory, uriContentProvider, classPath)
3749
private val workspaces = KotlinWorkspaceService(sourceFiles, sourcePath, classPath, textDocuments, config)
3850
private val protocolExtensions = KotlinProtocolExtensionService(uriContentProvider, classPath, sourcePath)
3951

@@ -56,7 +68,9 @@ class KotlinLanguageServer(
5668

5769
override fun connect(client: LanguageClient) {
5870
this.client = client
59-
connectLoggingBackend()
71+
if (!tcpDebug) {
72+
connectLoggingBackend()
73+
}
6074

6175
workspaces.connect(client)
6276
textDocuments.connect(client)
@@ -87,7 +101,8 @@ class KotlinLanguageServer(
87101
serverCapabilities.documentSymbolProvider = Either.forLeft(true)
88102
serverCapabilities.workspaceSymbolProvider = Either.forLeft(true)
89103
serverCapabilities.referencesProvider = Either.forLeft(true)
90-
serverCapabilities.semanticTokensProvider = SemanticTokensWithRegistrationOptions(semanticTokensLegend, true, true)
104+
serverCapabilities.semanticTokensProvider =
105+
SemanticTokensWithRegistrationOptions(semanticTokensLegend, true, true)
91106
serverCapabilities.codeActionProvider = Either.forLeft(true)
92107
serverCapabilities.documentFormattingProvider = Either.forLeft(true)
93108
serverCapabilities.documentRangeFormattingProvider = Either.forLeft(true)
@@ -98,13 +113,14 @@ class KotlinLanguageServer(
98113
databaseService.setup(storagePath)
99114

100115
val clientCapabilities = params.capabilities
101-
config.completion.snippets.enabled = clientCapabilities?.textDocument?.completion?.completionItem?.snippetSupport ?: false
116+
config.completion.snippets.enabled =
117+
clientCapabilities?.textDocument?.completion?.completionItem?.snippetSupport ?: false
102118

103-
if (clientCapabilities?.window?.workDoneProgress ?: false) {
119+
if (clientCapabilities?.window?.workDoneProgress == true) {
104120
progressFactory = LanguageClientProgress.Factory(client)
105121
}
106122

107-
if (clientCapabilities?.textDocument?.rename?.prepareSupport ?: false) {
123+
if (clientCapabilities?.textDocument?.rename?.prepareSupport == true) {
108124
serverCapabilities.renameProvider = Either.forRight(RenameOptions(false))
109125
}
110126

@@ -176,6 +192,6 @@ class KotlinLanguageServer(
176192
// Fixed in https://github.com/eclipse/lsp4j/commit/04b0c6112f0a94140e22b8b15bb5a90d5a0ed851
177193
// Causes issue in lsp 0.15
178194
override fun getNotebookDocumentService(): NotebookDocumentService? {
179-
return null;
180-
}
195+
return null;
196+
}
181197
}

server/src/main/kotlin/org/javacs/kt/Main.kt

+12-3
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,27 @@ import org.eclipse.lsp4j.launch.LSPLauncher
77
import org.javacs.kt.util.ExitingInputStream
88
import org.javacs.kt.util.tcpStartServer
99
import org.javacs.kt.util.tcpConnectToClient
10-
1110
class Args {
1211
/*
1312
* The language server can currently be launched in three modes:
1413
* - Stdio, in which case no argument should be specified (used by default)
1514
* - TCP Server, in which case the client has to connect to the specified tcpServerPort (used by the Docker image)
1615
* - TCP Client, in which case the server will connect to the specified tcpClientPort/tcpClientHost (optionally used by VSCode)
1716
*/
18-
1917
@Parameter(names = ["--tcpServerPort", "-sp"])
2018
var tcpServerPort: Int? = null
19+
2120
@Parameter(names = ["--tcpClientPort", "-p"])
2221
var tcpClientPort: Int? = null
22+
2323
@Parameter(names = ["--tcpClientHost", "-h"])
2424
var tcpClientHost: String = "localhost"
25+
26+
@Parameter(names = ["--tcpDebug"])
27+
var tcpDebug: Boolean = false
28+
29+
@Parameter(names = ["--tracingLog"])
30+
var tracingLog: Boolean = false
2531
}
2632

2733
fun main(argv: Array<String>) {
@@ -39,7 +45,10 @@ fun main(argv: Array<String>) {
3945
tcpStartServer(it)
4046
} ?: Pair(System.`in`, System.out)
4147

42-
val server = KotlinLanguageServer()
48+
if (args.tracingLog) {
49+
LOG.setTracing()
50+
}
51+
val server = KotlinLanguageServer(tcpDebug = args.tcpDebug)
4352
val threads = Executors.newSingleThreadExecutor { Thread(it, "client") }
4453
val launcher = LSPLauncher.createServerLauncher(server, ExitingInputStream(inStream), outStream, threads) { it }
4554

shared/src/main/kotlin/org/javacs/kt/Logger.kt

+42-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import org.javacs.kt.util.DelegatePrintStream
1212

1313
val LOG = Logger()
1414

15-
private class JULRedirector(private val downstream: Logger): Handler() {
15+
private class JULRedirector(private val downstream: Logger) : Handler() {
1616
override fun publish(record: LogRecord) {
1717
when (record.level) {
1818
Level.SEVERE -> downstream.error(record.message)
@@ -43,10 +43,17 @@ enum class LogLevel(val value: Int) {
4343

4444
class LogMessage(
4545
val level: LogLevel,
46-
val message: String
46+
val message: String,
47+
private val funName: String? = null,
4748
) {
4849
val formatted: String
49-
get() = "[$level] $message"
50+
get() {
51+
return if (funName != null) {
52+
"[$level] $funName $message"
53+
} else {
54+
"[$level] $message"
55+
}
56+
}
5057
}
5158

5259
class Logger {
@@ -58,10 +65,11 @@ class Logger {
5865
val outStream = DelegatePrintStream { log(LogMessage(LogLevel.INFO, it.trimEnd())) }
5966

6067
private val newline = System.lineSeparator()
61-
val logTime = false
68+
private val logTime = false
6269
var level = LogLevel.INFO
70+
var tracingLog = false;
6371

64-
fun logError(msg: LogMessage) {
72+
private fun logError(msg: LogMessage) {
6573
if (errBackend == null) {
6674
errQueue.offer(msg)
6775
} else {
@@ -78,14 +86,24 @@ class Logger {
7886
}
7987

8088
private fun logWithPlaceholdersAt(msgLevel: LogLevel, msg: String, placeholders: Array<out Any?>) {
89+
val stackTraceElement = if (tracingLog) {
90+
Throwable("Capturing stack trace for logging").stackTrace.firstOrNull { it.className != this::class.java.name }
91+
} else {
92+
null
93+
}
8194
if (level.value <= msgLevel.value) {
82-
log(LogMessage(msgLevel, format(insertPlaceholders(msg, placeholders))))
95+
log(LogMessage(msgLevel, format(insertPlaceholders(msg, placeholders)), stackTraceElement?.className))
8396
}
8497
}
8598

86-
inline fun logWithLambdaAt(msgLevel: LogLevel, msg: () -> String) {
99+
inline fun logWithLambdaAt(msgLevel: LogLevel, crossinline msg: () -> String) {
100+
val stackTraceElement = if (tracingLog) {
101+
Throwable("Capturing stack trace for logging").stackTrace.firstOrNull { it.className != this::class.java.name }
102+
} else {
103+
null
104+
}
87105
if (level.value <= msgLevel.value) {
88-
log(LogMessage(msgLevel, msg()))
106+
log(LogMessage(msgLevel, msg(), stackTraceElement?.className))
89107
}
90108
}
91109

@@ -103,22 +121,26 @@ class Logger {
103121

104122
fun trace(msg: String, vararg placeholders: Any?) = logWithPlaceholdersAt(LogLevel.TRACE, msg, placeholders)
105123

106-
fun deepTrace(msg: String, vararg placeholders: Any?) = logWithPlaceholdersAt(LogLevel.DEEP_TRACE, msg, placeholders)
124+
fun deepTrace(msg: String, vararg placeholders: Any?) =
125+
logWithPlaceholdersAt(LogLevel.DEEP_TRACE, msg, placeholders)
107126

108127
// Convenience logging methods using inlined lambdas
109128

110-
inline fun error(msg: () -> String) = logWithLambdaAt(LogLevel.ERROR, msg)
129+
inline fun error(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.ERROR, msg)
111130

112-
inline fun warn(msg: () -> String) = logWithLambdaAt(LogLevel.WARN, msg)
131+
inline fun warn(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.WARN, msg)
113132

114-
inline fun info(msg: () -> String) = logWithLambdaAt(LogLevel.INFO, msg)
133+
inline fun info(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.INFO, msg)
115134

116-
inline fun debug(msg: () -> String) = logWithLambdaAt(LogLevel.DEBUG, msg)
135+
inline fun debug(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.DEBUG, msg)
117136

118-
inline fun trace(msg: () -> String) = logWithLambdaAt(LogLevel.TRACE, msg)
137+
inline fun trace(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.TRACE, msg)
119138

120-
inline fun deepTrace(msg: () -> String) = logWithLambdaAt(LogLevel.DEEP_TRACE, msg)
139+
inline fun deepTrace(crossinline msg: () -> String) = logWithLambdaAt(LogLevel.DEEP_TRACE, msg)
121140

141+
fun setTracing() {
142+
tracingLog = true
143+
}
122144
fun connectJULFrontend() {
123145
val rootLogger = java.util.logging.Logger.getLogger("")
124146
rootLogger.addHandler(JULRedirector(this))
@@ -182,9 +204,9 @@ class Logger {
182204
}
183205

184206
private fun shortenOrPad(str: String, length: Int): String =
185-
if (str.length <= length) {
186-
str.padEnd(length, ' ')
187-
} else {
188-
".." + str.substring(str.length - length + 2)
189-
}
207+
if (str.length <= length) {
208+
str.padEnd(length, ' ')
209+
} else {
210+
".." + str.substring(str.length - length + 2)
211+
}
190212
}

shared/src/main/kotlin/org/javacs/kt/util/DelegatePrintStream.kt

+39-39
Original file line numberDiff line numberDiff line change
@@ -4,67 +4,67 @@ import java.io.ByteArrayOutputStream
44
import java.io.PrintStream
55
import java.util.function.Consumer
66

7-
class DelegatePrintStream(private val delegate: (String) -> Unit): PrintStream(ByteArrayOutputStream(0)) {
8-
private val newLine = System.lineSeparator()
7+
class DelegatePrintStream(private val delegate: (String) -> Unit) : PrintStream(ByteArrayOutputStream(0)) {
8+
private val newLine = System.lineSeparator()
99

10-
override fun write(c: Int) = delegate((c.toChar()).toString())
10+
override fun write(c: Int) = delegate((c.toChar()).toString())
1111

12-
override fun write(buf: ByteArray, off: Int, len: Int) {
13-
if (len > 0 && buf.size > 0) {
14-
delegate(String(buf, off, len))
15-
}
16-
}
12+
override fun write(buf: ByteArray, off: Int, len: Int) {
13+
if (len > 0 && buf.isNotEmpty()) {
14+
delegate(String(buf, off, len))
15+
}
16+
}
1717

18-
override fun append(csq: CharSequence): PrintStream {
19-
delegate(csq.toString())
20-
return this
21-
}
18+
override fun append(csq: CharSequence): PrintStream {
19+
delegate(csq.toString())
20+
return this
21+
}
2222

23-
override fun append(csq: CharSequence, start: Int, end: Int): PrintStream {
24-
delegate(csq.subSequence(start, end).toString())
25-
return this
26-
}
23+
override fun append(csq: CharSequence, start: Int, end: Int): PrintStream {
24+
delegate(csq.subSequence(start, end).toString())
25+
return this
26+
}
2727

28-
override fun append(c:Char): PrintStream {
29-
delegate((c).toString())
30-
return this
31-
}
28+
override fun append(c: Char): PrintStream {
29+
delegate((c).toString())
30+
return this
31+
}
3232

33-
override fun print(x: Boolean) = delegate(x.toString())
33+
override fun print(x: Boolean) = delegate(x.toString())
3434

35-
override fun print(x: Char) = delegate(x.toString())
35+
override fun print(x: Char) = delegate(x.toString())
3636

37-
override fun print(x: Int) = delegate(x.toString())
37+
override fun print(x: Int) = delegate(x.toString())
3838

39-
override fun print(x: Long) = delegate(x.toString())
39+
override fun print(x: Long) = delegate(x.toString())
4040

41-
override fun print(x: Float) = delegate(x.toString())
41+
override fun print(x: Float) = delegate(x.toString())
4242

43-
override fun print(x: Double) = delegate(x.toString())
43+
override fun print(x: Double) = delegate(x.toString())
4444

45-
override fun print(s: CharArray) = delegate(String(s))
45+
override fun print(s: CharArray) = delegate(String(s))
4646

47-
override fun print(s: String) = delegate(s)
47+
override fun print(s: String?) = delegate(s ?: "null")
4848

49-
override fun print(obj: Any) = delegate(obj.toString())
49+
override fun print(obj: Any?) = delegate(obj.toString())
5050

51-
override fun println() = delegate(newLine)
51+
override fun println() = delegate(newLine)
5252

53-
override fun println(x: Boolean) = delegate(x.toString() + newLine)
53+
override fun println(x: Boolean) = delegate(x.toString() + newLine)
5454

55-
override fun println(x: Char) = delegate(x.toString() + newLine)
55+
override fun println(x: Char) = delegate(x.toString() + newLine)
5656

57-
override fun println(x: Int) = delegate(x.toString() + newLine)
57+
override fun println(x: Int) = delegate(x.toString() + newLine)
5858

59-
override fun println(x: Long) = delegate(x.toString() + newLine)
59+
override fun println(x: Long) = delegate(x.toString() + newLine)
6060

61-
override fun println(x: Float) = delegate(x.toString() + newLine)
61+
override fun println(x: Float) = delegate(x.toString() + newLine)
6262

63-
override fun println(x: Double) = delegate(x.toString() + newLine)
63+
override fun println(x: Double) = delegate(x.toString() + newLine)
6464

65-
override fun println(x: CharArray) = delegate(String(x) + newLine)
65+
override fun println(x: CharArray) = delegate(String(x) + newLine)
6666

67-
override fun println(x: String) = delegate(x + newLine)
67+
override fun println(x: String?) = delegate((x ?: "null") + newLine)
6868

69-
override fun println(x: Any) = delegate(x.toString() + newLine)
69+
override fun println(x: Any?) = delegate(x.toString() + newLine)
7070
}

0 commit comments

Comments
 (0)