✨ Swift macros for easier logging via Apple’s unified logging system with optional 3rd-party logging support (e.g. Crashlytics)
#smartLog(logger, .info, "User \(userId) signed out at \(Date())")
Expands to:
{
logger.log(level: .info, "User \(userId) signed out at \(Date())")
SmartLogMacroCustomLogger.log("User \(userId) signed out at \(Date())")
}()
- 🔐 Privacy made easy – apply a single
privacy
setting to all interpolated values - 🔁 Optional external logging – forward the log message to any function (e.g. Crashlytics.crashlytics().log)
- ⚡ Zero runtime overhead – macro expands at compile-time
SmartLogMacro is available via Swift Package Manager.
To add it to your project in Xcode:
- Open your project.
- Go to File → Add Packages...
- Enter the URL: https://github.com/andriyGo/SmartLogMacro
- Select the version you want to use and press Add Package.
Or, add it manually to your Package.swift
:
dependencies: [
.package(url: "https://github.com/andriyGo/SmartLogMacro", from: "1.0.0")
]
Then add SmartLogMacro to your target dependencies:
.target(
name: "MyTarget",
dependencies: [.product(name: "SmartLogMacro", package: "SmartLogMacro")]
)
Macro | Privacy Level | External Logging | Description |
---|---|---|---|
#log |
configurable | optional | Full control over logging behaviour |
#logPublic |
.public |
optional | Shortcut for always-public logs |
#smartLog |
configurable | always enabled | Forwards to SmartLogMacroCustomLogger.log |
#smartLogPublic |
.public |
always enabled | Simplest usage – public logs + external forwarding |
With Apple's Logger
:
logger.info("Item \(item, privacy: .public) at \(indexPath, privacy: .public)")
With SmartLogMacro:
#log(logger, .info, "Item \(item) at \(indexPath)", privacy: .public)
Expands to:
logger.log(level: .info, "Item \(item, privacy: .public) at \(indexPath, privacy: .public)")
Or even shorter:
#logPublic(logger, .info, "Item \(item) at \(indexPath)")
#smartLog(logger, .error, "Sign-out failed for user: \(userId)")
#smartLogPublic(logger, .info, "User signed in: \(userId)")
To enable this, define:
struct SmartLogMacroCustomLogger {
static func log(_ message: String) {
Crashlytics.crashlytics().log(message)
}
}
Or use:
typealias SmartLogMacroCustomLogger = MyLogger
#log(logger, .error, "Error: \(error)", customLoggingFunction: Crashlytics.crashlytics().log)
#logPublic(logger, .error, "Unexpected logout", customLoggingFunction: MyLogger.send)
Define your own custom logger:
struct CustomLogger {
static func log(_ message: String) {
Crashlytics.crashlytics().log(message)
Analytics.logEvent("log", parameters: ["message": message])
}
}
- No trailing closure support for
customLoggingFunction
- Expanded macro uses a code block
May affect Xcode console line numbers. - No prefixing or metadata in external logs
Only raw message is passed.
💬 Most of these limitations stem from the desire to keep SmartLogMacro lightweight and simple in v1.
Contributions are welcome!
Open an issue or pull request — all feedback is appreciated.
Enjoying SmartLogMacro?
Buy me a coffee ☕💙
SmartLogMacro is available under the Apache License 2.0.
See the LICENSE file for full details.