Skip to content

Commit 596877c

Browse files
devjoonnbryce-b
andauthored
Add synchronous processing and HTTP status code validation to OtlpHttpTraceExporter (#1005)
* feat: update OtlpHttpTraceExporter export synchronous and validate HTTP status codes * fix: remove duplicate header values * fix: add timeout to OtlpHttpTraceExporter export/flush methods --------- Co-authored-by: Bryce Buchanan <75274611+bryce-b@users.noreply.github.com>
1 parent 23f7d80 commit 596877c

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

Sources/Exporters/OpenTelemetryProtocolHttp/HTTPClient.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,14 @@ func httpClientResult(for taskResult: (Data?, URLResponse?, Error?)) -> Result<H
7171
)
7272
}
7373

74+
let statusCode = httpResponse.statusCode
75+
guard (200..<300).contains(statusCode) else {
76+
return .failure(
77+
HTTPClientError(
78+
description: "HTTP request failed with status code: \(statusCode)"
79+
)
80+
)
81+
}
82+
7483
return .success(httpResponse)
7584
}

Sources/Exporters/OpenTelemetryProtocolHttp/trace/OtlpHttpTraceExporter.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class OtlpHttpTraceExporter: OtlpHttpExporterBase, SpanExporter {
5656

5757
public func export(spans: [SpanData], explicitTimeout: TimeInterval? = nil)
5858
-> SpanExporterResultCode {
59+
var resultValue: SpanExporterResultCode = .success
5960
var sendingSpans: [SpanData] = []
6061
exporterLock.withLockVoid {
6162
pendingSpans.append(contentsOf: spans)
@@ -68,7 +69,12 @@ public class OtlpHttpTraceExporter: OtlpHttpExporterBase, SpanExporter {
6869
$0.resourceSpans = SpanAdapter.toProtoResourceSpans(
6970
spanDataList: sendingSpans)
7071
}
71-
let request = createRequest(body: body, endpoint: endpoint)
72+
let semaphore = DispatchSemaphore(value: 0)
73+
var request = createRequest(body: body, endpoint: endpoint)
74+
75+
let timeout = min(explicitTimeout ?? TimeInterval.greatestFiniteMagnitude, config.timeout)
76+
request.timeoutInterval = timeout
77+
7278
exporterMetrics?.addSeen(value: sendingSpans.count)
7379
httpClient.send(request: request) { [weak self] result in
7480
switch result {
@@ -80,9 +86,17 @@ public class OtlpHttpTraceExporter: OtlpHttpExporterBase, SpanExporter {
8086
self?.pendingSpans.append(contentsOf: sendingSpans)
8187
}
8288
OpenTelemetry.instance.feedbackHandler?("\(error)")
89+
resultValue = .failure
8390
}
91+
semaphore.signal()
92+
}
93+
94+
let waitResult = semaphore.wait(timeout: .now() + timeout)
95+
if waitResult == .timedOut {
96+
exporterMetrics?.addFailed(value: sendingSpans.count)
97+
return .failure
8498
}
85-
return .success
99+
return resultValue
86100
}
87101

88102
public func flush(explicitTimeout: TimeInterval? = nil)
@@ -99,7 +113,9 @@ public class OtlpHttpTraceExporter: OtlpHttpExporterBase, SpanExporter {
99113
spanDataList: pendingSpans)
100114
}
101115
let semaphore = DispatchSemaphore(value: 0)
102-
let request = createRequest(body: body, endpoint: endpoint)
116+
var request = createRequest(body: body, endpoint: endpoint)
117+
let timeout = min(explicitTimeout ?? TimeInterval.greatestFiniteMagnitude, config.timeout)
118+
request.timeoutInterval = timeout
103119

104120
httpClient.send(request: request) { [weak self] result in
105121
switch result {
@@ -112,7 +128,12 @@ public class OtlpHttpTraceExporter: OtlpHttpExporterBase, SpanExporter {
112128
}
113129
semaphore.signal()
114130
}
115-
semaphore.wait()
131+
132+
let waitResult = semaphore.wait(timeout: .now() + timeout)
133+
if waitResult == .timedOut {
134+
exporterMetrics?.addFailed(value: pendingSpans.count)
135+
return .failure
136+
}
116137
}
117138
return resultValue
118139
}

0 commit comments

Comments
 (0)