Swift

debugPrint와 print 알고쓰기 (feat. dump)

GREEN.1229 2023. 5. 8. 09:21

안녕하세요. 그린입니다🍏

이번 포스팅에서는 debugPrint와 print에 대해 알아보려 합니다 (조금 더 나아가서 간단히 dump까지!)🙋🏻

 

사실 많은 iOS 개발자라면 이미 익숙하고 차이도 잘 아실텐데 한번 확실히 좀 더 명확하게 왜 로깅용으로 debugPrint를 써야하는지 그리고 모든 로깅 상황에서 debugPrint를 가져가는게 좋은건지 정리해보려고 이번 포스팅의 주제로 가져와봤습니다🕺🏻

 

그럼 우선 개념적으로 간단하게 짚고 넘어가야하니 debugPrint와 print의 개념부터 훑어보시죠!

 

debugPrint

우선 공식문서에서는 디버깅에 가장 적합한 텍스트 표현을 출력에 사용한다고 아주 로깅용으로 써라!라고 대놓고 강조하고 있는 느낌입니다😲

 

선언을 보시면 아래와 같습니다.

func debugPrint(
    _ items: Any...,
    separator: String = " ",
    terminator: String = "\n"
)

어디선가 많이 보신것 같지 않나요? 이후 나오겠지만 이 선언은 print와 다를게 없습니다!

공통적으로 모든 항목들이 출력된 후 개행시켜주도록 terminator가 달려있습니다.

 

그럼 바로 이어서 print는 어떻게 생겨먹었는지 볼까요?

 

print

debugPrint에서 로깅용을 강조했다면 print에서는 그냥 주어진 항목의 텍스트 표현 출력을 위해 사용한다고 해요.

어떻게 보면 print가 조금 더 포괄적인 느낌이죠.

 

선언은 아래와 같아요.

func print(
    _ items: Any...,
    separator: String = " ",
    terminator: String = "\n"
)

debugPrint와 동일하죠?

 

그럼 알겠으니 이 둘의 차이를 실제 로깅을 해보면서 찾아보겠습니다!

 

debugPrint와 print의 출력 차이

우선 간단하게 문자열을 출력해볼께요.

let value: String = "Green is Green"

debugPrint(value)
print(value)

// "Green is Green"
// Green is Green

debugPrint는 문자열임으로 ""가 붙어 해당 지금 로깅 출력한 친구가 String 값이라는걸 출력을 통해 알 수 있죠.

반면 print는 그냥 그 문자열이 갖는 값 그대로를 출력합니다.

지금은 사실 print로 출력을 해도 Green is Green이라는 값은 누가봐도 String이기에 헷갈리는게 더 어렵다고 쳐볼께요.

 

그럼 아래와 같을때는 어떨까요?

let value: String = "123123"

print(value)
// 123123

이렇게 보면 실제 print를 사용해 로깅 시 해당 값이 만약 알파벳 문자열이 아니라 "123123"과 같은 숫자 문자열이라면 이게 String인지 Int값인지 헷갈릴 수 있을거에요.

 

그럼 조금 더 나아가볼께요.

 

아래와 같이 1~10까지의 숫자 범위를 출력할 때는 어떨까요?

debugPrint(1...10)
print(1...10)

// ClosedRange(1...10)
// 1...10

debugPrint가 명확하게 어떤 타입인지 출력해주고 있습니다.

이처럼 로깅 시에는 타입 미스매치 오류가 있을 수 있기에 확실히 타입 정보까지 준다면 더 명확할 수 있을거에요.

 

그럼 사실 디버그 로깅을 많이 하는 통신에서는 어떤게 좀 더 이점이 있을지 살펴볼까요?

 

let urlReq = URLRequest(url: URL(string: "https://itunes.apple.com/search?term=jack+johnson&limit=1")!)

Alamofire.request(urlReq).responseJSON { (data) in
  print("Print 로깅")
  print(data)
  print("=========")
  print("debugPrint 로깅")
  debugPrint(data)
}

요렇게 실제 통신하여 받아온 data를 출력할때 차이를 보시죠.

 

print 로깅의 경우 아래와 같이 실제 전달되는 data의 핵심 정보만 노출시켜 줍니다.

SUCCESS: {
    resultCount = 1;
    results =     (
                {
            artistId = 909253;
            artistName = "Jack Johnson";
            artistViewUrl = "https://itunes.apple.com/us/artist/jack-johnson/id909253?uo=4";
        }
    );
}

 

반면 debugPrint 로깅의 경우는 어떤 request였고 response로 온 상세한 정보들을 다 담아서 보내주죠.

[Request]: GET https://itunes.apple.com/search?term=jack+johnson&limit=1
[Response]: <NSHTTPURLResponse: 0x610000223860> { URL: https://itunes.apple.com/search?term=jack+johnson&limit=1 } { status code: 200, headers {
    "Access-Control-Allow-Origin" = "*";
    "Cache-Control" = "max-age=86345";
    Connection = "keep-alive";
    "Content-Disposition" = "attachment; filename=1.txt";
    "Content-Length" = 1783;
    "Content-Type" = "text/javascript; charset=utf-8";
    Date = "Sat, 23 Sep 2017 14:29:11 GMT";
    "Strict-Transport-Security" = "max-age=31536000";
    Vary = "Accept-Encoding";
    "X-Apple-Partner" = "origin.0";
    "X-Cache" = "TCP_MISS from a23-76-156-143.deploy.akamaitechnologies.com (AkamaiGHost/9.1.0.4-20866905) (-)";
    "X-Cache-Remote" = "TCP_MISS from a23-45-232-92.deploy.akamaitechnologies.com (AkamaiGHost/9.1.0.4-20866905) (-)";
    "X-True-Cache-Key" = "/L/itunes.apple.com/search ci2=limit=1&term=jack+johnson__";
    "apple-originating-system" = MZStoreServices;
    "apple-seq" = 0;
    "apple-timing-app" = "86 ms";
    "apple-tk" = false;
    "x-apple-application-instance" = 1000492;
    "x-apple-application-site" = NWK;
    "x-apple-jingle-correlation-key" = VEF3J3UWCHKUSGPHDZRI6RB2QY;
    "x-apple-orig-url" = "https://itunes.apple.com/search?term=jack+johnson&limit=1";
    "x-apple-request-uuid" = "a90bb4ee-9611-d549-19e7-1e628f443a86";
    "x-apple-translated-wo-url" = "/WebObjects/MZStoreServices.woa/ws/wsSearch?term=jack+johnson&limit=1&urlDesc=";
    "x-content-type-options" = nosniff;
    "x-webobjects-loadaverage" = 0;
} }
[Data]: 1783 bytes
[Result]: SUCCESS: {
    resultCount = 1;
    results =     (
                {
            artistId = 909253;
            artistName = "Jack Johnson";
            artistViewUrl = "https://itunes.apple.com/us/artist/jack-johnson/id909253?uo=4";
        }
    );
}

[Timeline]: Timeline: 

{
  "Request Start Time": 527869893.013,
  "Initial Response Time": 527869893.033,
  "Request Completed Time": 527869893.034,
  "Serialization Completed Time": 527869893.035,
  "Latency": 0.020secs,
  "Request Duration": 0.021secs,
  "Serialization Duration": 0.001secs,
  "Total Duration": 0.021secs
}

사실 필요한 data 정보만 로깅한다면 print로도 충분하겠지만 실제 에러가 났을때 로그로 파악이 필요하다면 어떤게 누락되고 잘못되었는지 또 타임아웃은 걸리지 않았는지 등 더 상세하고 유용한 정보를 봐야할때가 많을거에요.

이럴때는 debugPrint가 확실한 이점을 가져갈 수 있습니다.

 

즉 정리해보자면 단순한 로깅 시 분기처리 혹은 여기서부터 로그 시작입니다~ 같은 타입 등과 같은 상세한 정보가 필요하지 않은 부분은 print가 조금 더 깔끔할 수 있고 실제 타입 및 상세한 정보가 필요한 로깅에서는 debugPrint를 사용하는게 적절할 것 같아요!

 

이 이점 때문에 애플에서도 로깅 시에는 debugPrint를 권장하는것 같습니다.

 

그럼 마무리로 dump라는것도 많이 보셨을것 같은데 어떨때 쓰게 될까요?

 

dump

dump는 mirror라는 개념을 사용해 주어진 객체의 정보를 출력해줍니다.

쉽게 말해 객체를 조금 더 보기 좋게 가공해서 출력해줄 수 있다는것이죠.

선언은 아래와 같아요.

@discardableResult func dump<T>(
    _ value: T,
    name: String? = nil,
    indent: Int = 0,
    maxDepth: Int = .max,
    maxItems: Int = .max
) -> T

 

이 dump를 사용할때와 print를 사용할때의 차이를 봐볼까요?

 

struct Person{
  var name = "Green"
  var age = 10
  var footSize = 290.5
}

let green = Person()

print(green)
dump(green)

// Person(name: "Green", age: 10, footSize: 290.5)
// ▿ Project.Person
//  - name: "Green"
//  - age: 10
//  - footSize: 290.5

보시면 위 print를 사용하여 green 객체 정보를 출력하는것보다 dump를 사용한다면 조금 더 가공되어 보여주게 됩니다.

요럴때 dump를 적절히 사용하면 좋을것 같아요.

 

마무리

너무나 당연하게 사용하는것들에 대해 조금 더 명확한 기준을 세우고자 한번 정리해봤습니다!

이럴땐 이렇게 사용한다 라는 명확한 답보다는 개인적으로 기준을 잘 세우면 좋을것 같습니다🙌

 

[참고 자료]

https://developer.apple.com/documentation/swift/debugprint(_:separator:terminator:) 

 

debugPrint(_:separator:terminator:) | Apple Developer Documentation

Writes the textual representations of the given items most suitable for debugging into the standard output.

developer.apple.com

https://developer.apple.com/documentation/swift/print(_:separator:terminator:) 

 

print(_:separator:terminator:) | Apple Developer Documentation

Writes the textual representations of the given items into the standard output.

developer.apple.com

https://developer.apple.com/documentation/swift/dump(_:name:indent:maxdepth:maxitems:) 

 

dump(_:name:indent:maxDepth:maxItems:) | Apple Developer Documentation

Dumps the given object’s contents using its mirror to standard output.

developer.apple.com

https://stackoverflow.com/questions/41826683/print-vs-debugprint-in-swift

 

print() vs debugPrint() in swift

This might be a simple question but because of clear understanding between print() and debug() print in swift I am unable to understand where to use each one.

stackoverflow.com