Is your application working perfectly? Let's check
\n\nHave you ever launched a Swift application into production and prayed it wouldn't crash? I have. And every time a user wrote "it froze," I felt like a blind kitten. Logging and monitoring are the eyes and ears that turn chaos into order. Without them, you're guessing what went wrong. With them, you see every step.
\n\nIn this article, we'll break down how to set up monitoring for Swift applications so you can sleep soundly. No dry theory — just live code, real cases, and life hacks I've collected over the years. Let's go!
\n\nWhy logging in Swift is not just print()
\n\nThe first impulse of any developer is to stick print("everything broke here") around every corner. And it works... until you release the application. In production, print disappears into the void, and the user is left alone with the bug. We need something more.
Modern Swift application logging is structured data, severity levels, and the ability for remote collection. Apple gives us a powerful tool — OSLog. It's lightweight, fast, and built right into the system. Let's see how to tame it.
\n\nOSLog: Basic Level
\n\nImport the framework and create a logger:
\n\nimport OSLog\n\nlet logger = Logger(\n subsystem: "com.pythonlib.monitoring",\n category: "network"\n)\n\nfunc fetchUserData() {\n logger.info("Starting user data download")\n // ... request code ...\n logger.debug("Response received: \\(response.statusCode)")\n}\n\nNotice the subsystem and category. These are your tags for filtering. When you have 50 modules, you can filter out only network logs or only database logs — without extra noise.
Logging Levels: When to shout and when to whisper
\n\nOSLog supports six levels. Here's how to use them:
\n\n- \n
debug— for development, disabled in release (unless explicitly enabled). \n info— useful information that doesn't clutter the console. \n notice— important events, e.g., successful startup. \n error— errors that can be handled. \n fault— critical failures after which the application may crash. \n
Example with a real error:
\n\nfunc handleApiError(_ error: Error) {\n logger.error("API Error: \\(error.localizedDescription, privacy: .public)")\n // privacy: .public — to see the text in logs, otherwise it will be hidden\n}\n\nMonitoring Swift Applications: Metrics and Performance
\n\nLogs are the past. Monitoring Swift applications is the present. You want to know what's happening right now: how much memory your code is consuming, whether animations are lagging, if the frame rate is dropping.
\n\nApple provides MetricKit — a framework for collecting diagnostics on user devices. It collects crash reports, battery data, and launch metrics. But for full-fledged monitoring, third-party services are often integrated.
\n\nIntegrating Crashlytics (Firebase) — Fast and Painful
\n\nCrashlytics remains the industry standard. Here's the minimal setup:
\n\nimport FirebaseCrashlytics\n\n// Somewhere at app startup\nCrashlytics.crashlytics().setUserID("user_123")\nCrashlytics.crashlytics().setCustomValue(true, forKey: "is_premium")\n\n// Log non-fatal errors\ndo {\n try riskyOperation()\n} catch {\n Crashlytics.crashlytics().record(error: error)\n logger.error("Non-fatal error: \\(error)")\n}\n\nImportant point: do not log user personal data without consent. Use setUserID only if you have an anonymized identifier.