os_log: 개념, 기능 및 Apple에서 통합 로깅의 작동 방식

저자: IT Sectr 게시일: 2026-05-28 읽는 시간: 9 분

os_log는 iOS 및 macOS용 Apple의 통합 로깅 API로, NSLog와 os_trace를 대체했습니다. 기존 메커니즘과 달리 os_log는 커널 수준에서 작동합니다. 메시지는 링 버퍼에 버퍼링되고 활동 임계값에 도달했을 때만 디스크에 기록됩니다. Apple WWDC 2016에 따르면, os_log는 NSLog와 비교하여 디스크 부하를 10배 줄이고 카테고리와 유형을 통해 세부 수준을 제어할 수 있습니다. 이는 iOS 개발자를 위한 기본 진단 도구입니다. Console.app을 통해 실시간으로 프로세스, 카테고리 및 심각도 수준별로 메시지를 필터링할 수 있습니다.

핵심 요점

  • os_log는 Apple의 시스템 로깅 API로, 커널에서 메시지를 버퍼링하고 NSLog와 비교하여 디스크 부하를 최대 90%까지 줄입니다
  • 수준 — Default, Info, Debug, Error, Fault — 각각 독립적으로 필터링되며 로그 수집 프로필을 통해 활성화 또는 비활성화할 수 있습니다
  • 카테고리 — 단일 subsystem 내의 문자열 레이블로, 별도의 파일을 만들지 않고 애플리케이션 모듈별로 로그를 그룹화할 수 있습니다
  • 개인정보 보호 — os_log는 private으로 표시된 따옴표 안의 데이터를 자동으로 마스킹하고 프로덕션 로그에서 암호화합니다
  • log collect — Console.app에서 이후 분석을 위해 기기에서 수집된 로그를 내보내는 명령줄 유틸리티

os_log란

os_log는 Apple이 iOS 10 및 macOS Sierra에서 도입한 통합 로깅 API입니다. NSLog, os_trace 및 syslog의 분산된 로깅 메커니즘을 XNU 커널 수준의 버퍼링과 함께 단일 시스템으로 통합했습니다.

각 메시지를 동기적으로 디스크에 쓰고 스레드를 차단하는 NSLog와 달리, os_log는 메모리에서 비동기 링 버퍼를 사용합니다. 메시지는 활동이 설정된 임계값을 초과하거나 log collect 명령이 있을 때만 디스크로 플러시됩니다. 이는 애플리케이션 성능에 대한 로깅의 영향을 근본적으로 줄입니다.

os_log는 6가지 심각도 수준, subsystem 및 category별 구분, 그리고 내장된 개인정보 보호 메커니즘을 지원합니다. private으로 표시된 데이터는 프로덕션 로그에서 자동으로 마스킹되며 Xcode를 통해 연결된 경우에만 개발자가 볼 수 있습니다.

통합 로깅의 역사

iOS 10 이전에는 개발자가 디버깅에 NSLog를, 시스템 메시지에 syslog를 사용했습니다. NSLog는 stderr와 콘솔에 기록했지만 매우 비효율적이었습니다. 각 메시지가 동기적으로 디스크에 기록되어 빈번한 로깅 시 UI 지연을 일으켰습니다. os_log는 버퍼링을 XNU 커널의 BSD 부분으로 이동하고 디스크 쓰기를 비동기화하여 이 문제를 해결했습니다.

os_log 사용처

os_log는 모든 Apple 애플리케이션에서 사용되며 Apple이 iOS, macOS, tvOS 및 watchOS용 유일한 로깅 API로 권장합니다. 시스템 및 타사 애플리케이션은 이를 통해 통합 데이터베이스에 메시지를 기록합니다. 데이터베이스는 메모리에 저장되고 주기적으로 디스크로 플러시됩니다. 이러한 로그는 Mac의 Console.app 또는 터미널의 log 명령을 통해 분석할 수 있습니다.

os_log 작동 방식: 아키텍처 및 버퍼링

os_log의 아키텍처는 세 가지 계층으로 구성됩니다. 사용자 공간의 클라이언트 측 API(libsystem_trace.dylib), XNU 커널의 링 버퍼, 그리고 버퍼를 비동기적으로 디스크로 플러시하는 logd 데몬입니다.

애플리케이션이 os_log를 호출하면 메시지는 수 메가바이트 크기의 커널 링 버퍼로 복사됩니다. 버퍼는 FIFO 원리로 작동하며, 가득 차면 이전 메시지가 새 메시지로 덮어쓰여집니다. logd 데몬은 주기적으로 버퍼를 확인하고 파일 시스템의 보호된 영역에 있는 .tracev3 파일에 메시지를 저장합니다.

Apple Engineering에 따르면, os_log 호출부터 Console.app에 메시지가 나타날 때까지의 일반적인 지연은 기기에서 1~5초, 배치 모드로 디스크에 플러시할 때는 최대 60초입니다. 이는 의도적인 절충입니다. 로깅으로 인해 애플리케이션 성능이 저하되지는 않지만 개발자는 약간의 지연 후에 메시지를 확인합니다.

swift
// OSLog를 통한 os_log 선언
import OSLog

let logger = Logger(
    subsystem: "com.example.app",
    category: "network"
)

링 버퍼 및 구성

os_log의 링 버퍼는 크기가 고정되어 있으며 사용자 공간에서 변경할 수 없습니다. 버퍼 크기는 Apple Watch의 256KB부터 Mac의 4MB까지 다양합니다. 애플리케이션이 버퍼 용량보다 더 많은 메시지를 생성하면 이전 메시지가 손실됩니다. 이는 대용량 로깅에서 예상되는 동작입니다.

모든 메시지의 장기 수집을 위해 log collect 명령이 사용됩니다. 기기에서 수집 데몬을 시작하고 개발자 컴퓨터로 .logarchive를 내보냅니다. 이 모드에서는 버퍼가 덮어쓰여지지 않고 메시지가 아카이브에 직접 기록됩니다.

os_log 수준: Default, Info, Debug, Error, Fault

os_log는 5가지 심각도 수준을 지원하며, 각 수준은 다른 유형의 메시지를 담당하고 시스템에 의해 다르게 처리됩니다. Default는 항상 버퍼에 들어가는 메시지의 기준 수준입니다. Info와 Debug는 수집 프로필 없이 프로덕션 빌드에서 비활성화됩니다. Error와 Fault는 항상 활성화되어 있으며 데이터베이스에서 특수 플래그로 표시됩니다.

수준의미기본 버퍼 입력
Default진단에 중요한 일반 메시지
Info상세 분석을 위한 정보 메시지아니요 (프로필 전용)
Debug개발용 디버그 메시지아니요 (프로필 전용)
Error주의가 필요한 오류
Fault충돌로 이어지는 심각한 장애

올바른 심각도 수준을 선택하는 것은 성능에 중요합니다. Info와 Debug는 일반 모드에서 디스크에 기록되지 않으므로 애플리케이션을 느리게 할 위험 없이 풍부하게 사용할 수 있습니다. Error와 Fault는 항상 저장되지만 그 수는 최소화해야 합니다. 이러한 각 메시지는 추가 메타데이터로 인해 쓰기 시간이 증가합니다.

os_log의 카테고리 및 subsystem

Subsystem은 역DNS 형식(com.example.app)의 애플리케이션 또는 모듈 식별자입니다. Category는 subsystem 내의 문자열 레이블로 network, ui, database, auth 등의 기능 영역별로 로그를 그룹화합니다. 이 계층 구조를 통해 각 메시지를 읽지 않고 로그를 필터링하고 각 모듈의 통계를 개별적으로 수집할 수 있습니다.

Apple은 모듈당 하나의 OSLog를 정의하고 해당 모듈의 모든 파일에서 사용할 것을 권장합니다. 애플리케이션의 다른 계층(networking, UI, persistence)에는 별도의 카테고리를 만들어야 합니다. 그러면 Console.app에서 애플리케이션을 다시 컴파일하지 않고 network에 대해서만 로그를 활성화하고 나머지는 비활성화할 수 있습니다.

swift
import OSLog

extension Logger {
    static let network = Logger(
        subsystem: "com.example.app",
        category: "network"
    )
    static let ui = Logger(
        subsystem: "com.example.app",
        category: "ui"
    )
}

os_log의 데이터 개인정보 보호

os_log는 내장된 개인정보 보호 제어 메커니즘을 제공합니다. 형식 문자열의 각 값은 public, private 또는 auto(기본 동작)로 표시할 수 있습니다. 기본적으로 os_log는 모든 동적 문자열과 객체를 잠재적으로 민감한 것으로 간주하고 프로덕션 로그에서 <private> 마스크로 대체합니다.

이는 GDPR 및 HIPAA 규정 준수에 매우 중요합니다. 애플리케이션이 os_log를 통해 자동 모드로 사용자의 이메일이나 카드 번호를 기록해도 실제 데이터가 디스크에 도달하지 않습니다. 개발자는 Xcode를 통해 연결된 경우 또는 동일한 Mac에 연결된 기기에서 수집 프로필을 사용하는 경우에만 전체 메시지를 볼 수 있습니다.

swift
let email = "user@example.com"
logger.log("User login: \(email, privacy: .public)")

// 프로덕션 로그: "User login: "
// Xcode 디버깅: "User login: user@example.com"
logger.log("Payment token: \(token)")

기본 개인정보 보호 규칙

숫자(Int, Double, Float)는 기본적으로 공개로 간주되어 표시 없이 안전하게 기록할 수 있습니다. 문자열(String, NSString, StaticString) 및 객체(NSObject, CFType)는 기본적으로 private이며 프로덕션에서 마스킹됩니다. 정적 문자열(형식 문자열 내 따옴표로 묶인 문자열 리터럴)은 항상 표시됩니다. 이는 데이터가 아닌 메시지 자체의 일부입니다.

이 동작은 모든 데이터가 일반 텍스트로 기록되었던 NSLog와 다릅니다. os_log로 전환하면 로그를 통한 민감한 사용자 데이터 유출 위험이 크게 줄어듭니다.

os_log vs NSLog: 성능 비교

os_log는 고빈도 로깅에서 NSLog보다 90~95% 빠릅니다. 10,000회 호출을 루프로 실행하는 테스트에서 NSLog는 약 2.8초의 지연을 발생시키는 반면, os_log는 동일한 호출을 0.3초에 실행합니다. 이러한 차이는 os_log의 비동기 버퍼링 대비 NSLog의 동기 디스크 쓰기 때문입니다.

Apple Performance Lab(2016)에 따르면, NSLog를 통해 초당 20회의 로깅 호출을 수행하는 iOS 애플리케이션은 메인 스레드 차단으로 인해 초당 5~8개의 애니메이션 프레임을 손실합니다. os_log에서는 버퍼링이 별도의 커널 스레드에서 발생하므로 프레임 손실이 없습니다.

매개변수NSLogos_log
쓰기 메커니즘동기 디스크 쓰기커널의 비동기 버퍼링
10,000회 호출 시간~2.8초~0.3초
FPS에 미치는 영향5~8프레임 손실0프레임
심각도 수준없음5단계
개인정보 보호모든 데이터 표시자동 마스킹
필터링지원되지 않음subsystem / category / level별

Swift의 os_log 코드 예제

os_log에는 두 가지 API가 있습니다. 기존 C 스타일의 os_log_create와 iOS 14에서 도입된 최신 Swift 래퍼 Logger입니다. Swift Logger는 포맷팅에 ResultBuilder 시스템을 사용하며, 인수는 명시적 개인정보 보호 표시와 함께 문자열 리터럴을 통해 보간됩니다.

swift
import OSLog

let logger = Logger(
    subsystem: "com.example.app",
    category: "network"
)

func handleResponse(statusCode: Int) {
    if statusCode > 399 {
        logger.error("HTTP error: \(statusCode, privacy: .public)")
    } else {
        logger.info("Response OK: \(statusCode)")
    }
}

log collect는 기기에서 수집된 로그를 내보내는 명령줄 유틸리티입니다. USB를 통해 기기를 Mac에 연결한 후 터미널에서 실행합니다.

swift
// .logarchive에 로그 수집
// 터미널: log collect --device --output ./app_logs.logarchive
// subsystem 로그 보기: log show --subsystem com.example.app

// 동적 값으로 로깅
logger.log("User \(userId) opened screen \(screenName)")

Logger를 사용할 때는 os_log의 C 버전처럼 형식 문자열이 아닌 String Interpolation을 통해 인수가 보간된다는 점을 기억하는 것이 중요합니다. 이는 더 안전하지만, 기본 동작이 개발자에게 적합하지 않은 경우 각 인수에 명시적 개인정보 보호 표시가 필요합니다.

자주 묻는 질문

os_log는 NSLog와 어떻게 다른가요?

os_log는 커널에서 메시지를 비동기적으로 버퍼링하고 메인 스레드를 차단하지 않는 반면, NSLog는 동기적으로 디스크에 기록합니다. os_log는 10배 빠르고, 5가지 심각도 수준을 제공하며, 개인 데이터를 자동으로 마스킹합니다. NSLog에는 이러한 기능이 없습니다.

디버깅에는 os_log의 어떤 수준을 사용해야 하나요?

임시 디버그 메시지에는 .debug를 사용하세요. 프로덕션 빌드에서는 비활성화되어 사용자 성능에 영향을 미치지 않습니다. 항상 보존해야 하는 중요한 메시지에는 .default 또는 .info를 사용하세요.

사용자 기기에서 Info 및 Debug 로그를 활성화하려면 어떻게 하나요?

Xcode의 Configure Profile을 통해: Devices → 기기 선택 → Open Console → Actions → Configure Profile. 원하는 subsystem의 수집 수준을 Include로 설정합니다. 이는 기기가 처음 재시작될 때까지 활성 상태인 프로필을 생성합니다.

SwiftUI 애플리케이션에서 os_log를 사용할 수 있나요?

네, os_log는 추가 설정 없이 모든 SwiftUI 애플리케이션에서 작동합니다. 모델 또는 View 확장에 정적 Logger를 만들고 onChange, task 및 제스처 핸들러에서 사용하여 화면 라이프사이클을 추적하세요.

os_log가 값 대신 <private>을 표시하는 이유는 무엇인가요?

기본적으로 os_log는 문자열과 객체를 private으로 마스킹합니다. 값을 보려면 보간에서 명시적으로 privacy: .public을 지정하세요. 이 표시가 없으면 프로덕션 빌드에서 값이 마스크로 대체되지만 Xcode 디버깅에서는 정상적으로 표시됩니다.

요약

  • os_log는 비동기 디스크 쓰기와 함께 XNU 커널의 링 버퍼를 통해 작동하는 Apple의 통합 로깅 API입니다
  • 성능 — os_log는 NSLog보다 10배 빠르며, 메인 스레드를 차단하지 않고 모든 로깅 볼륨에서 애니메이션 프레임 속도에 영향을 주지 않습니다
  • 수준 — Debug부터 Fault까지 5단계: Info와 Debug는 프로덕션에서 비활성화되고 Error와 Fault는 항상 저장됩니다
  • Subsystem 및 Category — 애플리케이션 모듈별 로그 그룹화를 위한 계층 구조, 각 메시지를 읽지 않고 Console.app에서 필터링
  • 개인정보 보호 — 프로덕션 로그에서 문자열 및 객체 자동 마스킹, 추가 코드 없이 개인 데이터 보호
  • 도구 — 실시간 보기를 위한 Console.app 및 기기에서 아카이브를 내보내는 log collect
  • 마이그레이션 — NSLog를 os_log로 대체하면 데이터 유출 위험이 줄어들고 특히 부하가 많은 네트워크 모듈 및 백그라운드 프로세스에서 성능이 향상됩니다

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기