My code uses swift-log
to generate log messages.
My unit tests have been successfully migrated to swift-testing
.
I am on latest swift 6.0 with strict concurrency checking.
Now I want to bootstrap a global LoggingSystem
with LogHandler
for all my unit tests so that I can start logging.
import Foundation
import Testing
import Logging
let logger: Logger = {
LoggingSystem.bootstrap { label in
var handler = StreamLogHandler.standardOutput(label: label)
// handler.logLevel = .debug
return handler
}
return Logger(label: "logger")
}()
final class FunctionalityTests {
init() async throws {
// make sure logger + logger handler is initialised before being used
logger.trace("starting")
}
@Test func a() async throws {
// ...
}
@Test func b() async throws {
// ...
}
// ... and so on ...
}
Now I have multiple tests in this class. And all of them want to log. And all of them want to share one underlying LogHandler
.
I understand that swift-testing
allocates multiple instances of the FunctionalityTests
class and invokes a randomly selected test on each of those. They all share the same process. And they all run in parallel when invoked from the command line via swift test
.
I thought code above would be safe, but it's crashing randomly with:
Logging/Logging.swift:617: Precondition failed: logging system can only be initialized once per process.
This would indicate that global let logger = {}()
is being called multiple times.
But this is in swift 6 with strict mode enabled.
I thought this is never going to happen. Compiler is silent.
Help me please understand what I'm doing wrong. And how to properly initialise Logging
for swift-testing
.
thanks for any tips,
Martin
P.S. I found this bug filed against swift-testing
which I think hits the nail: test process bootstrap/async setup hook · Issue #328 · swiftlang/swift-testing · GitHub, but I'd still like to understand why is the code above not working. Shouldn't the global variable logger
be available once per process and initialised only once? What magic is happening here?