Skip to content

Commit 564152b

Browse files
committed
RUM-8042 Add count of batches blocked
1 parent 2a444dc commit 564152b

File tree

3 files changed

+62
-27
lines changed

3 files changed

+62
-27
lines changed

DatadogCore/Sources/Core/Upload/DataUploadWorker.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,23 @@ internal class DataUploadWorker: DataUploadWorkerType {
7373
let context = contextProvider.read()
7474
let blockersForUpload = uploadConditions.blockersForUpload(with: context)
7575
let isSystemReady = blockersForUpload.isEmpty
76-
let files = isSystemReady ? fileReader.readFiles(limit: maxBatchesPerUpload) : nil
77-
if let files = files, !files.isEmpty {
76+
let files = fileReader.readFiles(limit: maxBatchesPerUpload)
77+
78+
if !files.isEmpty && isSystemReady {
7879
DD.logger.debug("⏳ (\(self.featureName)) Uploading batches...")
7980
self.backgroundTaskCoordinator?.beginBackgroundTask()
8081
self.uploadFile(from: files.reversed(), context: context)
8182
sendUploadCycleMetric()
8283
} else {
83-
let batchLabel = files?.isEmpty == false ? "YES" : (isSystemReady ? "NO" : "NOT CHECKED")
84+
let batchLabel = files.isEmpty ? "NO" : "YES"
8485
DD.logger.debug("💡 (\(self.featureName)) No upload. Batch to upload: \(batchLabel), System conditions: \(blockersForUpload.description)")
8586
self.delay.increase()
8687
self.backgroundTaskCoordinator?.endBackgroundTask()
8788
self.scheduleNextCycle()
88-
sendBatchBlockedMetric(blockers: blockersForUpload)
89+
sendBatchBlockedMetric(blockers: blockersForUpload, batchCount: files.count)
8990
}
9091
}
92+
9193
self.readWork = readWorkItem
9294

9395
// Start sending batches immediately after initialization:
@@ -107,6 +109,7 @@ internal class DataUploadWorker: DataUploadWorkerType {
107109
return
108110
}
109111

112+
let filesCount = files.count
110113
var files = files
111114
guard let file = files.popLast() else {
112115
self.scheduleNextCycle()
@@ -127,6 +130,7 @@ internal class DataUploadWorker: DataUploadWorkerType {
127130
DD.logger.debug(" → (\(self.featureName)) not delivered, will be retransmitted: \(uploadStatus.userDebugDescription)")
128131
self.delay.increase()
129132
self.scheduleNextCycle()
133+
sendBatchBlockedMetric(status: uploadStatus, batchCount: filesCount)
130134
return
131135
}
132136

@@ -147,7 +151,6 @@ internal class DataUploadWorker: DataUploadWorkerType {
147151
previousUploadStatus = nil
148152

149153
if let error = uploadStatus.error {
150-
sendBatchBlockedMetric(error: error)
151154
throw error // Throw to report the request error accordingly
152155
}
153156
} catch DataUploadError.httpError(statusCode: .unauthorized), DataUploadError.httpError(statusCode: .forbidden) {
@@ -241,7 +244,7 @@ internal class DataUploadWorker: DataUploadWorkerType {
241244
)
242245
}
243246

244-
private func sendBatchBlockedMetric(blockers: [DataUploadConditions.Blocker]) {
247+
private func sendBatchBlockedMetric(blockers: [DataUploadConditions.Blocker], batchCount: Int) {
245248
guard !blockers.isEmpty else {
246249
return
247250
}
@@ -252,6 +255,7 @@ internal class DataUploadWorker: DataUploadWorkerType {
252255
SDKMetricFields.typeKey: BatchBlockedMetric.typeValue,
253256
BatchMetric.trackKey: featureName,
254257
BatchBlockedMetric.uploaderDelayKey: delay.current,
258+
BatchBlockedMetric.batchCount: batchCount,
255259
BatchBlockedMetric.blockers: blockers.map {
256260
switch $0 {
257261
case .battery: return "low_battery"
@@ -264,13 +268,18 @@ internal class DataUploadWorker: DataUploadWorkerType {
264268
)
265269
}
266270

267-
private func sendBatchBlockedMetric(error: DataUploadError) {
271+
private func sendBatchBlockedMetric(status: DataUploadStatus, batchCount: Int) {
272+
guard let error = status.error else {
273+
return
274+
}
275+
268276
telemetry.metric(
269277
name: BatchBlockedMetric.name,
270278
attributes: [
271279
SDKMetricFields.typeKey: BatchBlockedMetric.typeValue,
272280
BatchMetric.trackKey: featureName,
273281
BatchBlockedMetric.uploaderDelayKey: delay.current,
282+
BatchBlockedMetric.batchCount: batchCount,
274283
BatchBlockedMetric.failure: {
275284
switch error {
276285
case let .httpError(code): return "intake-code-\(code.rawValue)"

DatadogCore/Sources/SDKMetrics/BatchMetrics.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ internal enum BatchBlockedMetric {
142142
/// It is applied in addition to the telemetry sample rate (20% by default).
143143
static let sampleRate: Float = 1.5 // 1.5%
144144
/// The key for uploader's current delay.
145-
static let uploaderDelayKey = "uploader_delay"
145+
static let uploaderDelayKey = "uploader_delay.current"
146+
/// The key for count of bacthes being blocked.
147+
static let batchCount = "batch_count"
146148

147149
/// List of upload blockers
148150
static let blockers = "blockers"

DatadogCore/Tests/Datadog/Core/Upload/DataUploadWorkerTests.swift

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -609,13 +609,8 @@ class DataUploadWorkerTests: XCTestCase {
609609
worker.cancelSynchronously()
610610

611611
// Then
612-
XCTAssertEqual(telemetry.messages.count, 2)
612+
XCTAssertEqual(telemetry.messages.count, 1)
613613
XCTAssertNotNil(telemetry.messages.firstMetric(named: "upload_cycle"), "An upload cycle metric should be send to `telemetry`.")
614-
615-
let metric = try XCTUnwrap(telemetry.messages.firstMetric(named: "Batch Blocked"), "A Batch Blocked metric should be send to `telemetry`.")
616-
XCTAssertEqual(metric.attributes["failure"] as? String, "intake-code-\(randomStatusCode.rawValue)")
617-
XCTAssertNil(metric.attributes["blockers"])
618-
XCTAssertEqual(metric.attributes["track"] as? String, featureName)
619614
}
620615

621616
func testWhenDataIsUploadedWithAlertingStatusCode_itSendsErrorTelemetry() throws {
@@ -659,17 +654,9 @@ class DataUploadWorkerTests: XCTestCase {
659654
worker.cancelSynchronously()
660655

661656
// Then
662-
XCTAssertEqual(telemetry.messages.count, 3)
663-
664-
XCTAssertNotNil(telemetry.messages.firstMetric(named: "upload_cycle"), "An upload cycle metric should be send to `telemetry`.")
665657

666658
let error = try XCTUnwrap(telemetry.messages.firstError(), "An error should be send to `telemetry`.")
667659
XCTAssertEqual(error.message,"Data upload finished with status code: \(randomStatusCode.rawValue)")
668-
669-
let metric = try XCTUnwrap(telemetry.messages.firstMetric(named: "Batch Blocked"), "A Batch Blocked metric should be send to `telemetry`.")
670-
XCTAssertEqual(metric.attributes["failure"] as? String, "intake-code-\(randomStatusCode.rawValue)")
671-
XCTAssertNil(metric.attributes["blockers"])
672-
XCTAssertEqual(metric.attributes["track"] as? String, featureName)
673660
}
674661

675662
func testWhenDataCannotBeUploadedDueToNetworkError_itSendsErrorTelemetry() throws {
@@ -707,15 +694,52 @@ class DataUploadWorkerTests: XCTestCase {
707694
worker.cancelSynchronously()
708695

709696
// Then
710-
XCTAssertEqual(telemetry.messages.count, 3)
711-
712-
XCTAssertNotNil(telemetry.messages.firstMetric(named: "upload_cycle"), "An upload cycle metric should be send to `telemetry`.")
713-
714697
let error = try XCTUnwrap(telemetry.messages.firstError(), "An error should be send to `telemetry`.")
715698
XCTAssertEqual(error.message, #"Data upload finished with error - Error Domain=abc Code=0 "(null)""#)
699+
}
700+
701+
func testWhenDataIsUploadedWithRetryableStatusCode_itSendsBatchBlockedTelemetry() throws {
702+
// Given
703+
let telemetry = TelemetryMock()
704+
705+
writer.write(value: ["key": "value"])
706+
let randomStatusCode: HTTPResponseStatusCode = [
707+
.requestTimeout,
708+
.tooManyRequests,
709+
.internalServerError,
710+
.serviceUnavailable
711+
].randomElement()!
712+
713+
// When
714+
let startUploadExpectation = self.expectation(description: "Upload has started")
715+
let mockDataUploader = DataUploaderMock(
716+
uploadStatus: .mockWith(needsRetry: true, error: .httpError(statusCode: randomStatusCode))
717+
)
716718

719+
mockDataUploader.onUpload = { previousUploadStatus in
720+
XCTAssertNil(previousUploadStatus)
721+
startUploadExpectation.fulfill()
722+
}
723+
724+
let featureName: String = .mockRandom()
725+
let worker = DataUploadWorker(
726+
queue: uploaderQueue,
727+
fileReader: reader,
728+
dataUploader: mockDataUploader,
729+
contextProvider: .mockAny(),
730+
uploadConditions: .alwaysUpload(),
731+
delay: DataUploadDelay(performance: UploadPerformanceMock.veryQuickInitialUpload),
732+
featureName: featureName,
733+
telemetry: telemetry,
734+
maxBatchesPerUpload: .mockRandom(min: 1, max: 100)
735+
)
736+
737+
wait(for: [startUploadExpectation], timeout: 0.5)
738+
worker.cancelSynchronously()
739+
740+
// Then
717741
let metric = try XCTUnwrap(telemetry.messages.firstMetric(named: "Batch Blocked"), "A Batch Blocked metric should be send to `telemetry`.")
718-
XCTAssertEqual(metric.attributes["failure"] as? String, "network-code-\(nserror.code)")
742+
XCTAssertEqual(metric.attributes["failure"] as? String, "intake-code-\(randomStatusCode.rawValue)")
719743
XCTAssertNil(metric.attributes["blockers"])
720744
XCTAssertEqual(metric.attributes["track"] as? String, featureName)
721745
}

0 commit comments

Comments
 (0)