Skip to content

Commit 5f69147

Browse files
committed
Remove logging dependency from SourceKitD
Make logging protocol requirements on `SourceKitD` so that implementers of the protocol can decide how to log requests. This allows us to add different kinds of sourcekitd connections that behave differently in the future, for example one that dynamically links against sourcekitd instead of loading it it using `dlopen`.
1 parent 4269e90 commit 5f69147

File tree

2 files changed

+67
-44
lines changed

2 files changed

+67
-44
lines changed

Sources/SourceKitD/SourceKitD.swift

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
@_exported import Csourcekitd
1414
import Dispatch
1515
import Foundation
16-
import LSPLogging
1716
import SKSupport
1817

1918
/// Access to sourcekitd API, taking care of initialization, shutdown, and notification handler
@@ -42,6 +41,24 @@ public protocol SourceKitD: AnyObject {
4241

4342
/// Removes a previously registered notification handler.
4443
func removeNotificationHandler(_ handler: SKDNotificationHandler)
44+
45+
/// Log the given request.
46+
///
47+
/// This log call is issued during normal operation. It is acceptable for the logger to truncate the log message
48+
/// to achieve good performance.
49+
func log(request: SKDRequestDictionary)
50+
51+
/// Log the given request and file contents, ensuring they do not get truncated.
52+
///
53+
/// This log call is used when a request has crashed. In this case we want the log to contain the entire request to be
54+
/// able to reproduce it.
55+
func log(crashedRequest: SKDRequestDictionary, fileContents: String?)
56+
57+
/// Log the given response.
58+
///
59+
/// This log call is issued during normal operation. It is acceptable for the logger to truncate the log message
60+
/// to achieve good performance.
61+
func log(response: SKDResponse)
4562
}
4663

4764
public enum SKDError: Error, Equatable {
@@ -70,11 +87,7 @@ extension SourceKitD {
7087
/// - fileContents: The contents of the file that the request operates on. If sourcekitd crashes, the file contents
7188
/// will be logged.
7289
public func send(_ req: SKDRequestDictionary, fileContents: String?) async throws -> SKDResponseDictionary {
73-
logRequest(req)
74-
75-
let signposter = logger.makeSignposter()
76-
let signpostID = signposter.makeSignpostID()
77-
let signposterState = signposter.beginInterval("sourcekitd-request", id: signpostID, "Start")
90+
log(request: req)
7891

7992
let sourcekitdResponse: SKDResponse = try await withCancellableCheckedThrowingContinuation { continuation in
8093
var handle: sourcekitd_api_request_handle_t? = nil
@@ -83,56 +96,26 @@ extension SourceKitD {
8396
}
8497
return handle
8598
} cancel: { handle in
86-
api.cancel_request(handle)
99+
if let handle {
100+
api.cancel_request(handle)
101+
}
87102
}
88103

89-
logResponse(sourcekitdResponse)
104+
log(response: sourcekitdResponse)
90105

91106
guard let dict = sourcekitdResponse.value else {
92-
signposter.endInterval("sourcekitd-request", signposterState, "Error")
93107
if sourcekitdResponse.error == .connectionInterrupted {
94-
let log = """
95-
Request:
96-
\(req.description)
97-
98-
File contents:
99-
\(fileContents ?? "<nil>")
100-
"""
101-
let chunks = splitLongMultilineMessage(message: log)
102-
for (index, chunk) in chunks.enumerated() {
103-
logger.fault(
104-
"""
105-
sourcekitd crashed (\(index + 1)/\(chunks.count))
106-
\(chunk)
107-
"""
108-
)
109-
}
108+
log(crashedRequest: req, fileContents: fileContents)
110109
}
111110
throw sourcekitdResponse.error!
112111
}
113112

114-
signposter.endInterval("sourcekitd-request", signposterState, "Done")
115113
return dict
116114
}
117-
}
118-
119-
private func logRequest(_ request: SKDRequestDictionary) {
120-
logger.info(
121-
"""
122-
Sending sourcekitd request:
123-
\(request.forLogging)
124-
"""
125-
)
126-
}
127115

128-
private func logResponse(_ response: SKDResponse) {
129-
logger.log(
130-
level: (response.error == nil || response.error == .requestCancelled) ? .debug : .error,
131-
"""
132-
Received sourcekitd response:
133-
\(response.forLogging)
134-
"""
135-
)
116+
public func log(request: SKDRequestDictionary) {}
117+
public func log(response: SKDResponse) {}
118+
public func log(crashedRequest: SKDRequestDictionary, fileContents: String?) {}
136119
}
137120

138121
/// A sourcekitd notification handler in a class to allow it to be uniquely referenced.

Sources/SourceKitD/SourceKitDImpl.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Foundation
14+
import LSPLogging
1415
import SKSupport
1516

1617
import struct TSCBasic.AbsolutePath
@@ -96,6 +97,45 @@ public final class SourceKitDImpl: SourceKitD {
9697
_notificationHandlers.removeAll(where: { $0.value == nil || $0.value === handler })
9798
}
9899
}
100+
101+
public func log(request: SKDRequestDictionary) {
102+
logger.info(
103+
"""
104+
Sending sourcekitd request:
105+
\(request.forLogging)
106+
"""
107+
)
108+
}
109+
110+
public func log(response: SKDResponse) {
111+
logger.log(
112+
level: (response.error == nil || response.error == .requestCancelled) ? .debug : .error,
113+
"""
114+
Received sourcekitd response:
115+
\(response.forLogging)
116+
"""
117+
)
118+
}
119+
120+
public func log(crashedRequest req: SKDRequestDictionary, fileContents: String?) {
121+
let log = """
122+
Request:
123+
\(req.description)
124+
125+
File contents:
126+
\(fileContents ?? "<nil>")
127+
"""
128+
let chunks = splitLongMultilineMessage(message: log)
129+
for (index, chunk) in chunks.enumerated() {
130+
logger.fault(
131+
"""
132+
sourcekitd crashed (\(index + 1)/\(chunks.count))
133+
\(chunk)
134+
"""
135+
)
136+
}
137+
}
138+
99139
}
100140

101141
struct WeakSKDNotificationHandler {

0 commit comments

Comments
 (0)