Skip to content

Commit 91a0816

Browse files
authored
Merge pull request #1474 from ahoppen/logging-doc
Add a document to describe which log level to use
2 parents 5a611fb + 7f90508 commit 91a0816

16 files changed

+106
-48
lines changed

Documentation/Logging.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Logging
2+
3+
The following is a guide of how to write log messages and which level they should be logged at. There may be reasons to deviate from these guides but they should be a good starting point.
4+
5+
## Log Levels
6+
7+
The following log levels should be used by log messages in default. The [Explore logging in Swift](https://developer.apple.com/wwdc20/10168?time=604) session from WWDC20 has some explanation of how these levels are persisted by OS log and we follow those guidelines.
8+
9+
### Fault
10+
11+
> From Explore Logging in Swift: _Bug in program_
12+
13+
A bug in SourceKit-LSP, sourcekitd or any other project included in the Swift toolchain that should never happen and is not due to malformed user input. The fix for faults should always be in a project controlled by the Swift toolchain (most likely in SourceKit-LSP itself) and we should never close them as a third party to resolve. Think of these as light assertions that don’t crash sourcekit-lsp because it is able to recover in some way.
14+
15+
Examples:
16+
- Some global state invariant is broken like a file to `startProgress` not being followed by `endProgress`
17+
- sourcekitd crashes
18+
- Two targets in SwiftPM have the same name
19+
20+
### Error
21+
22+
> From Explore Logging in Swift: _Error seen during execution_
23+
24+
An error that is due to user input or eg. stale state of files on disk. It indicates that something is going wrong which might explain unexpected behavior. Errors could be due to malformed user input such as invalid requests from the editor or due to stale state that will eventually converge again.
25+
26+
Examples:
27+
- The client sends an invalid request
28+
- Preparation of a file failed due to a syntax error in the user’s code
29+
- The index contains a reference to a source file but the source fail has been modified since the index was last updated and is thus no longer valid
30+
31+
## Log/Notice/Default
32+
33+
`logger.default` logs at the `default` aka `notice` level.
34+
35+
> From Explore Logging in Swift: _Essential for troubleshooting_
36+
37+
Essential state transitions during SourceKit-LSP’s execution that allow use to determine what interactions the user performed. These logs will most likely be included in diagnose bundles from `sourcekit-lsp` diagnose and should help us solve most problems.
38+
39+
Examples:
40+
- The user sends an LSP request
41+
- Indexing of a file starts or finishes
42+
- New build settings for a file have been computed
43+
- Responses from sourcekitd
44+
45+
## Info
46+
47+
> From Explore Logging in Swift: _Helpful but not essential for troubleshooting_ (not persisted, logged to memory)
48+
49+
Internal state transitions that are helpful. If eg. a request fails and it’s not immediately obvious at which it failed, these should help us narrow down the code that it failed in. These messages might be missing from the logs generated by `sourcekit-lsp diagnose` and should not generally be needed to fix issues
50+
51+
Examples:
52+
- Requests sent to `sourcekitd` or `clangd`
53+
- Logging the main file for a header file
54+
55+
## Debug
56+
57+
> From Explore Logging in Swift: _Useful only during debugging_ (only logged during debugging)
58+
59+
Log messages that are useful eg. when debugging a test failure but that is not needed for diagnosing most real-world issues, like detailed information about when a function starts executing to diagnose race conditions.
60+
61+
Examples:
62+
- Tasks start and finish executing in `TaskScheduler`
63+
64+
## Log messages
65+
66+
Log messages should resemble English sentences and start with an uppercase letter. If the log is a single sentence it should not have a period at its end.
67+

Sources/LSPLogging/Logging.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/// Which log level to use (from https://developer.apple.com/wwdc20/10168?time=604)
14-
/// - Debug: Useful only during debugging (only logged during debugging)
15-
/// - Info: Helpful but not essential for troubleshooting (not persisted, logged to memory)
16-
/// - Notice/log/default: Essential for troubleshooting
17-
/// - Error: Error seen during execution
18-
/// - Used eg. if the user sends an erroneous request or if a request fails
19-
/// - Fault: Bug in program
20-
/// - Used eg. if invariants inside sourcekit-lsp are broken and the error is not due to user-provided input
21-
2213
import Foundation
2314

2415
#if canImport(os) && !SOURCEKITLSP_FORCE_NON_DARWIN_LOGGER

Sources/LanguageServerProtocolJSONRPC/JSONRPCConnection.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public final class JSONRPCConnection: Connection {
134134
queue: queue,
135135
cleanupHandler: { (error: Int32) in
136136
if error != 0 {
137-
logger.error("IO error \(error)")
137+
logger.fault("IO error \(error)")
138138
}
139139
ioGroup.leave()
140140
}
@@ -153,7 +153,7 @@ public final class JSONRPCConnection: Connection {
153153
queue: sendQueue,
154154
cleanupHandler: { (error: Int32) in
155155
if error != 0 {
156-
logger.error("IO error \(error)")
156+
logger.fault("IO error \(error)")
157157
}
158158
ioGroup.leave()
159159
}
@@ -195,7 +195,7 @@ public final class JSONRPCConnection: Connection {
195195
guard errorCode == 0 else {
196196
#if !os(Windows)
197197
if errorCode != POSIXError.ECANCELED.rawValue {
198-
logger.error("IO error reading \(errorCode)")
198+
logger.fault("IO error reading \(errorCode)")
199199
}
200200
#endif
201201
if done { self.closeAssumingOnQueue() }
@@ -365,7 +365,7 @@ public final class JSONRPCConnection: Connection {
365365
precondition(state != .created, "tried to send message before calling start(messageHandler:)")
366366
let ready = state == .running
367367
if shouldLog && !ready {
368-
logger.error("ignoring message; state = \(String(reflecting: self.state), privacy: .public)")
368+
logger.error("Ignoring message; state = \(String(reflecting: self.state), privacy: .public)")
369369
}
370370
return ready
371371
}
@@ -444,7 +444,7 @@ public final class JSONRPCConnection: Connection {
444444

445445
sendIO.write(offset: 0, data: dispatchData, queue: sendQueue) { [weak self] done, _, errorCode in
446446
if errorCode != 0 {
447-
logger.error("IO error sending message \(errorCode)")
447+
logger.fault("IO error sending message \(errorCode)")
448448
if done, let self {
449449
// An unrecoverable error occurs on the channel’s file descriptor.
450450
// Close the connection.
@@ -546,7 +546,7 @@ public final class JSONRPCConnection: Connection {
546546
guard state == .running else { return }
547547
state = .closed
548548

549-
logger.log("closing JSONRPCConnection...")
549+
logger.log("Closing JSONRPCConnection...")
550550
// Attempt to close the reader immediately; we do not need to accept remaining inputs.
551551
receiveIO.close(flags: .stop)
552552
// Close the writer after it finishes outstanding work.

Sources/SKCore/BuildServerBuildSystem.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public actor BuildServerBuildSystem: MessageHandler {
118118
// config file was missing, no build server for this workspace
119119
return nil
120120
} catch {
121-
logger.fault("failed to start build server: \(error.forLogging)")
121+
logger.fault("Failed to start build server: \(error.forLogging)")
122122
return nil
123123
}
124124
}
@@ -127,7 +127,7 @@ public actor BuildServerBuildSystem: MessageHandler {
127127
if let buildServer = self.buildServer {
128128
_ = buildServer.send(ShutdownBuild()) { result in
129129
if let error = result.failure {
130-
logger.fault("error shutting down build server: \(error.forLogging)")
130+
logger.fault("Error shutting down build server: \(error.forLogging)")
131131
}
132132
buildServer.send(ExitBuildNotification())
133133
buildServer.close()
@@ -175,7 +175,7 @@ public actor BuildServerBuildSystem: MessageHandler {
175175
let buildServer = try makeJSONRPCBuildServer(client: self, serverPath: serverPath, serverFlags: flags)
176176
let response = try await buildServer.send(initializeRequest)
177177
buildServer.send(InitializedBuildNotification())
178-
logger.log("initialized build server \(response.displayName)")
178+
logger.log("Initialized build server \(response.displayName)")
179179

180180
// see if index store was set as part of the server metadata
181181
if let indexDbPath = readReponseDataKey(data: response.data, key: "indexDatabasePath") {
@@ -307,7 +307,7 @@ extension BuildServerBuildSystem: BuildSystem {
307307
let request = RegisterForChanges(uri: uri, action: .register)
308308
_ = self.buildServer?.send(request) { result in
309309
if let error = result.failure {
310-
logger.error("error registering \(uri): \(error.forLogging)")
310+
logger.error("Error registering \(uri): \(error.forLogging)")
311311

312312
Task {
313313
// BuildServer registration failed, so tell our delegate that no build
@@ -324,7 +324,7 @@ extension BuildServerBuildSystem: BuildSystem {
324324
let request = RegisterForChanges(uri: uri, action: .unregister)
325325
_ = self.buildServer?.send(request) { result in
326326
if let error = result.failure {
327-
logger.error("error unregistering \(uri.forLogging): \(error.forLogging)")
327+
logger.error("Error unregistering \(uri.forLogging): \(error.forLogging)")
328328
}
329329
}
330330
}
@@ -416,7 +416,7 @@ private func makeJSONRPCBuildServer(
416416
process.terminationHandler = { process in
417417
logger.log(
418418
level: process.terminationReason == .exit ? .default : .error,
419-
"build server exited: \(String(reflecting: process.terminationReason)) \(process.terminationStatus)"
419+
"Build server exited: \(String(reflecting: process.terminationReason)) \(process.terminationStatus)"
420420
)
421421
connection.close()
422422
}

Sources/SKCore/BuildSystemManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ extension BuildSystemManager {
265265

266266
public func unregisterForChangeNotifications(for uri: DocumentURI) async {
267267
guard let mainFile = self.watchedFiles[uri]?.mainFile else {
268-
logger.error("Unbalanced calls for registerForChangeNotifications and unregisterForChangeNotifications")
268+
logger.fault("Unbalanced calls for registerForChangeNotifications and unregisterForChangeNotifications")
269269
return
270270
}
271271
self.watchedFiles[uri] = nil

Sources/SKCore/CompilationDatabaseBuildSystem.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ extension CompilationDatabaseBuildSystem: BuildSystem {
173173
}
174174

175175
if compdb == nil {
176-
logger.error("could not open compilation database for \(path)")
176+
logger.error("Could not open compilation database for \(path)")
177177
}
178178

179179
return compdb

Sources/SKSupport/Process+Run.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,14 @@ extension Process {
118118
private func setProcessPriority(pid: Process.ProcessID, newPriority: TaskPriority) {
119119
#if os(Windows)
120120
guard let handle = OpenProcess(UInt32(PROCESS_SET_INFORMATION), /*bInheritHandle*/ false, UInt32(pid)) else {
121-
logger.error("Failed to get process handle for \(pid) to change its priority: \(GetLastError())")
121+
logger.fault("Failed to get process handle for \(pid) to change its priority: \(GetLastError())")
122122
return
123123
}
124124
defer {
125125
CloseHandle(handle)
126126
}
127127
if !SetPriorityClass(handle, UInt32(newPriority.windowsProcessPriority)) {
128-
logger.error("Failed to set process priority of \(pid) to \(newPriority.rawValue): \(GetLastError())")
128+
logger.fault("Failed to set process priority of \(pid) to \(newPriority.rawValue): \(GetLastError())")
129129
}
130130
#elseif canImport(Darwin) || canImport(Android)
131131
// `setpriority` is only able to decrease a process's priority and cannot elevate it. Since Swift task’s priorities

Sources/SKSwiftPMWorkspace/SwiftPMBuildSystem.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public actor SwiftPMBuildSystem {
305305
} catch Error.noManifest {
306306
return nil
307307
} catch {
308-
logger.error("failed to create SwiftPMWorkspace at \(uri.forLogging): \(error.forLogging)")
308+
logger.error("Failed to create SwiftPMWorkspace at \(uri.forLogging): \(error.forLogging)")
309309
return nil
310310
}
311311
}
@@ -450,7 +450,7 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
450450
}
451451

452452
guard let buildTarget = self.targets[configuredTarget]?.buildTarget else {
453-
logger.error("Did not find target with name \(configuredTarget.targetID)")
453+
logger.fault("Did not find target with name \(configuredTarget.targetID)")
454454
return nil
455455
}
456456

Sources/SourceKitLSP/CapabilityRegistry.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public final actor CapabilityRegistry {
141141
) async {
142142
if let registration = registration(for: languages, in: registrationDict) {
143143
if options != registration {
144-
logger.error(
144+
logger.fault(
145145
"""
146146
Failed to dynamically register for \(method, privacy: .public) for \(languages, privacy: .public) \
147147
due to pre-existing options:
@@ -200,7 +200,7 @@ public final actor CapabilityRegistry {
200200
guard clientHasDynamicDidChangeWatchedFilesRegistration else { return }
201201
if let registration = didChangeWatchedFiles {
202202
if watchers != registration.watchers {
203-
logger.error(
203+
logger.fault(
204204
"Unable to register new file system watchers \(watchers) due to pre-existing options \(registration.watchers)"
205205
)
206206
}

Sources/SourceKitLSP/CreateBuildSystem.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func createBuildSystem(
2929
// We assume that workspaces are directories. This is only true for URLs not for URIs in general.
3030
// Simply skip setting up the build integration in this case.
3131
logger.error(
32-
"cannot setup build integration at URI \(rootUri.forLogging) because the URI it is not a valid file URL"
32+
"Cannot setup build integration at URI \(rootUri.forLogging) because the URI it is not a valid file URL"
3333
)
3434
return nil
3535
}

Sources/SourceKitLSP/Rename.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ extension SourceKitLSPServer {
537537
) async throws -> CrossLanguageName? {
538538
let definitions = index.occurrences(ofUSR: usr, roles: [.definition])
539539
if definitions.isEmpty {
540-
logger.error("no definitions for \(usr) found")
540+
logger.error("No definitions for \(usr) found")
541541
return nil
542542
}
543543
if definitions.count > 1 {

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ extension SourceKitLSPServer {
931931
do {
932932
try await buildSystem?.generateBuildGraph(allowFileSystemWrites: true)
933933
} catch {
934-
logger.error("failed to generate build graph at \(workspaceFolder.uri.forLogging): \(error.forLogging)")
934+
logger.error("Failed to generate build graph at \(workspaceFolder.uri.forLogging): \(error.forLogging)")
935935
return nil
936936
}
937937

@@ -990,7 +990,7 @@ extension SourceKitLSPServer {
990990
case .some(.int(let maxResults)):
991991
self.options.completionOptions.maxResults = maxResults
992992
case .some(let invalid):
993-
logger.error("expected null or int for 'maxResults'; got \(String(reflecting: invalid))")
993+
logger.error("Expected null or int for 'maxResults'; got \(String(reflecting: invalid))")
994994
}
995995
}
996996
}
@@ -1018,7 +1018,7 @@ extension SourceKitLSPServer {
10181018
}
10191019

10201020
if self.workspaces.isEmpty {
1021-
logger.error("no workspace found")
1021+
logger.error("No workspace found")
10221022

10231023
let workspace = await Workspace(
10241024
documentManager: self.documentManager,
@@ -1278,7 +1278,7 @@ extension SourceKitLSPServer {
12781278
let uri = notification.textDocument.uri
12791279
guard let workspace = await workspaceForDocument(uri: uri) else {
12801280
logger.error(
1281-
"received open notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
1281+
"Received open notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
12821282
)
12831283
return
12841284
}
@@ -1310,7 +1310,7 @@ extension SourceKitLSPServer {
13101310
let uri = notification.textDocument.uri
13111311
guard let workspace = await workspaceForDocument(uri: uri) else {
13121312
logger.error(
1313-
"received close notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
1313+
"Received close notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
13141314
)
13151315
return
13161316
}
@@ -1321,7 +1321,7 @@ extension SourceKitLSPServer {
13211321
let uri = notification.textDocument.uri
13221322
guard let workspace = await workspaceForDocument(uri: uri) else {
13231323
logger.error(
1324-
"received reopen notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
1324+
"Received reopen notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
13251325
)
13261326
return
13271327
}
@@ -1345,7 +1345,7 @@ extension SourceKitLSPServer {
13451345

13461346
guard let workspace = await workspaceForDocument(uri: uri) else {
13471347
logger.error(
1348-
"received change notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
1348+
"Received change notification for file '\(uri.forLogging)' without a corresponding workspace, ignoring..."
13491349
)
13501350
return
13511351
}
@@ -1597,7 +1597,7 @@ extension SourceKitLSPServer {
15971597

15981598
func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny? {
15991599
guard let uri = req.textDocument?.uri else {
1600-
logger.error("attempted to perform executeCommand request without an url!")
1600+
logger.error("Attempted to perform executeCommand request without an URL")
16011601
return nil
16021602
}
16031603
guard let workspace = await workspaceForDocument(uri: uri) else {
@@ -1704,7 +1704,7 @@ extension SourceKitLSPServer {
17041704
}
17051705
}
17061706
guard let usr = symbol.usr else { return [] }
1707-
logger.info("performing indexed jump-to-def with usr \(usr)")
1707+
logger.info("Performing indexed jump-to-definition with USR \(usr)")
17081708
var occurrences = index.definitionOrDeclarationOccurrences(ofUSR: usr)
17091709
if symbol.isDynamic ?? true {
17101710
lazy var transitiveReceiverUsrs: [String]? = {

Sources/SourceKitLSP/Swift/Diagnostic.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extension CodeAction {
3232
}
3333

3434
if !editsMapped {
35-
logger.fault("failed to construct TextEdits from response \(fixits)")
35+
logger.fault("Failed to construct TextEdits from response \(fixits)")
3636
return nil
3737
}
3838

@@ -374,7 +374,7 @@ extension DiagnosticStage {
374374
self = .sema
375375
default:
376376
let desc = sourcekitd.api.uid_get_string_ptr(uid).map { String(cString: $0) }
377-
logger.fault("unknown diagnostic stage \(desc ?? "nil", privacy: .public)")
377+
logger.fault("Unknown diagnostic stage \(desc ?? "nil", privacy: .public)")
378378
return nil
379379
}
380380
}

Sources/SourceKitLSP/Swift/RewriteSourceKitPlaceholders.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ func rewriteSourceKitPlaceholders(in string: String, clientSupportsSnippets: Boo
1818
var index = 1
1919
while let start = result.range(of: "<#") {
2020
guard let end = result[start.upperBound...].range(of: "#>") else {
21-
logger.error("invalid placeholder in \(string)")
21+
logger.fault("Invalid placeholder in \(string)")
2222
return string
2323
}
2424
let rawPlaceholder = String(result[start.lowerBound..<end.upperBound])
2525
guard let displayName = EditorPlaceholderData(text: rawPlaceholder)?.nameForSnippet else {
26-
logger.error("failed to decode placeholder \(rawPlaceholder) in \(string)")
26+
logger.fault("Failed to decode placeholder \(rawPlaceholder) in \(string)")
2727
return string
2828
}
2929
let snippet = clientSupportsSnippets ? "${\(index):\(displayName)}" : ""

0 commit comments

Comments
 (0)