iOS

Logger Caching & Performance

GREEN.1229 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