Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions DatadogSDKTesting.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
objects = {

/* Begin PBXBuildFile section */
02DF858038394B24B4534C49 /* TelemetryEventsFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC8A25D6F0A4B818594FE62 /* TelemetryEventsFeature.swift */; };
1F26679E6F497C3AEF3A4845 /* MetricObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5687C35EB7CCAF30113528FC /* MetricObservers.swift */; };
1FB416017E14C140B15E1D97 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3EB9ACD93007FC43F039EE /* Async.swift */; };
300F42B595C3462AB9656B0C /* EarlyFlakeDetectionSwiftTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC931D86ADB841B6969C7A7A /* EarlyFlakeDetectionSwiftTestingTests.swift */; };
3300465F32C8F7EFB93A9D26 /* MockBackendTelemetryParsingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637F01E90EBE5A82DE309F1A /* MockBackendTelemetryParsingTests.swift */; };
3592750B292103668D7668F7 /* MultipartFormURLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE92A3947C2E5BD2183BB4E /* MultipartFormURLRequest.swift */; };
3B086A157E782A8DCA702976 /* LogsApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = D969899DDA68AF3C690F7FF8 /* LogsApi.swift */; };
476CBA69A1DF07E74A0E7311 /* KnownTestsApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1531A96019132E3E9E96A3A7 /* KnownTestsApi.swift */; };
Expand All @@ -18,7 +20,6 @@
56B58A2FC91F21D1ABB0155E /* TelemetryApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB970146040DD4967C7411 /* TelemetryApi.swift */; };
7972B04FB1DFA64DC20032AE /* Telemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E11F924F40C94461C2B6B27 /* Telemetry.swift */; };
7C6CBEE99C831DBEBB28BD67 /* TelemetryObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26CA2B1C720A94291E83285B /* TelemetryObservers.swift */; };
02DF858038394B24B4534C49 /* TelemetryEventsFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC8A25D6F0A4B818594FE62 /* TelemetryEventsFeature.swift */; };
821FA0CC8B62245A4949FDBB /* APITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E85241CF97F1B6DAA49ECA23 /* APITypes.swift */; };
86137D23E1704D17A7B6D486 /* TelemetryExporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DFE52D135C457D9160920A /* TelemetryExporterTests.swift */; };
8EF6F88255506A4CEE6D36B6 /* GitUploadApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F3AA8F51FDDEF0C319080E8 /* GitUploadApi.swift */; };
Expand Down Expand Up @@ -84,8 +85,6 @@
A77C123C2D9425C7009C2BA1 /* KnownTestsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A77C123B2D9425C7009C2BA1 /* KnownTestsTests.swift */; };
A77C123E2D9474E6009C2BA1 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = A77C123D2D9474E6009C2BA1 /* Models.swift */; };
A7926AEF2FCDCBFE007834F2 /* TelemetryLogExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7926AEE2FCDCBFE007834F2 /* TelemetryLogExporter.swift */; };
A7926AF12FCDD411007834F2 /* TelemetryMetricExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7926AF02FCDD411007834F2 /* TelemetryMetricExporter.swift */; };
A7926AF42FCDD411007834F2 /* TelemetryMetricExporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7926AF32FCDD411007834F2 /* TelemetryMetricExporterTests.swift */; };
A7926AF62FCDD411007834F2 /* TelemetryLogExporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7926AF52FCDD411007834F2 /* TelemetryLogExporterTests.swift */; };
A794A8FF2E7990D20044FE3C /* TestManagementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A794A8FE2E7990C40044FE3C /* TestManagementTests.swift */; };
A79DA5B42F928F87004BCA8C /* SwiftTestingSmokeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79DA5B32F928F87004BCA8C /* SwiftTestingSmokeTests.swift */; };
Expand Down Expand Up @@ -434,11 +433,12 @@
1495758A45B516A2C584B845 /* TestImpactAnalysisApi.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TestImpactAnalysisApi.swift; sourceTree = "<group>"; };
1531A96019132E3E9E96A3A7 /* KnownTestsApi.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = KnownTestsApi.swift; sourceTree = "<group>"; };
26CA2B1C720A94291E83285B /* TelemetryObservers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TelemetryObservers.swift; sourceTree = "<group>"; };
6BC8A25D6F0A4B818594FE62 /* TelemetryEventsFeature.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TelemetryEventsFeature.swift; sourceTree = "<group>"; };
2E11F924F40C94461C2B6B27 /* Telemetry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Telemetry.swift; sourceTree = "<group>"; };
31F8747157604DB48FE692EB /* AutoTestRetriesSwiftTestingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoTestRetriesSwiftTestingTests.swift; sourceTree = "<group>"; };
5687C35EB7CCAF30113528FC /* MetricObservers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MetricObservers.swift; sourceTree = "<group>"; };
5F3AA8F51FDDEF0C319080E8 /* GitUploadApi.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GitUploadApi.swift; sourceTree = "<group>"; };
637F01E90EBE5A82DE309F1A /* MockBackendTelemetryParsingTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MockBackendTelemetryParsingTests.swift; sourceTree = "<group>"; };
6BC8A25D6F0A4B818594FE62 /* TelemetryEventsFeature.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TelemetryEventsFeature.swift; sourceTree = "<group>"; };
6F3EB9ACD93007FC43F039EE /* Async.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Async.swift; sourceTree = "<group>"; };
81894A4E29B0A28B00108C51 /* Retrying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Retrying.swift; sourceTree = "<group>"; };
8194A2242940B33100B4B592 /* DDSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDSession.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -503,8 +503,6 @@
A77C123B2D9425C7009C2BA1 /* KnownTestsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KnownTestsTests.swift; sourceTree = "<group>"; };
A77C123D2D9474E6009C2BA1 /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
A7926AEE2FCDCBFE007834F2 /* TelemetryLogExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryLogExporter.swift; sourceTree = "<group>"; };
A7926AF02FCDD411007834F2 /* TelemetryMetricExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryMetricExporter.swift; sourceTree = "<group>"; };
A7926AF32FCDD411007834F2 /* TelemetryMetricExporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryMetricExporterTests.swift; sourceTree = "<group>"; };
A7926AF52FCDD411007834F2 /* TelemetryLogExporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryLogExporterTests.swift; sourceTree = "<group>"; };
A794A8FE2E7990C40044FE3C /* TestManagementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestManagementTests.swift; sourceTree = "<group>"; };
A79DA5B22F928F71004BCA8C /* IntegrationTests-UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "IntegrationTests-UnitTests.xctestplan"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -832,7 +830,6 @@
isa = PBXGroup;
children = (
04DFE52D135C457D9160920A /* TelemetryExporterTests.swift */,
A7926AF32FCDD411007834F2 /* TelemetryMetricExporterTests.swift */,
A7926AF52FCDD411007834F2 /* TelemetryLogExporterTests.swift */,
);
path = Telemetry;
Expand Down Expand Up @@ -926,6 +923,7 @@
A7EE000000020000000000A1 /* LibraryConfigurationErrorTagsTests.swift */,
A7EE000000020000000000A3 /* AdditionalTagsFeatureTests.swift */,
C8BF04956AA1E2FADBB80244 /* TelemetryTests.swift */,
637F01E90EBE5A82DE309F1A /* MockBackendTelemetryParsingTests.swift */,
);
path = Features;
sourceTree = "<group>";
Expand Down Expand Up @@ -1015,7 +1013,6 @@
children = (
BC161A86B91745F4BDC88FF1 /* TelemetryExporter.swift */,
A7926AEE2FCDCBFE007834F2 /* TelemetryLogExporter.swift */,
A7926AF02FCDD411007834F2 /* TelemetryMetricExporter.swift */,
5687C35EB7CCAF30113528FC /* MetricObservers.swift */,
);
path = Telemetry;
Expand Down Expand Up @@ -2143,6 +2140,7 @@
A7FC26632BA1F6BF00067E26 /* StderrCaptureTests.swift in Sources */,
A754BB0A2F86CD3B001613EB /* MockSwiftTesting.swift in Sources */,
4CCD47B30A3B513F26C8936E /* TelemetryTests.swift in Sources */,
3300465F32C8F7EFB93A9D26 /* MockBackendTelemetryParsingTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2185,7 +2183,6 @@
A7FC264A2BA1ECF800067E26 /* File.swift in Sources */,
A7FC264D2BA1ED1200067E26 /* Exporter.swift in Sources */,
A7FC26302BA1ECBD00067E26 /* CoverageExporter.swift in Sources */,
A7926AF12FCDD411007834F2 /* TelemetryMetricExporter.swift in Sources */,
A7AB7C2026E7EB1100000011 /* CoverageData.swift in Sources */,
A7AB7C2026E7EB1100000013 /* CoverageProcessor.swift in Sources */,
A7FC263B2BA1ECCF00067E26 /* Feature.swift in Sources */,
Expand Down Expand Up @@ -2239,7 +2236,6 @@
A7B747C02C60E1E7009B4B93 /* SwiftUtilsTests.swift in Sources */,
A7FC26822BA1F81D00067E26 /* DeviceMock.swift in Sources */,
86137D23E1704D17A7B6D486 /* TelemetryExporterTests.swift in Sources */,
A7926AF42FCDD411007834F2 /* TelemetryMetricExporterTests.swift in Sources */,
A7926AF62FCDD411007834F2 /* TelemetryLogExporterTests.swift in Sources */,
A7FC26702BA1F7FA00067E26 /* SpansExporterTests.swift in Sources */,
A7FC268C2BA1F82300067E26 /* HTTPClientTests.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions IntegrationTests/Runner/UnitTests+XCTestSmoke.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ struct UnitTestsXCTestSmoke: IntergationTestSuite {
}
}

/// The SDK's own instrumentation telemetry round-trips to the backend: the
/// app-lifecycle events plus self-metrics produced over a basic test run.
@Test func telemetryReported() async throws {
try await run(test: "XCBasicPass/testBasicPass") { backend, success in
#expect(success == true)
// App-lifecycle: app-started is sent directly; app-closing rides the
// final batch flushed on shutdown.
#expect(backend.telemetryEventTypes.contains("app-started"))
#expect(backend.telemetryEventTypes.contains("app-closing"))
// Self-metrics reached the backend via generate-metrics — `test_session`
// is emitted once per session.
let metricNames = Set(backend.telemetryMetricSeries.map(\.metric))
#expect(!metricNames.isEmpty)
#expect(metricNames.contains("test_session"))
}
}

@Test func basicSkip() async throws {
try await run(test: "XCBasicSkip/testBasicSkip") { backend, success in
let spans = backend.allTestSpans
Expand Down
15 changes: 15 additions & 0 deletions Sources/DatadogSDKTesting/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ final class Config {
var instrumentationTelemetryEnabled: Bool = true
/// Telemetry metric collection/export interval, in seconds. Clamped to 1...3600.
var telemetryHeartbeatInterval: TimeInterval = 60
/// How often accumulated telemetry metrics are drained to the exporter, in
/// seconds. Kept short so a crash loses at most one interval. Clamped to 1...3600.
var telemetryFlushInterval: TimeInterval = 10
/// Buffered telemetry distribution samples that force an early drain (a
/// safety backstop for bursts; the timer does the normal draining). Generous
/// since each sample is just an 8-byte `Double` — 65536 ≈ 512 KB. Clamped to >= 1.
var telemetryDistributionBufferSize: Int = 65536

/// Avoids configuring the traces exporter
var disableTracesExporting: Bool = false
Expand Down Expand Up @@ -160,6 +167,12 @@ final class Config {
if let interval = env[.telemetryHeartbeatInterval, Int.self] {
telemetryHeartbeatInterval = TimeInterval(min(3600, max(1, interval)))
}
if let interval = env[.telemetryFlushInterval, Int.self] {
telemetryFlushInterval = TimeInterval(min(3600, max(1, interval)))
}
if let size = env[.telemetryDistributionBufferSize, Int.self] {
telemetryDistributionBufferSize = max(1, size)
}

/// UI testing properties
tracerTraceId = env[.tracerTraceId]
Expand Down Expand Up @@ -253,6 +266,8 @@ extension Config: CustomDebugStringConvertible {
Test Management Attempt To Fix Retries: \(testManagementAttemptToFixRetries.map(String.init) ?? "nil")
Instrumentation Telemetry Enabled: \(instrumentationTelemetryEnabled)
Telemetry Heartbeat Interval: \(telemetryHeartbeatInterval)
Telemetry Flush Interval: \(telemetryFlushInterval)
Telemetry Distribution Buffer Size: \(telemetryDistributionBufferSize)
Test Retries Enabled: \(testRetriesEnabled)
Test Retries Count: \(testRetriesTestRetryCount)
Test Retries Total Count: \(testRetriesTotalRetryCount)
Expand Down
21 changes: 12 additions & 9 deletions Sources/DatadogSDKTesting/DDTracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,10 @@ internal class DDTracer {
// Build the telemetry manager before the exporter so its observers can
// be wired into the exporter's upload/serialization pipeline.
let telemetry: Telemetry? = conf.instrumentationTelemetryEnabled
? DDTracer.makeTelemetry(api: api, configuration: exporterConfiguration, resource: resource,
exportInterval: conf.telemetryHeartbeatInterval)
? DDTracer.makeTelemetry(api: api, configuration: exporterConfiguration,
flushInterval: conf.telemetryFlushInterval,
heartbeatInterval: conf.telemetryHeartbeatInterval,
distributionCap: conf.telemetryDistributionBufferSize)
: nil

// Exporter files live under the cache manager's session directory so
Expand Down Expand Up @@ -216,7 +218,8 @@ internal class DDTracer {
/// storage or exporter can't be created, in which case telemetry is simply
/// not gathered.
private static func makeTelemetry(api: TestOptimizationApi, configuration: ExporterConfiguration,
resource: Resource, exportInterval: TimeInterval) -> Telemetry?
flushInterval: TimeInterval, heartbeatInterval: TimeInterval,
distributionCap: Int) -> Telemetry?
{
guard let cacheManager = DDTestMonitor.cacheManager,
let storage = try? cacheManager.session(feature: "telemetry")
Expand All @@ -233,12 +236,12 @@ internal class DDTracer {
return nil
}

let metricExporter = TelemetryMetricExporter(telemetryExporter: telemetryExporter,
namespace: .civisibility,
distributionNamespace: .civisibility)
return Telemetry(api: api.telemetry, telemetryExporter: telemetryExporter,
metricExporter: metricExporter, resource: resource,
exportInterval: exportInterval,
return Telemetry(api: api.telemetry,
exporter: telemetryExporter,
flushInterval: flushInterval,
heartbeatInterval: heartbeatInterval,
distributionCap: distributionCap,
clock: DDTestMonitor.clock,
configuration: Self.telemetryConfiguration())
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/DatadogSDKTesting/Environment/EnvironmentKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ internal enum EnvironmentKey: String, CaseIterable {
case testManagementEnabled = "DD_TEST_MANAGEMENT_ENABLED"
case instrumentationTelemetryEnabled = "DD_INSTRUMENTATION_TELEMETRY_ENABLED"
case telemetryHeartbeatInterval = "DD_TELEMETRY_HEARTBEAT_INTERVAL"
case telemetryFlushInterval = "DD_TELEMETRY_FLUSH_INTERVAL"
case telemetryDistributionBufferSize = "DD_TELEMETRY_DISTRIBUTION_BUFFER_SIZE"
case testManagementAttemptToFixRetries = "DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES"
case disableSourceLocation = "DD_DISABLE_SOURCE_LOCATION"
case localTestEnvironmentPort = "DD_LOCAL_TEST_ENVIRONMENT_PORT"
Expand Down
Loading
Loading