debugPrint와 print 알고쓰기 (feat. dump)
안녕하세요. 그린입니다🍏
이번 포스팅에서는 debugPrint와 print에 대해 알아보려 합니다 (조금 더 나아가서 간단히 dump까지!)🙋🏻
사실 많은 iOS 개발자라면 이미 익숙하고 차이도 잘 아실텐데 한번 확실히 좀 더 명확하게 왜 로깅용으로 debugPrint를 써야하는지 그리고 모든 로깅 상황에서 debugPrint를 가져가는게 좋은건지 정리해보려고 이번 포스팅의 주제로 가져와봤습니다🕺🏻
그럼 우선 개념적으로 간단하게 짚고 넘어가야하니 debugPrint와 print의 개념부터 훑어보시죠!
debugPrint
우선 공식문서에서는 디버깅에 가장 적합한 텍스트 표현을 출력에 사용한다고 아주 로깅용으로 써라!라고 대놓고 강조하고 있는 느낌입니다😲
선언을 보시면 아래와 같습니다.
func debugPrint(
_ items: Any...,
separator: String = " ",
terminator: String = "\n"
)
어디선가 많이 보신것 같지 않나요? 이후 나오겠지만 이 선언은 print와 다를게 없습니다!
공통적으로 모든 항목들이 출력된 후 개행시켜주도록 terminator가 달려있습니다.
그럼 바로 이어서 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:)
https://developer.apple.com/documentation/swift/print(_:separator:terminator:)
https://developer.apple.com/documentation/swift/dump(_:name:indent:maxdepth:maxitems:)
https://stackoverflow.com/questions/41826683/print-vs-debugprint-in-swift