아직도 Swift에서 print문을 쓰고있나요?

홍승현·2023년 4월 3일
0

iOS

목록 보기
3/3
post-thumbnail

대부분 프로젝트에서 코드를 작성하고 난 뒤 결과물을 확인하기 위해 print문을 적거나 debugging을 이용하여 값을 확인하곤 합니다. 특히 print문을 남발하게 되면, debug screen을 깔끔하게 유지하고 싶은 사람에게는 고역이나 다름이 없습니다. 값을 때때로 확인하고 싶고, debug screen도 깔끔하게 유지되면서 로깅 처리를 할 수 있는 방법은 무엇이 있을까요?

OSLog

OSLog는 iOS와 macOS에서 로그를 기록하고 관리하는 데 사용되는 강력한 프레임워크입니다.

OSLog를 사용하면 다음과 같은 이점이 있습니다:

  1. 성능: OSLog는 시스템 최적화로 인해 일반 print문에 비해 성능이 우수(따라서 앱의 성능에 미치는 영향이 더 적다).
  2. 유연성: OSLog는 다양한 로그 레벨과 카테고리를 지원하여, 필요한 정보만을 손쉽게 필터링할 수 있고, 이는 디버깅 시간을 단축에 영향을 미침
  3. 시스템 통합: OSLog는 시스템 로그와 통합되어, 관련 시스템 이벤트와 함께 보기가 가능
  4. 보안: OSLog는 개인 정보가 포함된 로그를 자동으로 가리는 기능을 제공하여, 개인 정보 보호에 용이
LevelDiskNotes
DebugX개발 중에만 유용한 상세 정보를 캡처하여 보여줍니다. 코드 디버깅에서 사용됩니다.
InfoO문제 해결에 도움이 되는 정보를 캡처하지만 필수적이지는 않습니다.
Notice (Default)O문제 해결의 필수적인 정보를 캡처합니다.ex) 실패 원인이 될 수 있는 정보
ErrorO코드 실행 중 발생한 오류를 캡처합니다. 관련 프로세스 체인에 대한 정보가 있는 경우 해당 정보도 함께 캡처됩니다.
FaultO코드의 결함 및 버그 정보를 캡처합니다. 관련 프로세스 체인에 대한 정보가 있는 경우 해당 정보도 함께 캡처됩니다.

사용해보기

예시를 통해 OSLog의 사용법을 살펴보겠습니다. 기존에 다음과 같이 print문을 사용했다고 가정해봅시다.

print("User's email: \(user.email)")

이제 OSLog를 사용하여 위의 역할을 하는 로그를 작성합니다.

import OSLog

let log = OSLog(subsystem: "com.example.yourapp", category: "user")
// Level: Default
// Subsystem: com.example.yourapp
// Category: user
os_log("User's email: %{public}@", log: log, type: .default, user.email)

그리고 Console 애플리케이션을 열어 실행한 기기의 로그를 확인해보면 아래와 같이 복잡하게 나오게 됩니다.

이는 해당하는 기기의 모든 로그를 보여주는 것이기 때문에, 앞서 작성했던 문자열을 특정하여 필터링하면 원하는 결과값이 나오게 됩니다.

Log Level을 이용해보기

위에서 언급한 Level을 이용하여 로깅의 중요도를 나타낼 수 있습니다.

Error

os_log("User's email: %{public}@", log: log, type: .error, user.email)

Fault

os_log("User's email: %{public}@", log: log, type: .fault, user.email)

Subsystem과 category 활용하기

여러 로그가 즐비한 가운데, 자기가 로깅하고자 하는 앱만 보고 싶은 경우 subsystem값을 설정하여 필터링할 수 있습니다.

let log = OSLog(subsystem: "com.example.yourapp", category: "user")
os_log("User's email: %{public}@", log: log, type: .default, "test@test.com")
os_log("User's name: %{public}@", log: log, type: .default, "홍길동")

더 나아가서, 특정 기능에 대해서만 로그를 보고 싶다면, category를 설정하여 필터링하면 손쉽게 필터링이 가능합니다.

let log = OSLog(subsystem: "com.example.yourapp", category: "user")
os_log("User's email: %{public}@", log: log, type: .default, "test@test.com")
os_log("User's name: %{public}@", log: log, type: .default, "홍길동")

let uiLog = OSLog(subsystem: "com.example.yourapp", category: "UI")
let viewFrame = yourView.frame
os_log(
  "UIView frame: x: %.2f, y: %.2f, width: %.2f, height: %.2f",
  log: uiLog,
  type: .info,
  viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.width, viewFrame.size.height
)

OSLog 확장시키기

카테고리별 인스턴스를 생성해서 앱의 다양한 구성 요소에 맞게 로그 처리를 할 수 있습니다.

extension OSLog {
  // 앱의 서브시스템 정의
  private static var subsystem = Bundle.main.bundleIdentifier!
  
  // 카테고리별 로그 객체 생성
  static let networking = OSLog(subsystem: subsystem, category: "Networking")
  static let database = OSLog(subsystem: subsystem, category: "Database")
  static let userInterface = OSLog(subsystem: subsystem, category: "UserInterface")
  // 추가로 필요한 카테고리를 여기에 정의할 수 있습니다.
  
  // 로그 레벨에 따른 메시지 출력 함수 생성
  static func logError(_ message: StaticString, category: OSLog, _ args: CVarArg...) {
    log(message, type: .fault, category: category, args: args)
  }
  
  static func logWarning(_ message: StaticString, category: OSLog, _ args: CVarArg...) {
    log(message, type: .error, category: category, args: args)
  }
  
  static func logDefault(_ message: StaticString, category: OSLog, _ args: CVarArg...) {
    log(message, type: .default, category: category, args: args)
  }
  
  static func logInfo(_ message: StaticString, category: OSLog, _ args: CVarArg...) {
    log(message, type: .info, category: category, args: args)
  }
  
  static func logDebug(_ message: StaticString, category: OSLog, _ args: CVarArg...) {
    log(message, type: .debug, category: category, args: args)
  }
  
  // 로그 출력을 위한 공통 함수
  private static func log(_ message: StaticString, type: OSLogType, category: OSLog, args: [CVarArg]) {
    os_log(message, log: category, type: type, args)
  }
}

위 처럼 확장했을 경우 다음과 같이 코드 작성이 가능해집니다.

OSLog.logError("Network error: %@", category: .networking, error.localizedDescription)
OSLog.logInfo("User successfully logged in.", category: .userInterface)

이처럼 OSLog의 Extension을 사용하게 되면, 협업할 때 로그 레벨과 카테고리를 일관되게 사용할 수 있고, 로그를 작성하기가 더 편리해지는 장점이 있습니다.

profile
블로그 이전: https://www.whitehyun.com

0개의 댓글