-
Logger Caching & PerformanceiOS 2025. 6. 4. 13:15
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 Logger 캐싱과 성능에 대해 한번 정리해볼까 합니다 🙋🏻
Logger Caching & Performance
iOS 개발에서 os.Logger를 포함한 로깅 시스템은 앱 진단 및 디버깅에 있어서 핵심적인 역할을 해줍니다.
하지만, 혹시 Logger 인스턴스를 매번 새로 생성하고 있지는 않으신가요?
이번 포스팅에서는 그것을 중심으로 Logger 인스턴스 캐싱이 왜 필요하고 실제로 어떤 성능 차이가 있는지에 대해 한번 분석해보면서 정리해봅니다 😃
Logger를 매번 새로 만든다면?
Apple은 iOS 14부터 os.Logger API를 도입하면서 기존의 os_log 기반 로깅을 더 정돈된 방식으로 관리할 수 있게 발전했습니다.
이 Logger는 단순한 구조체지만, 내부적으로는 서브시스템 및 카테고리에 따라 로깅을 최적화하기 위한 내부 작업들이 수행됩니다.
매번 새로운 Logger 인스턴스를 생성하는 예를 하나 들어볼까요?
func logEvent(_ message: String) { let logger = Logger(subsystem: "com.myapp.analytics", category: "event") logger.info("\(message, privacy: .public)") }
이렇게 된다면 매번 호출마다 Logger 구조체가 생성되고, 내부적으로는 서브시스템, 카테고리 매핑 및 시스템 리소스를 사용하는 과정이 반복되는것입니다.
그럼 어떻게 해볼까요?
Logger Caching
Logger는 내부적으로 리소스를 사용하는 구조이기 때문에 매번 인스턴스를 새로 생성하는것보다 재사용하는것이 훨씬 효율적입니다.
enum Log { static let event = Logger(subsystem: "com.myapp.analytics", category: "event") static let network = Logger(subsystem: "com.myapp.networking", category: "http") static let ui = Logger(subsystem: "com.myapp.ui", category: "rendering") }
이렇게 된다면 Logger는 앱 생명주기 동안에 한번만 생성되며 이후 모든 로깅 작업에서 재사용될 수 있죠.
그럼 Performance는 얼마나 차이나길래 이게 중요할까요?
Logger Performance
한번 이를 알아보기 위해서 Logger 생성에 대한 차이를 측정해봤습니다.
측정 방식은 10만번의 로그 호출을 반복하고 측정 도구로는 DispatchTime을 이용했습니다.
매번 생성
let start = DispatchTime.now() for _ in 0..<100_000 { let logger = Logger(subsystem: "com.test.perf", category: "temp") logger.info("test log") } let end = DispatchTime.now() print("Time (new each time): \(end.uptimeNanoseconds - start.uptimeNanoseconds)")
캐싱
let cachedLogger = Logger(subsystem: "com.test.perf", category: "temp") let start = DispatchTime.now() for _ in 0..<100_000 { cachedLogger.info("test log") } let end = DispatchTime.now() print("Time (cached): \(end.uptimeNanoseconds - start.uptimeNanoseconds)")
방식 평균 실행 시간 (ns) 매번 생성 약 950,000,000 캐싱 약 180,000,000 약 수치적으로 5배 이상의 성능 차이를 보입니다.
캐싱 시, 로그가 매우 빠르게 처리되며 시스템 리소스 사용량도 줄어들죠.
그럼 이 캐싱 전략을 어떻게 구현해보면 좋을까요?
Caching Policy
여러 방식이 당연히 있어 이 방법이 정답은 아닙니다.
하나의 예시라고 봐주시면 좋을것 같아요 🙏🏻
1️⃣ 전역 LoggerStore 정의
enum LoggerStore { static let app = Logger(subsystem: "com.myapp.core", category: "application") static let auth = Logger(subsystem: "com.myapp.auth", category: "authentication") static let db = Logger(subsystem: "com.myapp.db", category: "database") }
2️⃣ 재사용
LoggerStore.auth.debug("Login succeeded for user: \(username, privacy: .private)") LoggerStore.db.error("Failed to save entity: \(error.localizedDescription, privacy: .public)")
3️⃣ 확장 - 카테고리별 관리
enum LoggerCategory { case auth, network, ui, db var logger: Logger { switch self { case .auth: return Logger(subsystem: "com.myapp", category: "auth") case .network: return Logger(subsystem: "com.myapp", category: "network") case .ui: return Logger(subsystem: "com.myapp", category: "ui") case .db: return Logger(subsystem: "com.myapp", category: "db") } } }
그런데 위 3번 방식은 switch 구문에서 매번 계속 Logger를 생성하기에 캐싱 효과가 사라질 수 있고 좋은 방법은 아닙니다.
따라서 다음과 같은 정적인 캐시 맵 형태가 안전할 수 있어요.
enum LoggerCache { static let shared: [LoggerCategory: Logger] = [ .auth: Logger(subsystem: "com.myapp", category: "auth"), .network: Logger(subsystem: "com.myapp", category: "network"), .ui: Logger(subsystem: "com.myapp", category: "ui"), .db: Logger(subsystem: "com.myapp", category: "db"), ] }
Conclusion
정리해보면, 왜 Logger 캐싱을 해야 할까요?
Logger는 값 타입이지만 내부적으로 시스템 리소스를 관리하기에 생성 비용이 높죠.
그래서 재사용 가능한 인스턴스를 캐싱함으로 메모리 효율성을 증가시키고 로깅 속도를 향상시킵니다.
또한, CPU 부하도 감소 시켜줄 수 있죠.
로깅이 빈번하게 발생하는 앱이라면 이런 최적화가 전체적인 성능에 영향을 미칠 수 있어요.
로깅은 단순한 디버깅 도구를 넘어 앱 품질에도 영향을 주는 중요한 요소입니다.
Logger가 어떻게 사용되고 있는지 살펴보면서 전역 캐싱 방식으로 개선해보는건 어떨까요?
References
Logging | Apple Developer Documentation
Capture telemetry from your app for debugging and performance analysis using the unified logging system.
developer.apple.com
Explore logging in Swift - WWDC20 - Videos - Apple Developer
Meet the latest generation of Swift unified logging APIs. Learn how to log events and errors in your app while preserving privacy. Take...
developer.apple.com
'iOS' 카테고리의 다른 글
Lottie vs WebP Animation (2) 2025.05.28 Server Image Format (feat. JPG, PNG, WebP) (4) 2025.05.23 AVCaptureVideoPreviewLayer (0) 2025.04.18 Crash 감지하고 다루기 (1) 2025.03.29 iOS에서 서버 과부하 감지 및 API 호출 최적화 (0) 2025.03.15