@@ -32,6 +32,26 @@ extension NSLock {
32
32
}
33
33
}
34
34
35
+ /// Gathers data from clangd's stderr pipe. When it has accumulated a full line, writes the the line to the logger.
36
+ fileprivate class ClangdStderrLogForwarder {
37
+ private var buffer = Data ( )
38
+
39
+ func handle( _ newData: Data ) {
40
+ self . buffer += newData
41
+ while let newlineIndex = self . buffer. firstIndex ( of: UInt8 ( ascii: " \n " ) ) {
42
+ // Output a separate log message for every line in clangd's stderr.
43
+ // The reason why we don't output multiple lines in a single log message is that
44
+ // a) os_log truncates log messages at about 1000 bytes. The assumption is that a single line is usually less
45
+ // than 1000 bytes long but if we merge multiple lines into one message, we might easily exceed this limit.
46
+ // b) It might be confusing why sometimes a single log message contains one line while sometimes it contains
47
+ // multiple.
48
+ let logger = Logger ( subsystem: subsystem, category: " clangd-stderr " )
49
+ logger. info ( " \( String ( data: self . buffer [ ... newlineIndex] , encoding: . utf8) ?? " <invalid UTF-8> " ) " )
50
+ buffer = buffer [ buffer. index ( after: newlineIndex) ... ]
51
+ }
52
+ }
53
+ }
54
+
35
55
/// A thin wrapper over a connection to a clangd server providing build setting handling.
36
56
///
37
57
/// In addition, it also intercepts notifications and replies from clangd in order to do things
@@ -203,6 +223,17 @@ actor ClangLanguageServerShim: ToolchainLanguageServer, MessageHandler {
203
223
204
224
process. standardOutput = clangdToUs
205
225
process. standardInput = usToClangd
226
+ let logForwarder = ClangdStderrLogForwarder ( )
227
+ let stderrHandler = Pipe ( )
228
+ stderrHandler. fileHandleForReading. readabilityHandler = { fileHandle in
229
+ let newData = fileHandle. availableData
230
+ if newData. count == 0 {
231
+ stderrHandler. fileHandleForReading. readabilityHandler = nil
232
+ } else {
233
+ logForwarder. handle ( newData)
234
+ }
235
+ }
236
+ process. standardError = stderrHandler
206
237
process. terminationHandler = { [ weak self] process in
207
238
logger. log (
208
239
level: process. terminationReason == . exit ? . default : . error,
0 commit comments