Production debugging toolkit for modern iOS apps.
AppVitals is a lightweight Swift package that gives teams an in-app diagnostics console for logs, network requests, errors, and recent crash context without pulling in an enterprise observability stack.
import AppVitals
@main
struct ExampleApp: App {
init() {
AppVitals.start()
AppVitals.trackNetwork()
AppVitals.enableShakeToDebug()
}
var body: some Scene {
WindowGroup {
ContentView()
.appVitalsDebugOverlay(stores: AppVitals.stores)
}
}
}- URLSession inspection through
URLProtocol - request method, URL, headers, request body, response body, status, duration, and error capture
- cURL export and pretty JSON formatting
- actor-backed event, network, and memory stores
- app, navigation, warning, error, network, performance, and custom timeline events
- SwiftUI debug console with Logs, Network, Errors, Timeline, and Memory tabs
- memory usage chart, object lifecycle tracking, stream/listener monitoring, and view rebuild analysis
- shake-to-debug view modifier and floating debug bubble
- crash context persistence for recent logs, requests, and visible screen name
- Swift 6, SwiftUI, Observation, async/await, and Swift Testing
Add this repository in Xcode:
File > Add Package Dependencies...
Then import the umbrella module:
import AppVitalsAppVitals.start()
AppVitals.trackNetwork()
AppVitals.log("User tapped checkout")
AppVitals.screen("Checkout")Attach the console to your root view:
RootView()
.appVitalsDebugOverlay(stores: AppVitals.stores)For explicit URLSession configurations:
let configuration = NetworkTracking.sessionConfiguration()
let session = URLSession(configuration: configuration)Enable memory insights in debug builds:
// Enabled automatically with the .debug preset:
AppVitals.start(.debug)Track object lifetimes — leaks show as non-zero "alive" counts in the Memory tab:
class ProductViewModel: ObservableObject {
private let _lifetime = AppVitals.trackLifetime(named: "ProductViewModel")
}Track active subscriptions or async streams:
class FeedViewModel {
private var _feedToken: StreamToken?
func subscribe() {
_feedToken = AppVitals.trackStream(named: "FeedStream")
}
func unsubscribe() { _feedToken = nil }
}Count SwiftUI view rebuilds automatically:
ProductListView()
.trackRebuilds("ProductListView", store: AppVitals.stores.memory)AppVitalsCore: models, configuration, redaction policy, ring buffer, crash context contracts, memory snapshot typesAppVitalsStorage: actor-backed event, network, crash context, and memory storesAppVitalsNetwork: URLProtocol capture, redaction, body formatting, cURL exportAppVitalsPerformance: FPS monitor, memory monitor, lifecycle and stream tokensAppVitalsUI: SwiftUI console, search, filters, memory tab, shake overlay modifierAppVitalsTestingSupport: mock URL protocol and test factoriesAppVitals: umbrella API for simple app integration
AppVitals defaults to bounded in-memory storage and redacts sensitive headers/query items such as authorization tokens, cookies, API keys, and passwords. Body capture is byte-limited by configuration.
See Docs/Architecture.md, Docs/Testing.md, and Docs/Release.md.
AppVitals is free and open source. If it saves you time or helps your team ship better iOS apps, consider sponsoring development.
