iOS SDK Logging
Structured logging for iOS apps with automatic batching, exponential backoff, and lifecycle awareness via the native Swift SDK.
Structured logging for iOS apps with automatic batching, exponential backoff, and lifecycle awareness. Logs are buffered and sent in batches to minimize network usage and battery drain.
Logs are buffered and sent in batches (default: 50)
Failed batches retry with increasing delays (2s, 4s, 8s... up to 60s, max 10 retries)
Logs are buffered in memory only (enableOfflineStorage covers errors, not logs); the oldest are dropped when the buffer exceeds 1000
Timer only runs when buffer has logs — no battery drain when idle
Automatically attaches user ID set via AbrovaTrace.shared.setUserId()
Built with Swift, supports iOS 12+, macOS 10.14+, tvOS 12+
Enable Logging#
After initializing AbrovaTrace, enable the logging service. (If you call a log method without enabling it, logging is turned on automatically with no sourceId.) Logs appear in the Console under Abrova Trace → Logs; they are separate from captureMessage, which goes to Messages.
UIKit
import UIKit
import AbrovaTrace
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize AbrovaTrace first
let config = AbrovaTraceConfigBuilder(apiKey: "ab_live_YOUR_API_KEY")
.environment("production")
.release(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String)
.build()
AbrovaTrace.shared.initialize(config: config)
// Enable logging with a source identifier
AbrovaTrace.shared.enableLogging(
sourceId: "my-ios-app",
sourceName: "My iOS App",
batchSize: 50,
flushInterval: 5.0
)
return true
}
}SwiftUI
import SwiftUI
import AbrovaTrace
@main
struct MyApp: App {
init() {
let config = AbrovaTraceConfigBuilder(apiKey: "ab_live_YOUR_API_KEY")
.environment("production")
.build()
AbrovaTrace.shared.initialize(config: config)
// Enable logging
AbrovaTrace.shared.enableLogging(
sourceId: "my-ios-app",
sourceName: "My iOS App"
)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}Sending Logs#
Convenience Methods
// Info log
AbrovaTrace.shared.info("User login successful", metadata: [
"user_id": "user_123"
])
// Warning log
AbrovaTrace.shared.warn("Slow API response", metadata: [
"endpoint": "/api/users",
"duration_ms": 2500
])
// Error log
AbrovaTrace.shared.logErrorMessage("Database query failed", metadata: [
"query": "SELECT * FROM users",
"error": "Connection timeout"
])
// Debug log
AbrovaTrace.shared.logDebugMessage("Cache hit for key: user_123")
// Trace log
AbrovaTrace.shared.trace("Entering function processPayment()")
// Fatal log
AbrovaTrace.shared.fatal("App crashed unexpectedly", metadata: [
"last_screen": "checkout"
])Generic Log Method
// Generic log with explicit level
AbrovaTrace.shared.log("Custom event", level: .info, metadata: ["key": "value"])Log Levels#
- trace —
AbrovaTrace.shared.trace()— Very detailed trace-level debugging - debug —
AbrovaTrace.shared.logDebugMessage()— Debug information during development - info —
AbrovaTrace.shared.info()— General application information - warn —
AbrovaTrace.shared.warn()— Warnings about potential issues - error —
AbrovaTrace.shared.logErrorMessage()— Errors that need attention - fatal —
AbrovaTrace.shared.fatal()— Critical/unrecoverable errors
Usage with ViewControllers#
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AbrovaTrace.shared.info("ViewController loaded", metadata: ["screen": "main"])
}
func handlePurchase() {
AbrovaTrace.shared.info("Purchase initiated", metadata: [
"product_id": "premium_pack",
"amount": 99.99
])
do {
try processPurchase()
AbrovaTrace.shared.info("Purchase completed", metadata: ["amount": 99.99])
} catch {
AbrovaTrace.shared.logErrorMessage("Purchase failed", metadata: [
"error": error.localizedDescription,
"product_id": "premium_pack"
])
AbrovaTrace.shared.captureError(error)
}
}
func processPurchase() throws { /* ... */ }
}SwiftUI Views
struct ContentView: View {
var body: some View {
Button("Purchase") {
AbrovaTrace.shared.info("Purchase button tapped")
handlePurchase()
}
.onAppear {
AbrovaTrace.shared.info("ContentView appeared")
}
}
func handlePurchase() {
// Purchase logic with logging
}
}Manual Operations#
// Force flush all buffered logs
AbrovaTrace.shared.flushLogs { success in
if success {
print("Logs flushed successfully")
}
}
// Check buffer status
let pendingCount = AbrovaTrace.shared.pendingLogCount
print("Pending logs: \(pendingCount)")Configuration#
| Option | Type | Required | Description |
|---|---|---|---|
| sourceId | String? | No | Identifier for batch sending (e.g., "my-ios-app"). Without it, buffered logs are sent one request each and failed sends are not retried |
| sourceName | String? | No | Human-readable name for this source |
| batchSize | Int | No | Flush when buffer reaches this size (default: 50) |
| flushInterval | TimeInterval | No | Max time before flush in seconds (default: 5.0) |
Best Practices#
Enable logging right after AbrovaTrace initialization to capture all events
Set a meaningful sourceId to identify logs from this app in the dashboard
Include structured metadata (user ID, screen name, etc.) for easier debugging
Use info for normal events, warn for potential issues, error for failures
Logs flush automatically when the app enters the background and on terminate; call AbrovaTrace.shared.flushLogs() for other shutdown paths
Avoid logging in tight loops — the buffer has a max size and will drop oldest logs