Mastering Process-Level Monitoring with Swift System Metrics 1.0

By
<h2 id="overview">Overview</h2> <p>Swift System Metrics 1.0 is a Swift package that provides a unified API for collecting process-level system metrics such as CPU utilization time, memory usage, file descriptor counts, and process start time. It runs on both Linux and macOS, making cross-platform monitoring straightforward. By integrating this package into your service, you can detect performance issues, optimize resource usage, and ensure reliability under varying loads—all with just a few lines of code. This tutorial walks you through adding Swift System Metrics to a Swift project, configuring it with the <code>swift-metrics</code> API and <code>swift-service-lifecycle</code>, and avoiding common pitfalls.</p><figure style="margin:20px 0"><img src="/assets/images/system-metrics-1.0/grafana.png" alt="Mastering Process-Level Monitoring with Swift System Metrics 1.0" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px">Source: swift.org</figcaption></figure> <h2 id="prerequisites">Prerequisites</h2> <p>Before you begin, ensure you have the following:</p> <ul> <li><strong>Swift 5.5 or later</strong> (Swift System Metrics 1.0 requires Swift 5.5+ for structured concurrency support)</li> <li><strong>A Swift package manager project</strong> (<code>Package.swift</code>)</li> <li><strong>Basic familiarity with async/await</strong> and Swift concurrency</li> <li>Understanding of <strong>metrics backends</strong> like Prometheus or OpenTelemetry (optional but helpful for visualization)</li> <li><strong>Linux or macOS</strong> development environment (the package works on both)</li> </ul> <h2 id="step-by-step">Step-by-Step Instructions</h2> <h3 id="step-1">Step 1: Add the Dependency</h3> <p>Open your <code>Package.swift</code> file and add <code>swift-system-metrics</code> as a dependency:</p> <pre><code>// swift-tools-version:5.7 import PackageDescription let package = Package( name: "YourProject", dependencies: [ .package(url: "https://github.com/apple/swift-system-metrics", from: "1.0.0"), // Add other dependencies like OTel or Prometheus as needed ], targets: [ .executableTarget( name: "YourTarget", dependencies: [ .product(name: "SystemMetrics", package: "swift-system-metrics"), ] ), ] ) </code></pre> <h3 id="step-2">Step 2: Import and Set Up a Metrics Backend</h3> <p>Swift System Metrics reports data through <code>swift-metrics</code> (the Metrics API). You need to bootstrap a backend like OpenTelemetry or Prometheus. Here we use <code>swift-otel</code> as an example:</p> <pre><code>import OTel import Logging let logger = Logger(label: "com.example.app") var otelConfig = OTel.Configuration.default otelConfig.serviceName = "MyMonitoredService" let otelService = try OTel.bootstrap(configuration: otelConfig) </code></pre> <p><em>Note</em>: The <code>bootstrap</code> function installs the OTel metrics backend into <code>MetricsSystem</code>, so all collected metrics are automatically forwarded.</p> <h3 id="step-3">Step 3: Create a SystemMetricsMonitor</h3> <p>Import <code>SystemMetrics</code> and create a monitor instance. The monitor is a Swift Service Lifecycle service that periodically collects metrics:</p> <pre><code>import SystemMetrics import ServiceLifecycle let systemMetricsMonitor = SystemMetricsMonitor(logger: logger) </code></pre> <h3 id="step-4">Step 4: Integrate with Service Lifecycle</h3> <p>Use <code>ServiceGroup</code> to manage your services together with the monitor. This ensures graceful startup and shutdown:</p> <pre><code>let serviceGroup = ServiceGroup( services: [otelService, yourActualService, systemMetricsMonitor], gracefulShutdownSignals: [.sigint], cancellationSignals: [.sigterm], logger: logger ) try await serviceGroup.run() </code></pre> <p>Replace <code>yourActualService</code> with your own service (must conform to <code>Service</code>). The monitor will automatically start collecting CPU time, memory (virtual and resident), open file descriptors, and process start time.</p><figure style="margin:20px 0"><img src="https://www.github.com/kukushechkin.png?size=64" alt="Mastering Process-Level Monitoring with Swift System Metrics 1.0" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px">Source: swift.org</figcaption></figure> <h3 id="step-5">Step 5: Visualize (Optional)</h3> <p>The package includes a sample Grafana dashboard JSON configuration. Once your metrics are exported (e.g., via Prometheus), you can import the dashboard from <code>Sources/SystemMetrics/Grafana/Dashboard.json</code> in the repository to see real-time graphs.</p> <h2 id="common-mistakes">Common Mistakes</h2> <h3>Mistake 1: Forgetting to Bootstrap the Metrics Backend</h3> <p>Without calling <code>OTel.bootstrap</code> (or equivalent for another backend), the metrics collected by <code>SystemMetricsMonitor</code> have nowhere to go. Always install a backend before starting the monitor.</p> <h3>Mistake 2: Not Including the Monitor in the Service Group</h3> <p>The monitor must be part of <code>ServiceGroup</code> to run its collection loop. Adding it as a standalone object without lifecycle integration will result in no metrics being collected.</p> <h3>Mistake 3: Misunderstanding Cross-Platform Features</h3> <p>While the API is identical on Linux and macOS, certain metrics may not be available on all kernels (e.g., file descriptor limits are platform-specific). Test on your target OS.</p> <h3>Mistake 4: Ignoring Permissions</h3> <p>On Linux, reading <code>/proc</code> usually requires no special permissions, but containerized environments may restrict access. Ensure the process has read access to <code>/proc/self/</code>.</p> <h3>Mistake 5: Using Old Package Name</h3> <p>Swift System Metrics was previously called <code>swift-metrics-extras</code>. Update your <code>Package.swift</code> to use the new URL and product name <code>SystemMetrics</code>.</p> <h2 id="summary">Summary</h2> <p>Swift System Metrics 1.0 makes process-level monitoring easy and portable. You’ve learned how to add the dependency, set up a metrics backend, create a monitor, and integrate it with Swift Service Lifecycle. By avoiding the common pitfalls outlined above, you can quickly gain visibility into CPU, memory, file descriptors, and process start time—right from your Swift application. Start monitoring today and ensure your services run reliably under any load.</p>
Tags:

Related Articles