π Learn how to build and use this package: https://www.swiftful-thinking.com/offers/REyNLwwH
A reusable logger for Swift applications, built for Swift 6. LogManager coordinates multiple LogService implementations (Console, Firebase, Mixpanel, etc.) through a single API. Includes @Observable support.
Details (Click to expand)
Add SwiftfulLogging to your project.
https://github.com/SwiftfulThinking/SwiftfulLogging.git
Import the package.
import SwiftfulLoggingCreate an instance of LogManager with one or more services:
// Development β console only
let logger = LogManager(services: [ConsoleService()])
// Production β multiple services
let logger = LogManager(services: [
ConsoleService(),
FirebaseAnalyticsService(),
FirebaseCrashlyticsService(),
MixpanelService(token: "your_token")
])Optionally add to the SwiftUI environment:
Text("Hello, world!")
.environment(logger)Details (Click to expand)
LogManager is initialized with an array of LogService. ConsoleService is included in the package. Other services are separate packages so you can pick and choose:
- Console β included, prints to console via OSLog or stdout
- Mixpanel β SwiftfulLoggingMixpanel
- Firebase Analytics β SwiftfulLoggingFirebaseAnalytics
- Firebase Crashlytics β SwiftfulLoggingFirebaseCrashlytics
// Default β prints parameters, uses stdout
let console = ConsoleService()
// Custom β hide parameters, use OSLog
let console = ConsoleService(printParameters: false, system: .osLog)Create your own by conforming to the protocol:
public protocol LogService: Sendable {
func identifyUser(userId: String, name: String?, email: String?)
func addUserProperties(dict: [String: Any], isHighPriority: Bool)
func deleteUserProfile()
func trackEvent(event: LoggableEvent)
func trackScreenView(event: LoggableEvent)
}Details (Click to expand)
Log events with a name, optional parameters, and a log type:
logger.trackEvent(eventName: "ButtonTapped")
logger.trackEvent(eventName: "ButtonTapped", parameters: ["button_id": "save"])
logger.trackEvent(eventName: "ButtonTapped", parameters: ["button_id": "save"], type: .analytic)Use AnyLoggableEvent for convenience:
let event = AnyLoggableEvent(eventName: "ButtonTapped", parameters: ["button_id": "save"], type: .analytic)
logger.trackEvent(event: event)Recommended: Use the LoggableEvent protocol with custom enums for type-safe events:
enum Event: LoggableEvent {
case screenDidAppear(title: String)
case buttonTapped(id: String)
case screenError(error: Error)
var eventName: String {
switch self {
case .screenDidAppear: return "ScreenAppear"
case .buttonTapped: return "ButtonTapped"
case .screenError: return "ScreenError"
}
}
var parameters: [String: Any]? {
switch self {
case .screenDidAppear(let title):
return ["title": title]
case .buttonTapped(let id):
return ["button_id": id]
case .screenError(let error):
return ["error_description": error.localizedDescription]
}
}
var type: LogType {
switch self {
case .screenDidAppear, .buttonTapped:
return .analytic
case .screenError:
return .severe
}
}
}logger.trackEvent(event: Event.screenDidAppear(title: "Home"))Details (Click to expand)
Every event has a LogType that classifies its severity:
logger.trackEvent(eventName: "UserLoaded", type: .info) // Informational, not an issue
logger.trackEvent(eventName: "ScreenAppear", type: .analytic) // Standard analytics (default)
logger.trackEvent(eventName: "RetryFailed", type: .warning) // Non-breaking issue
logger.trackEvent(eventName: "CrashDetected", type: .severe) // Breaks user experience| Type | Purpose |
|---|---|
.info |
Informational logging, not issues or errors |
.analytic |
Standard analytics events (default) |
.warning |
Issues that should not occur but don't break UX |
.severe |
Critical errors that affect user experience |
Services can use the log type to handle events differently. For example, FirebaseCrashlyticsService only records .severe events as errors.
Details (Click to expand)
Track screen views separately from events. Some analytics services (e.g. Firebase Analytics) have dedicated screen view tracking.
let event = AnyLoggableEvent(eventName: "HomeScreen", type: .analytic)
logger.trackScreenView(event: event)
// Or with a custom LoggableEvent enum
logger.trackScreenView(event: Event.screenDidAppear(title: "Home"))Details (Click to expand)
Identify the current user (log them in to all services):
logger.identifyUser(userId: "abc123", name: "Nick", email: "hello@swiftful-thinking.com")Add user properties for analytics segmentation:
logger.addUserProperties(dict: ["is_premium": true, "plan": "annual"])
logger.addUserProperties(dict: ["account_type": "pro"], isHighPriority: true)Note: isHighPriority matters for services with limited user property slots (e.g. Firebase Analytics only sets properties when isHighPriority is true).
Delete user profile:
logger.deleteUserProfile()This package includes a .claude/swiftful-logging-rules.md with usage guidelines, event patterns, and integration advice for projects using Claude Code.
- iOS 17.0+
- macOS 14.0+
SwiftfulLogging is available under the MIT license.