Pulse

sanghoon Ahn·2022년 7월 28일
1

iOS

목록 보기
17/19
post-thumbnail

안녕하세요!! dvHuni 입니다 !!!

오늘은 조금 새로운걸 가져와 봤어요 ..ㅎㅎㅎ

다들 네트워크 로그는 어떻게 사용하고 계시나요??

직접 print? 아니면 Moya를 사용하는 분들은 Provider를 사용해서 자동으로 로그를 찍도록 하시는 분들도 계실텐데요!

오늘은 이러한 네트워킹 로그를 편리하게 확인할 수 있는 프레임워크를 알게되어 소개해드리려고 합니다. 😄

함께 해보시죠! 🏃

Needs & Problems

Pulse를 소개하기 전에 어떻게 Pulse를 알게되었는지 먼저 이야기해드리려 합니다.

저는 다음과 같은 고민을 하고있었습니다. 🧐

  1. 네트워크 로그를 확인하기 위해서는 프로젝트 내의 property를 override 해야했다.
    -> 그로인해 로그를 확인하고 property를 원복하지 않으면 프로젝트에 계속 네트워크 로그가 노출되었다.
  2. 네트워크 로그나 패킷을 로그를 통해 확인하므로 iOS 개발자만 확인할 수 있었다.
    -> 따라서 네트워크 패킷 확인 요청을 위한 핑퐁이 불가피했다.
  3. Web Browser 처럼 실시간으로 iOS Native App에서 네트워크 패킷을 확인 할 수 없을까?

처음에는 임시적인 해결책으로 Instruments를 활용하여 Network를 추적하였습니다.

하지만 물리 디바이스에서만 실행 할 수 있다는 단점이 있었고, 재측정시 이전의 로그는 초기화 되는 문제가 있었습니다.

이러한 고민을 팀원분에게 이야기 했었고,

팀원분은 Pulse를 보고있었는데 한번 적용해보는것이 어떻겠냐며 추천해주셨습니다 ✌️

github를 딱 들어가본 순간… 저는 이거다!! 라고 (소리를 지르며) 신나서 냅다 적용해보겠다고 하였습니다.

What is Pulse

자.. 그렇다면 어떻길래 한눈에 딱 반했느냐 !

먼저 https://github.com/kean/Pulse 의 README 부터 아주 흥미로운 사진들이 있습니다.

이미 두가지의 스크린샷으로 눈치채셨듯이, Network 패킷을 한눈에 확인 할 수 있는 Inspector를 지원하는 Network Inspector framework 입니다.

또한 Console UI를 제공하여, 간편하게 네트워크 패킷을 확인할 수 있습니다.

나름 Document, Guide 까지 정리되어있습니다.

오호.. 한번 써보고싶은데?

라고 생각했다면 계속 읽어주시죠 👀

Easy to Adpat

소개는 README 처럼 스크린샷과 몇줄의 텍스트로 정리하고 이제 장점들을 조금 나열하는 약팔이 시간입니다.

먼저 말씀드리고 싶은 장점은 적용하기 정말 쉽습니다…

이해하기 조금 난해한 가이드를 보면서도 충분히 적용할 수 있었습니다.. 😉

먼저 로그를 담을 LoggingSystem을 bootstrap 해주고 ..!

그냥 냅다 Logger 호출해서 로그 찍으면?

맨 첫째줄에 GET Network 로그가 보이시나요??

console에 로그가 찍힙니다.

아 너무 쉽다…

자세한 적용방법은 아래에서 소개하겠습니다 ! 😃

Automatic Tracking

정말 팔고 싶은 이 약의 다른 효능은

URLSeesion을 활용한 Networking의 경우 자동으로 Logging이 가능합니다!! 😮

앱 실행 최초 1회 해당 메소드를 호출해주면..!

Alamofire, Moya는 URLSession을 wrapping 하고있죠?

Alamofire와 Moya를 사용한 Networking은 자동으로 Console에 로그가 기록됩니다.

아 못믿겠다고요?

영상첨부합니다.

Try it

이제 약팔이의 하이라이트인 실제 적용 예시를 빼놓을 수 없겠죠?

먼저 프로젝트에 Pulse 프레임워크를 설치합니다.

(주의사항) SPM과 XCFrameworks만 지원합니다.

SPM을 추가하시면 Pulse, PulseCore, PulseUI 라이브러리 세개가 나올텐데, 모두 target에 추가해줍니다!

추가로 swift-log 라는 라이브러리가 추가되는데, 이는 Pulse에서 로그를 남길때 사용하는 log입니다.

자세한 내용은 여기에서 확인하실 수 있습니다.

이제 준비는 끝났습니다.

Bootstrapping

import Pulse
import Logging

LoggingSystem.bootstrap(PersistentLogHandler.init)

먼저 LoggingSystem.bootstrap(PersistentLogHandler.init) 메소드를 실행하여 LoggingSystem을 초기화 합니다.

이는 swift-log의 사용하는 로그시스템이며 자세한 내용은 여기에서 확인 가능합니다!

주의할점은 bootstrap 메소드는 프로그램 내에서 최대 1회 실행되어야 합니다!

(저는 AppDelegate에서 호출해주었습니다.)
+ Pulse 2.0 버전에서는 해당 내용이 조금 변경되었습니다 !

NetworkLogging

Networking Logging 방식은 Manual, Automatic 두가지 방법이 있습니다.

Manual with URLSession

먼저 URLSession을 이용한 Logging 방법입니다.

URLSessionDataDelegate에서 dataTask, response를 기록하는 방법입니다.

final class Service: NSObject {
	private let networkLogger = NetworkLogger()
	
	private func request() {
		let session = URLSession(configuration: .default)
		let task = session.dataTask(with: url)
	  	task.delegate = self
	  	task.resume()
	}
}

extension Service: URLSessionDataDelegate {
	func urlSession(
    	_ session: URLSession,
    	dataTask: URLSessionDataTask,
    	didReceive response: URLResponse,
    	completionHandler: @escaping (URLSession.ResponseDisposition) -> Void
 	) {
   		networkLogger.logDataTask(dataTask, didReceive: response)
    	completionHandler(.allow)
  }
}

Manual with Alamofire

다음은 Alamofire를 사용하여 Manual Logging을 하는 방법입니다.

final class Service: NSObject {
	private let networkLogger = NetworkLogger()
	
	private func afRequest() {
		let session = Alamofire.Session(eventMonitors: [ AFNetworkEventMoinitor(logger: networkLogger)])
    	session.request(url).response { data in
      		print("\(data)")
    	}
	}
}

struct AFNetworkEventMoinitor: EventMonitor {
	private let _logger: NetworkLogger
  
	init(logger: NetworkLogger) {
		self._logger = logger
	}
  
 	func urlSession(_ session: URLSession, dataTask:	URLSessionDataTask, didReceive data: Data) {
		_logger.logDataTask(dataTask, didReceive: data)
	}
}

정말 간단하쥬 ?

근데 Manual은 맛보기고 이제 진짜 Automatic Logging을 하러 떠나봅시다

Automatic Logging

// Call it anywhere in your code prior to instantiating a `URLSession`
URLSessionProxyDelegate.enableAutomaticRegistration()

먼저 해당 메소드를 호출해줍니다. (저는 마찬가지로 AppDelegate에서 호출했습니다!)

해당 메소드는 URLSession.init()을 사용할 때마다 delegate를 URLSessionProxyDelegate를 Pulse의 내부에서 동작하는 delegate로 교체하여 삽입합니다.

따라서 URLSession을 통한 모든 네트워킹에 대한 로깅이 가능해집니다.

해당 메소드를 호출 한 후, 이전에 시도했던 request를 logDataTask 메소드 호출 없이 시도해도 로깅이 잘 됩니다.

예시는 Alamofire만 사용하도록 하겠습니다.

final class Service: NSObject {
	func afRequest() {
      Alamofire.Session(configuration: .default).request(url).response { data in
        print("***** Alamofire Response *****")
        print("\(data)")
        print("******************************")
      }
	}
}

Inspector

자. 이제 로깅을 했으니 직접 봐야겠쥬?? 👀

스크린샷에 있는 화면들은 PusleUI에서 제공하는 화면이며, 간단하게 호출 가능합니다.

// at any ViewController for UIKit
present(MainViewController(), animated: true)

// for SwiftUI
let view = MainView()

MainViewController / MainView 모두 동일한 화면으로 이루어져있고,

Console, Network, Pins, Settings 탭 모두 지원합니다.

또한 watchOS, tvOS 등에서도 해당 화면을 동일하게 사용할 수 있다고 합니다.

자세한 내용은 여기를 참고하세요 ☺️

Pulse Pro

본 내용은 다 끝났지만, 하나 더 소개해드리고 마무리 하려합니다!!

보통 개발자분들은 디바이스에서 로그를 보기보단, 개발하시는 mac에서 보는게 더 편하시잖아요? 나만그런가

각설하고, Pluse는 macOS에서 실시간으로 로그를 확인할 수 있는 Application인 Pulse Pro를 제공합니다!

한번 맛을 볼까요? 🏃

우선 releases 에서 최신 버전 zip을 다운받아 Application을 설치해주세요.

그 후 로깅을 하고싶은 프로젝트의 info.plist에 다음 내용을 추가해주세요!

<key>NSLocalNetworkUsageDescription</key>
<string>Network usage required for debugging purposes </string>
<key>NSBonjourServices</key>
<array>
  <string>_pulse._tcp</string>
</array>

이후 Pulse UI의 Settings > Remote Logging을 활성화 하면

연결 할 수 있는 디바이스가 노출되고, 디바이스를 선택하여 연결합니다.

이후에는 로그를 남기게 되면 실시간으로 Pulse Pro Application에서 확인 가능합니다 😄

추가적인 기능도 몇가지 있는것 같은데…. 여기까지만 할게요.. 헿

궁금하신분은 요기!

마무리하며...

적용해보고 싶었던 내용을 샘플로 만들고, 팀원에게 공유하고, 직접 적용해보는건 언제나 짜릿합니다.

(대충 늘 새로워.. 짜릿해… 짤방)

적용도 간단했고, 사용도 편해서 팀원들과 구성원들에게 조금은 도움은 되지 않을까 싶습니다.

코드는 모두 github에 올려두었습니다.

궁금하신점이나 잘못된 내용에 대한 지적은 언제든지 환영합니다.

오늘도 읽어주셔서 감사합니다.

그럼 다음 포스팅에서 만나요 !! 안녕 👋

출처 : https://github.com/kean/Pulse


Update Pulse 2.0

Pulse 글을 쓴지 얼마 되지 않았는데.. Pulse 2.0이 release 되었네요..

지켜 보고 있었는데 기능추가도 있고, 변경사항도 조금 있어서 업데이트 해보려고 합니다! 😅

먼저 Release Note를 보는게 예의겠죠? 몇가지만 함께 살펴봅시다!! 👀

Pulse UI

iOS 16 부터 사용하는 urlSession(_:didCreateTask:) 메소드를 지원한다고 하네요. 👏

이전 버전의 OS에서는 NetworkLogger/logTaskCreated(_:)를 사용하면 된다고 합니다.

Improved Metrics

Metrics에서 original, current request에 대한 정보를 볼 수 있습니다. 또한 transaction들도 나타내 줍니다!

예를들면, 아래 영상에서는 response가 캐시를 통해 전달된 것 인지 확인 할 수 있습니다.
(개인적으로 response가 캐시인지 체크하기 어려웠었는데 좋은 기능인것 같습니다 😃)

original 이 아닌 current request의 Network Load를 보면, status code가 304인것을 확인 할 수 있고,

URLSessionDataTask의 "Source:Cache" 인 이유입니다.

또 Summary 페이지에서는 URLSessionDataTask, URLSessionDownloadTask 등 여러 필드와 섹션이 추가되었습니다.

마지막으로 hostpath 섹션을 분리하여 더욱 보기 쉽고 복사하기 쉽도록 변경되었다고 하네요 !

Insights

Insights가 조금더 시각적인 요소들로 변경된다고합니다.

그중엔 iOS 16부터 사용할 수 있는 Swift Charts도 있는데요, 아직은 포함되지 않은 것 같습니다. 🤓

Decoding Errors

많은 분들에게 가장 도움이 되는 기능이지 않을까 싶습니다.

Network Logger에서 isWaitingForDecoding option이 추가되었고, true일 때는 decoding error가 report 될 때 Pulse는 response body 에 error가 발생한 부분을 hightlight 시켜준다고 합니다! 🤩

요거는 꼭 한번 써봐야겠네요 !!

ETC

ModuleName

Module Name이 변경되었습니다!!

  • PulseCore -> Pulse
  • Pulse -> PulseLogHandler

2.0 이상 버전 업데이트 시 PulseCore not found 에러를 만나도 당황하지 마세요!

Bootstrapping

Module Name이 변경됨에 따라 기존에 사용하던 bootstrapping 방식이 아래와 같이 조금 변경되었습니다.

import PulseLogHandler

LoggingSystem.bootstrap(PersistentLogHandler.init)

작성일 : 2022. 08. 25

profile
hello, iOS

0개의 댓글