Introduction: Why Monitoring Swift Applications is a Necessity
\nDeveloping Swift applications for iOS and macOS is only half the battle. In today's world of user experience (UX), it is critically important not only to write code but also to ensure its stable operation in production. Without a monitoring system, you risk missing performance drops, memory leaks, or failures in critical modules. In this article, we will break down how to set up monitoring for Swift applications from scratch: from collecting metrics to configuring alerts. You will learn about best practices, tools, and code examples that will help your application run like clockwork.
\n\nKey Metrics for Swift Applications
\nMonitoring begins with understanding what exactly needs to be measured. For Swift applications (iOS/macOS), the key metrics are:
\n- \n
- Launch Time (Cold Start / Warm Start) — an indicator of the user's first impression. \n
- Memory Usage (Memory footprint) — preventing Out-of-Memory (OOM) crashes. \n
- FPS (Frames Per Second) — smoothness of animations and interface. \n
- Network Requests — response time, error count (4xx, 5xx). \n
- Crash Logs — number and type of application crashes. \n
These metrics can be collected using built-in tools (Xcode Metrics) as well as third-party SDKs (e.g., Firebase Crashlytics, New Relic, Datadog). However, for full control, it is better to use your own tools.
\n\nExample: Collecting Launch Time with SwiftMetrics
\nFor collecting metrics in Swift, it is convenient to use the SwiftMetrics library (part of the swift-metrics package). Install it via Swift Package Manager:
// Package.swift\ndependencies: [\n .package(url: "https://github.com/apple/swift-metrics.git", from: "2.4.0")\n]\nExample code for measuring cold start time:
\nimport Metrics\n\nclass AppMetrics {\n static let shared = AppMetrics()\n \n func recordLaunchTime() {\n let startTime = CFAbsoluteTimeGetCurrent()\n // Application initialization...\n let elapsed = (CFAbsoluteTimeGetCurrent() - startTime) * 1000 // in milliseconds\n Counter(label: "app.launch_time_ms").increment(by: Int(elapsed))\n }\n}\nThis code creates a counter that can be sent to a monitoring system (e.g., Prometheus or Grafana).
\n\nConfiguring Alerts: From Reaction to Proactivity
\nCollecting metrics is useless without an alerting system. Alerts allow you to react to problems before they become critical. In Swift applications, alerts are divided into two types:
\n- \n
- Local — triggered on the user's device (e.g., when a memory threshold is exceeded). \n
- Server-side — sent to your dashboard (e.g., when the number of errors increases). \n
Let's look at setting up a local alert for memory threshold exceedance using os.log and NotificationCenter:
import Foundation\nimport os.log\n\nclass MemoryMonitor {\n static let shared = MemoryMonitor()\n private let memoryWarningThreshold: UInt64 = 500_000_000 // 500 MB\n \n func startMonitoring() {\n NotificationCenter.default.addObserver(\n self,\n selector: #selector(handleMemoryWarning),\n name: UIApplication.didReceiveMemoryWarningNotification,\n object: nil\n )\n }\n \n @objc private func handleMemoryWarning() {\n let memoryUsed = reportMemoryUsage()\n if memoryUsed > memoryWarningThreshold {\n os_log(.error, "Memory usage critical: %llu MB", memoryUsed / 1_000_000)\n // Here you can send an alert to the server or show it to the user\n }\n }\n \n private func reportMemoryUsage() -> UInt6