iOS 애플리케이션 트레이싱 (Tracing iOS Applications)
iOS 애플리케이션에서 Datadog으로 트레이스를 보내는 방법이에요. Datadog의 dd-sdk-ios 클라이언트 SDK를 사용해 커스텀 스팬을 만들고, 로그를 보내며, 네트워크 요청을 추적할 수 있어요.
출처: 문서
본문
Datadog의 dd-sdk-ios 클라이언트 SDK로 iOS 애플리케이션에서 트레이스를 Datadog으로 보내고 다음 기능을 활용할 수 있어요.
- 앱의 다양한 작업에 대한 커스텀 스팬 만들기.
- 각 스팬에 대해 개별적으로 로그 보내기.
- 각 스팬에 기본·커스텀 속성 사용하기.
- 자동 일괄 전송(bulk posts)으로 네트워크 사용을 최적화하기.
Datadog은 iOS 애플리케이션에서 보낸 수집·인덱싱된 스팬에 대해 비용을 청구하지만, 기본 디바이스에는 청구하지 않아요. 자세한 내용은 APM 요금 문서를 읽어보세요.
설정 (Setup)
-
패키지 관리자에 따라 라이브러리를 의존성으로 선언하세요. Swift Package Manager(SPM)를 권장해요.
- Swift Package Manager (SPM): Apple의 Swift Package Manager로 통합하려면
Package.swift에 다음을 의존성으로 추가하세요.
.package(url: "https://github.com/Datadog/dd-sdk-ios.git", .upToNextMajor(from: "2.0.0"))프로젝트에서 다음 라이브러리를 링크하세요.
DatadogCore DatadogTrace- CocoaPods: CocoaPods로
dd-sdk-ios를 설치할 수 있어요.
pod 'DatadogCore' pod 'DatadogTrace'- Carthage: Carthage로
dd-sdk-ios를 설치할 수 있어요.
github "DataDog/dd-sdk-ios" - Swift Package Manager (SPM): Apple의 Swift Package Manager로 통합하려면
Xcode에서 다음 프레임워크를 링크하세요.
DatadogInternal.xcframework
DatadogCore.xcframework
DatadogTrace.xcframework
- 애플리케이션 컨텍스트와 Datadog 클라이언트 토큰으로 라이브러리를 초기화하세요. 보안상의 이유로 클라이언트 토큰을 사용해야 해요. Datadog API 키는 iOS 애플리케이션 IPA 바이트 코드에 클라이언트 측으로 노출되므로
dd-sdk-ios라이브러리 구성에 사용할 수 없어요.
클라이언트 토큰 설정에 대한 자세한 내용은 클라이언트 토큰 문서를 참고하세요.
app.datadoghq.com 사이트 사용자의 경우:
- Swift:
import DatadogCore
Datadog.initialize(
with: Datadog.Configuration(
clientToken: "<client token>",
env: "<environment>",
service: "<service name>"
),
trackingConsent: trackingConsent
)
- Objective-C:
DDConfiguration *configuration = [[DDConfiguration alloc] initWithClientToken:@"<client token>" env:@"<environment>"];
configuration.service = @"<service name>";
[DDDatadog initializeWithConfiguration:configuration
trackingConsent:trackingConsent];
app.datadoghq.eu 사이트 사용자의 경우 site: .eu1`` (해당 Swift/Objective-C)을 Datadog.Configuration에 지정하세요.
Datadog.initialize(
with: Datadog.Configuration(
clientToken: "<client token>",
env: "<environment>",
site: .eu1,
service: "<service name>"
),
trackingConsent: trackingConsent
)
다른 사이트 사용자도 초기화 시 site: 매개변수에 해당 사이트를 지정하면 됩니다. 지원되는 사이트 값은 다음과 같아요.
us3.datadoghq.com→.us3us5.datadoghq.com→.us5app.ddog-gov.com→.us1_fedus2.ddog-gov.com→.us2_fedap1.datadoghq.com→.ap1ap2.datadoghq.com→.ap2uk1.datadoghq.com→.uk1
Objective-C에서는 [DDSite eu1], [DDSite us3] 등 해당 메서드로 사이트를 설정하세요.
GDPR 규정을 준수하기 위해 SDK는 초기화 시 trackingConsent 값을 요구해요. trackingConsent는 다음 값 중 하나일 수 있어요.
.pending: SDK가 데이터 수집·배치를 시작하지만 Datadog으로 보내지는 않아요. 배치된 데이터를 어떻게 처리할지 결정하려면 새 추적 동의 값을 기다립니다..granted: SDK가 데이터 수집을 시작하고 Datadog으로 보내요..notGranted: SDK가 어떤 데이터도 수집하지 않아요. 로그·트레이스·RUM 이벤트가 Datadog으로 보내지지 않아요.
SDK 초기화 후 추적 동의 값을 바꾸려면 Datadog.set(trackingConsent:) API 호출을 사용하세요.
SDK는 새 값에 따라 동작을 바꿔요. 예를 들어 현재 추적 동의가 .pending이라면:
.granted로 바꾸면 SDK가 현재·향후 모든 데이터를 Datadog으로 보내요..notGranted로 바꾸면 SDK가 현재 모든 데이터를 지우고 향후 데이터 수집을 중지해요.
데이터가 Datadog으로 업로드되기 전에 애플리케이션 샌드박스의 캐시 디렉터리(Library/Caches)에 평문으로 저장돼요. 캐시 디렉터리는 기기에 설치된 다른 어떤 앱도 읽을 수 없어요.
애플리케이션을 작성할 때 개발 로그를 활성화해 SDK의 모든 내부 메시지를 제공된 레벨 이상의 우선순위로 콘솔에 기록할 수 있어요.
- Swift:
Datadog.verbosityLevel = .debug - Objective-C:
DDDatadog.verbosityLevel = DDSDKVerbosityLevelDebug;
- Datadog SDK는 OpenTracing과 OpenTelemetry 표준을 모두 구현해요. 공유 OpenTracing
Tracer를Tracer.shared()로 구성·활성화하세요.
- Swift:
import DatadogTrace
Trace.enable(
with: Trace.Configuration(
networkInfoEnabled: true
)
)
let tracer = Tracer.shared()
- Objective-C:
DDTraceConfiguration *configuration = [[DDTraceConfiguration alloc] init];
configuration.networkInfoEnabled = YES;
[DDTrace enableWith:configuration];
DDTracer *tracer = [Tracer shared];
- 다음 방법으로 코드를 계측하세요.
- Swift:
let span = tracer.startSpan(operationName: "<span_name>")
// 측정하려는 것을 수행하세요 ...
// ... 그런 다음 작업이 끝나면:
span.finish()
- Objective-C:
id<OTSpan> span = [tracer startSpan:@"<span_name>"];
// 측정하려는 것을 수행하세요 ...
// ... 그런 다음 작업이 끝나면:
[span finish];
- (선택) 스팬 사이의 자식-부모 관계를 설정하세요.
- Swift:
let responseDecodingSpan = tracer.startSpan(
operationName: "response decoding",
childOf: networkRequestSpan.context // make it a child of `networkRequestSpan`
)
// ... HTTP 응답 데이터 디코딩 ...
responseDecodingSpan.finish()
- Objective-C:
id<OTSpan> responseDecodingSpan = [tracer startSpan:@"response decoding"
childOf:networkRequestSpan.context];
// ... HTTP 응답 데이터 디코딩 ...
[responseDecodingSpan finish];
- (선택) 스팬에 추가 태그를 제공하세요.
- Swift:
span.setTag(key: "http.url", value: url) - Objective-C:
[span setTag:@"http.url" value:url];
- (선택) 표준 Open Tracing 로그 필드를 사용해 오류 정보를 기록해 스팬에 오류를 첨부하세요.
- Swift:
span.log(
fields: [
OTLogFields.event: "error",
OTLogFields.errorKind: "I/O Exception",
OTLogFields.message: "File not found",
OTLogFields.stack: "FileReader.swift:42",
]
)
- Objective-C:
[span log:@{
@"event": @"error",
@"error.kind": @"I/O Exception",
@"message": @"File not found",
@"stack": @"FileReader.swift:42",
}];
- (선택) 트레이스를 유지하거나 드롭하도록 강제해 샘플링 결정을 재정의하세요. 예를 들어 중요한 트랜잭션의 트레이스는 항상 유지하고, 불필요한 반복 트레이스는 항상 드롭할 수 있어요.
트레이스를 수동으로 유지하려면:
- Swift:
span.keepTrace() - Objective-C:
[span keepTrace];
트레이스를 수동으로 드롭하려면:
- Swift:
span.dropTrace() - Objective-C:
[span dropTrace];
항상 자식 스팬이 생성되거나 컨텍스트 전파가 일어나기 전에 루트 스팬에서 keepTrace() 또는 dropTrace()를 호출하세요. 그렇지 않으면 시스템이 일관성을 보장할 수 없어 부분적인 트레이스만 수집될 수 있어요.
- (선택) 프론트엔드에서 백엔드로처럼 환경 간에 트레이스를 분산하려면 수동으로 하거나 자동 계측을 사용할 수 있어요. 두 경우 모두 모든 요청 또는 샘플링된 요청에만 트레이스 컨텍스트를 주입하도록 선택할 수 있어요. 기본적으로 100% 샘플링이 적용돼요.
* 트레이스를 수동으로 전파하려면 URLRequest 헤더에 스팬 컨텍스트를 주입하세요.
- Swift:
var request: URLRequest = ... // your API에 대한 요청
let span = tracer.startSpan(operationName: "network request")
let traceContextInjection = ... // `.all` 또는 `.sampled`
let headersWriter = HTTPHeadersWriter(traceContextInjection: traceContextInjection)
tracer.inject(spanContext: span.context, writer: headersWriter)
for (headerField, value) in headersWriter.traceHeaderFields {
request.addValue(value, forHTTPHeaderField: headerField)
}
- Objective-C:
id<OTSpan> span = [tracer startSpan:@"network request"];
DDTraceContextInjection traceContextInjection = ...; // `DDTraceContextInjectionAll` 또는 `DDTraceContextInjectionSampled`
DDHTTPHeadersWriter *headersWriter = [[DDHTTPHeadersWriter alloc] initWithTraceContextInjection:traceContextInjection];
NSError *error = nil;
[tracer inject:span.context
format:OT.formatTextMap
carrier:headersWriter
error:&error];
for (NSString *key in headersWriter.traceHeaderFields) {
NSString *value = headersWriter.traceHeaderFields[key];
[request addValue:value forHTTPHeaderField:key];
}
이렇게 하면 요청에 추가 트레이싱 헤더가 설정되므로 백엔드가 요청을 추출해 분산 트레이싱을 계속할 수 있어요. 요청이 끝나면 완료 핸들러 안에서 span.finish()를 호출하세요. 백엔드도 Datadog APM & Distributed Tracing으로 계측되어 있다면 전체 프론트-백 트레이스가 Datadog 대시보드에 나타나요.
* 주어진 호스트에 대한 모든 네트워크 요청을 자동으로 트레이싱하려면 Trace 구성에서 urlSessionTracking과 함께 firstPartyHosts 배열을 지정하세요. 각 항목은 일반 호스트 이름(예: "example.com")이나 단일 *가 있는 와일드카드 패턴(예: "*.example.com")을 허용해요.
- Swift:
import DatadogTrace
Trace.enable(
with: Trace.Configuration(
urlSessionTracking: Trace.Configuration.URLSessionTracking(
firstPartyHostsTracing: .trace(hosts: ["example.com", "api.yourdomain.com", "*.api.yourdomain.com"])
)
)
)
- Objective-C:
@import DatadogObjc;
DDTraceFirstPartyHostsTracing *firstPartyHosts = [DDTraceFirstPartyHostsTracing alloc] initWithHosts:@[@"example.com", @"api.yourdomain.com"]
sampleRate: 20];
DDTraceURLSessionTracking *urlSessionTracking = [DDTraceURLSessionTracking alloc] initWithFirstPartyHostsTracing:firstPartyHosts];
DDTraceConfiguration *configuration = [[DDTraceConfiguration] alloc] init];
[configuration setURLSessionTracking:urlSessionTracking];
[DDTrace enableWith:configuration];
이렇게 하면 example.com과 api.yourdomain.com 호스트에 대한 모든 요청(예: https://api.yourdomain.com/v2/users 또는 https://subdomain.example.com/image.png)이 자동으로 트레이싱돼요.
(선택) 더 정확한 트레이스 타이밍을 위해 델리게이트 타입에 URLSessionInstrumentation을 활성화하세요.
- Swift:
URLSessionInstrumentation.enableDurationBreakdown(
with: .init(
delegateClass: <YourSessionDelegate>.self
)
)
let session = URLSession(
configuration: .default,
delegate: <YourSessionDelegate>(),
delegateQueue: nil
)
- Objective-C:
DDURLSessionInstrumentationConfiguration *config = [[DDURLSessionInstrumentationConfiguration alloc] initWithDelegateClass:[<YourSessionDelegate> class]];
[DDURLSessionInstrumentation enableDurationBreakdownWithConfiguration:config];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:[[<YourSessionDelegate> alloc] init]
delegateQueue:nil];
참고:
- 트레이싱 자동 계측은
URLSession스위즐링을 사용하며 옵트인 방식이에요.urlSessionTracking과firstPartyHosts구성을 지정하지 않으면 스위즐링이 적용되지 않아요. URLSessionInstrumentation없이도 트레이싱은 자동으로 동작하지만, 활성화하면 트레이스 타이밍이 더 정확해져요.
배치 수집 (Batch collection)
모든 스팬은 먼저 로컬 디바이스에 배치로 저장돼요. 각 배치는 수집 사양을 따릅니다. 네트워크를 사용할 수 있고 배터리가 충분히 높아 Datadog SDK가 최종 사용자 경험에 영향을 주지 않을 때 주기적으로 전송돼요. 애플리케이션이 포그라운드에 있는 동안 네트워크를 사용할 수 없거나 데이터 업로드가 실패하면, 성공적으로 보낼 수 있을 때까지 배치가 유지돼요.
즉 사용자가 오프라인 상태로 애플리케이션을 열어도 데이터가 손실되지 않아요.
SDK가 디스크 공간을 너무 많이 사용하지 않도록 데이터가 너무 오래되면 디스크의 데이터는 자동으로 폐기돼요.
초기화 (Initialization)
Trace.Configuration에서 Tracer를 만들 때 사용할 수 있는 속성은 다음과 같아요.
| 메서드 | 설명 |
|---|---|
bundleWithRumEnabled |
true로 설정하면 스팬이 현재 RUM View 정보로 강화돼요. 이렇게 하면 특정 View 수명 동안 생성된 모든 스팬을 RUM Explorer에서 볼 수 있어요. |
customEndpoint |
커스텀 서버로 트레이스를 보낼 URL을 설정해요. |
eventMapper |
스팬 이벤트를 보내기 전에 수정할 매퍼를 설정해요. |
networkInfoEnabled |
true로 설정하면 트레이스를 네트워크 연결 정보(도달성 상태, 연결 유형, 이동통신사 이름 등)로 강화해요. |
sampleRate |
수집할 트레이스의 비율을 정의하는 0-100 값을 설정해요. |
service |
service 값을 설정해요. |
tags |
Tracer가 만든 스팬에 추가할 <KEY>:<VALUE> 태그 쌍을 설정해요. |
urlSessionTracking |
네트워크 요청의 자동 트레이싱을 구성하도록 설정해요. 퍼스트파티 호스트와 샘플 비율, 트레이스 컨텍스트 주입 전략을 정의해요. RUM 같은 다른 기능이 이미 구성했다면 설정하지 마세요. |
더 알아보기 (Learn more)
도움이 되는 추가 문서, 링크, 글: