What it is
SwiftLog is Apple's logging API package, defining a common interface that libraries log against and applications route to a backend of their choice.
Create a Logger with a label, log at a level with structured metadata, and bootstrap a backend once at startup.
Installation
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.0")Getting started
The smallest useful thing you can do with it, and what each part means.
swift
import Logging
// Once, at startup, before any Logger is created.
LoggingSystem.bootstrap { label in
var handler = StreamLogHandler.standardOutput(label: label)
handler.logLevel = .info
return handler
}
let logger = Logger(label: "com.example.books")
logger.info("request completed", metadata: [
"path": "/books",
"status": "200",
"duration_ms": "42",
])
// Autoclosure: the message is not built when the level is disabled.
logger.debug("cache state: \(expensiveDescription())")
logger.error("sync failed", metadata: ["error": "\(error)"])Advanced usage
Where the library earns its place over a simpler alternative.
swift
// A logger that stamps request context on every subsequent line.
var requestLogger = logger
requestLogger[metadataKey: "request_id"] = "\(requestID)"
requestLogger[metadataKey: "user_id"] = "\(userID)"
requestLogger.info("validating") // carries both keys
// Fan out to several destinations.
LoggingSystem.bootstrap { label in
MultiplexLogHandler([
StreamLogHandler.standardOutput(label: label),
CrashReportingLogHandler(label: label, minimumLevel: .warning),
])
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Log level changes have no effect
- bootstrap ran after loggers were created, or was called twice. Move it to the first line of main.
- No output at all on Linux
- The default handler writes to stdout; check that the level is not filtering everything, and that output is not buffered by the container.
Best practices
- Call LoggingSystem.bootstrap once, at the very start, before creating any Logger.
- Use metadata rather than string interpolation so a log platform can index the fields.
- Copy the logger and attach request metadata rather than passing context to every call.
- Libraries should depend on SwiftLog and never bootstrap — that is the application's decision.
Background
Why it exists, and what it was reacting to.
SwiftLog solves the same problem SLF4J solves on the JVM: a library should not dictate where logs go. It is an API with pluggable backends, not a logging implementation.
