Swift 中的可观测性:面向专家的追踪、指标与日志

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

什么是可观测性,为什么 Swift 开发者需要它?

\n\n

你是否曾试图弄清楚为什么你的 iOS Swift 应用在个人资料页面卡顿,而基于 Vapor 的服务器端对欧洲用户的响应延迟达到 3 秒?如果是这样,那么你已经遇到了 可观测性 所解决的问题。

\n\n

可观测性不仅仅是“日志记录”。它是一种无需编写新代码就能向系统提出任何关于其状态问题的能力。可观测性的三大支柱是:追踪、指标 和 日志。它们共同提供了从用户请求到数据库深处执行的完整图景。

\n\n

在本文中,我们将探讨如何在 Swift 项目中实施可观测性——无论是在客户端 (iOS) 还是在服务器端 (Vapor / Hummingbird)。你将了解使用哪些库,如何编写高效的追踪和指标,以及如何避免在日志中迷失方向。

\n\n

为什么 Swift 是可观测性的理想候选者?

\n\n

Swift 是一种强类型语言,性能与 C 语言相当,并且拥有不断增长的服务器端开发生态系统。但有一个问题:Swift 社区才刚刚开始积极采用可观测性。与 Java 或 Go(其中 OpenTelemetry 已成为标准)不同,Swift 中的可观测性是一个新趋势,它为早期采用者提供了巨大的优势。

\n\n

Swift 开发者面临的主要挑战:

\n
    \n
  • 异步性:async/await 和结构化并发正在改变追踪的规则。
  • \n
  • 多平台:Swift 代码可以在 iOS、macOS、服务器甚至嵌入式系统上运行。
  • \n
  • 缺乏统一标准:目前还没有像 Java 世界那样的“银弹”。
  • \n
\n\n

但好消息是,Swift 提供了构建可靠可观测性的所有工具——你只需要知道往哪里看。

\n\n

Swift 中的追踪:从请求到响应

\n\n

什么是追踪,为什么需要它?

\n

追踪(或分布式跟踪)允许你跟踪单个请求通过所有服务和应用程序函数的路径。在微服务世界中,这是不可或缺的。但即使在单体 iOS 应用中,追踪也有助于理解代码的哪一部分导致了卡顿。

\n\n

OpenTelemetry Swift:你的主要工具

\n

OpenTelemetry 是一个用于可观测性的开放标准。对于 Swift,有一个名为 opentelemetry-swift 的包。它支持追踪、指标和日志,并且可以将数据导出到任何后端(Jaeger、Prometheus、Grafana)。

\n\n

通过 Swift Package Manager 安装:

\n
// Package.swift\n.package(url: "https://github.com/open-telemetry/opentelemetry-swift.git", from: "1.10.0")
\n\n

用 Swift 编写你的第一个追踪

\n

假设你有一个加载用户个人资料的函数。没有追踪,你只能看到总执行时间。有了追踪,你可以看到每一步:

\n\n
import OpenTelemetryApi\nimport OpenTelemetrySdk\n\nlet tracer = OpenTelemetry.instance.tracerProvider.get(\n    instrumentationName: "ProfileModule",\n    instrumentationVersion: "1.0.0"\n)\n\nfunc loadUserProfile(userId: String) async throws -> UserProfile {\n    let span = tracer.spanBuilder(spanName: "loadUserProfile")\n        .setAttribute(key: "user.id", value: userId)\n        .startSpan()\n    \n    defer {\n        span.end()\n    }\n    \n    // 步骤 1:检查缓存\n    let cacheSpan = tracer.spanBuilder(spanName: "checkCache").startSpan()\n    let cached = checkCache(for: userId)\n    cacheSpan.end()\n    \n    if let cachedProfile = cached {\n        span.setAttribute(key: "cache.hit", value: true)\n        return cachedProfile\n    }\n    \n    // 步骤 2:向 API 发起请求\n    let apiSpan = tracer.spanBuilder(spanName: "fetchFromAPI").startSpan()\n    let profile = try await api.fetchPro                

博客

书籍推荐