Tüm Yazılar
KategoriPerformance
Okuma Süresi
23 dk okuma
Yayın Tarihi
...
Kelime Sayısı
1.706kelime

Kahveni hazırla - bu içerikli bir makale!

MetricKit, os_signpost, OSLog, custom telemetry ve production performance monitoring. Crash reporting, ANR detection ve kullanici deneyimi metrikleri.

iOS Performance Monitoring & Observability Rehberi

# iOS Performance Monitoring & Observability Rehberi

Uygulamaniz App Store'da yayinlandiktan sonra performans izleme kritik oneme sahiptir. Gelistirme ortamindaki testler gercek dunyadaki milyonlarca farkli cihaz, network kosulu ve kullanim senaryosunu temsil edemez. Bu rehberde Apple'in native araclari, ucuncu parti cozumler ve production-grade monitoring stratejilerini ele alacagiz.

Gercek: Kullanicilarin %53'u 3 saniyeden uzun suren sayfa yuklemelerinde uygulamayi terk ediyor (Google Research).

Icindekiler


1. Observability Neden Onemli?

Observability uc temel sutun uzerine kurulur:

Sutun
Aciklama
iOS Araci
**Metrics**
Sayisal olcumler
MetricKit, custom counters
**Logs**
Olay kayitlari
OSLog, os_log
**Traces**
Islem akis takibi
os_signpost, Instruments

Performance Metrikleri ve Hedefler

Metrik
Hedef
Kritik Esik
Olcum Araci
**App Launch**
< 400ms
> 2s
MetricKit
**Hang Rate**
< %0.1
> %1
MetricKit
**Memory Peak**
< 200MB
> 500MB
MetricKit
**Crash Rate**
< %0.1
> %1
Xcode Organizer
**Frame Drop**
< %5
> %15
CADisplayLink
**Battery**
< %5/saat
> %10/saat
MetricKit
**Disk Write**
< 100MB/gun
> 1GB/gun
MetricKit

2. MetricKit Framework

MetricKit, Apple'in production performance olcum framework'udur. Gunluk ve anlik metrikler saglar.

swift
1import MetricKit
2 
3final class PerformanceMonitor: NSObject, MXMetricManagerSubscriber {
4 static let shared = PerformanceMonitor()
5 
6 private override init() {
7 super.init()
8 }
9 
10 func startMonitoring() {
11 let manager = MXMetricManager.shared
12 manager.add(self)
13 }
14 
15 func stopMonitoring() {
16 MXMetricManager.shared.remove(self)
17 }
18 
19 // Gunluk metrik raporu (24 saatte bir)
20 func didReceive(_ payloads: [MXMetricPayload]) {
21 for payload in payloads {
22 processMetricPayload(payload)
23 }
24 }
25 
26 // Anlik teshis raporu (crash, hang vb.)
27 func didReceive(_ payloads: [MXDiagnosticPayload]) {
28 for payload in payloads {
29 processDiagnosticPayload(payload)
30 }
31 }
32 
33 private func processMetricPayload(_ payload: MXMetricPayload) {
34 // Launch metrikleri
35 if let launchMetrics = payload.applicationLaunchMetrics {
36 let resumeTime = launchMetrics.histogrammedTimeToFirstDraw
37 logMetric("launch_time", histogram: resumeTime)
38 }
39 
40 // Memory metrikleri
41 if let memoryMetrics = payload.memoryMetrics {
42 let peakMemory = memoryMetrics.peakMemoryUsage
43 logMetric("peak_memory", measurement: peakMemory)
44 }
45 
46 // CPU metrikleri
47 if let cpuMetrics = payload.cpuMetrics {
48 let cumulativeCPU = cpuMetrics.cumulativeCPUTime
49 logMetric("cpu_time", measurement: cumulativeCPU)
50 }
51 
52 // Disk I/O
53 if let diskMetrics = payload.diskIOMetrics {
54 let writes = diskMetrics.cumulativeLogicalWrites
55 logMetric("disk_writes", measurement: writes)
56 }
57 
58 // JSON olarak server'a gonder
59 if let jsonData = payload.jsonRepresentation() {
60 sendToServer(data: jsonData, type: "metric")
61 }
62 }
63 
64 private func processDiagnosticPayload(_ payload: MXDiagnosticPayload) {
65 // Crash raporlari
66 if let crashDiags = payload.crashDiagnostics {
67 for crash in crashDiags {
68 logDiagnostic("crash", callStack: crash.callStackTree)
69 }
70 }
71 
72 // Hang raporlari
73 if let hangDiags = payload.hangDiagnostics {
74 for hang in hangDiags {
75 let duration = hang.hangDuration
76 logDiagnostic("hang", duration: duration)
77 }
78 }
79 
80 // CPU exception
81 if let cpuDiags = payload.cpuExceptionDiagnostics {
82 for cpuException in cpuDiags {
83 logDiagnostic("cpu_exception", callStack: cpuException.callStackTree)
84 }
85 }
86 
87 // Disk write exception
88 if let diskDiags = payload.diskWriteExceptionDiagnostics {
89 for diskException in diskDiags {
90 logDiagnostic("disk_exception", callStack: diskException.callStackTree)
91 }
92 }
93 
94 if let jsonData = payload.jsonRepresentation() {
95 sendToServer(data: jsonData, type: "diagnostic")
96 }
97 }
98 
99 private func logMetric(_ name: String, histogram: MXHistogram<UnitDuration>? = nil, measurement: Measurement<UnitDuration>? = nil) {
100 // Analytics backend'e gonder
101 }
102 
103 private func logDiagnostic(_ type: String, callStack: MXCallStackTree? = nil, duration: Measurement<UnitDuration>? = nil) {
104 // Crash reporting backend'e gonder
105 }
106 
107 private func sendToServer(data: Data, type: String) {
108 // HTTP POST ile server'a gonder
109 }
110}

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?


3. OSLog ve Signpost

OSLog, Apple'in modern logging framework'udur. Console.app ve Instruments ile entegre calisir.

swift
1import OSLog
2 
3// Logger tanimlama
4extension Logger {
5 private static let subsystem = Bundle.main.bundleIdentifier ?? "com.app"
6 
7 static let network = Logger(subsystem: subsystem, category: "Network")
8 static let database = Logger(subsystem: subsystem, category: "Database")
9 static let ui = Logger(subsystem: subsystem, category: "UI")
10 static let auth = Logger(subsystem: subsystem, category: "Auth")
11 static let performance = Logger(subsystem: subsystem, category: "Performance")
12}
13 
14// Kullanim
15struct NetworkService {
16 func fetchUsers() async throws -> [User] {
17 Logger.network.info("Kullanici listesi isteniyor")
18 
19 let startTime = CFAbsoluteTimeGetCurrent()
20 
21 do {
22 let users = try await apiClient.get("/users")
23 let elapsed = CFAbsoluteTimeGetCurrent() - startTime
24 
25 Logger.network.info("Basarili: \(users.count) kullanici, \(elapsed, format: .fixed(precision: 2))s")
26 Logger.performance.notice("API /users suresi: \(elapsed, format: .fixed(precision: 2))s")
27 
28 return users
29 } catch {
30 Logger.network.error("Hata: \(error.localizedDescription)")
31 throw error
32 }
33 }
34}

OSLog Seviyeleri

Seviye
Kullanim
Disk'e Yazilir mi?
Performans Etkisi
`.debug`
Gelistirme
Hayir
Yok
`.info`
Genel bilgi
Hafizada, gerekirse
Minimal
`.notice`
Onemli olaylar (default)
Evet
Dusuk
`.error`
Hatalar
Evet
Dusuk
`.fault`
Kritik hatalar
Evet + kalici
Dusuk

4. Xcode Organizer

Xcode Organizer (Window > Organizer), App Store'daki uygulamanizin performans verilerini gosterir:

  • Crashes: Crash raporlari ve stack trace'ler
  • Energy: Pil tuketim raporlari
  • Hangs: UI donma raporlari
  • Disk Writes: Asiri disk yazimi
  • Scrolling: Scroll performansi
  • Launch Time: Uygulama acilis suresi
  • Memory: Bellek kullanimi

5. Crash Reporting

swift
1// Custom crash handler
2final class CrashReporter {
3 static let shared = CrashReporter()
4 
5 func install() {
6 // Uncaught exception handler
7 NSSetUncaughtExceptionHandler { exception in
8 let info = CrashInfo(
9 name: exception.name.rawValue,
10 reason: exception.reason ?? "Bilinmeyen",
11 callStack: exception.callStackSymbols,
12 timestamp: Date()
13 )
14 CrashReporter.shared.saveCrash(info)
15 }
16 
17 // Signal handler (EXC_BAD_ACCESS vb.)
18 setupSignalHandlers()
19 
20 // Onceki crash varsa gonder
21 sendPendingCrashes()
22 }
23 
24 private func saveCrash(_ info: CrashInfo) {
25 // UserDefaults'a kaydet (FileManager crash sirasinda guvenli degil)
26 if let data = try? JSONEncoder().encode(info) {
27 UserDefaults.standard.set(data, forKey: "pending_crash")
28 }
29 }
30 
31 private func sendPendingCrashes() {
32 guard let data = UserDefaults.standard.data(forKey: "pending_crash"),
33 let crash = try? JSONDecoder().decode(CrashInfo.self, from: data) else {
34 return
35 }
36 
37 // Server'a gonder
38 Task {
39 do {
40 try await uploadCrash(crash)
41 UserDefaults.standard.removeObject(forKey: "pending_crash")
42 } catch {
43 Logger.performance.error("Crash raporu gonderilemedi")
44 }
45 }
46 }
47 
48 private func setupSignalHandlers() {
49 // SIGSEGV, SIGABRT, SIGBUS vb. icin
50 }
51 
52 private func uploadCrash(_ crash: CrashInfo) async throws {
53 // HTTP POST
54 }
55}
56 
57struct CrashInfo: Codable {
58 let name: String
59 let reason: String
60 let callStack: [String]
61 let timestamp: Date
62}

6. ANR (Application Not Responding) Detection

Main thread'in 250ms'den fazla bloklanmasi kullanici deneyimini bozar. Bunu tespit etmek icin watchdog mekanizmasi kurabilirsiniz.

swift
1final class HangDetector {
2 private var watchdogThread: Thread?
3 private let threshold: TimeInterval
4 private var lastPing = Date()
5 
6 init(threshold: TimeInterval = 0.5) {
7 self.threshold = threshold
8 }
9 
10 func start() {
11 // Main thread'den periyodik ping
12 let mainTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
13 self?.lastPing = Date()
14 }
15 RunLoop.main.add(mainTimer, forMode: .common)
16 
17 // Background thread'den izleme
18 watchdogThread = Thread {
19 while !Thread.current.isCancelled {
20 Thread.sleep(forTimeInterval: self.threshold)
21 let elapsed = Date().timeIntervalSince(self.lastPing)
22 if elapsed > self.threshold {
23 self.reportHang(duration: elapsed)
24 }
25 }
26 }
27 watchdogThread?.name = "HangDetector"
28 watchdogThread?.start()
29 }
30 
31 func stop() {
32 watchdogThread?.cancel()
33 }
34 
35 private func reportHang(duration: TimeInterval) {
36 let symbols = Thread.callStackSymbols
37 Logger.performance.warning("Main thread hang: \(duration, format: .fixed(precision: 2))s")
38 // Server'a bildir
39 }
40}

7. Network Monitoring

URLSession metrikleri ile network performansini izleyin:

swift
1final class NetworkMetricsCollector: NSObject, URLSessionTaskDelegate {
2 func urlSession(
3 _ session: URLSession,
4 task: URLSessionTask,
5 didFinishCollecting metrics: URLSessionTaskMetrics
6 ) {
7 for transaction in metrics.transactionMetrics {
8 let dns = transaction.domainLookupEndDate?.timeIntervalSince(
9 transaction.domainLookupStartDate ?? Date()
10 ) ?? 0
11 
12 let connect = transaction.connectEndDate?.timeIntervalSince(
13 transaction.connectStartDate ?? Date()
14 ) ?? 0
15 
16 let ttfb = transaction.responseStartDate?.timeIntervalSince(
17 transaction.requestStartDate ?? Date()
18 ) ?? 0
19 
20 Logger.network.info(
21 "DNS: \(dns)s, Connect: \(connect)s, TTFB: \(ttfb)s"
22 )
23 }
24 }
25}

8. Custom Telemetry

Kendi metriklerinizi tanimlayin ve izleyin.

Telemetri Katmanlari

Katman
Icerik
Ornek
**Teknik**
CPU, memory, disk
MetricKit
**Uygulama**
API suresi, cache hit
Custom
**Is**
Conversion, engagement
Analytics
**Kullanici**
Session suresi, retention
Analytics

9. Dashboard ve Alerting

Production monitoring icin bir dashboard kurulmalidir:

  • Grafana + Prometheus: Acik kaynak, esnek
  • Datadog: Kapsamli SaaS cozum
  • Firebase Performance: Google'in ucretsiz araci
  • Sentry: Hata ve performans izleme
  • New Relic: Enterprise cozum

10. Best Practices

Monitoring Checklist

  • MetricKit subscriber'i ekleyin
  • OSLog ile yapisal logging yapin
  • Crash reporting kurun
  • Hang detection aktif edin
  • Network metrikleri toplayin
  • Launch time izleyin
  • Memory uyarilari ekleyin
  • Alerting kurallari tanimlayin

11. Sonuc ve Oneriler

Performance monitoring bir lüks degil, zorunluluktur. Kullanicilariniz sessizce terk etmeden once sorunlari tespit edin.

Oncelik Sirasi

  1. Crash reporting (en kritik)
  2. Launch time monitoring
  3. Hang detection
  4. Memory metrikleri
  5. Network performansi
  6. Custom is metrikleri

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:

Etiketler

#Performance#Monitoring#MetricKit#OSLog#Observability#Crash#iOS
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

İlgili İçerik