Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-1744 Collect Kronos telemetry in Internal Monitoring #709

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
24 changes: 24 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@
617B954224BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617B954124BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift */; };
617CD0DD24CEDDD300B0B557 /* RUMUserActionScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617CD0DC24CEDDD300B0B557 /* RUMUserActionScopeTests.swift */; };
617CEB392456BC3A00AD4669 /* TracingUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617CEB382456BC3A00AD4669 /* TracingUUID.swift */; };
61815C06278867D1004A666C /* KronosMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61815C05278867D1004A666C /* KronosMonitorTests.swift */; };
618236892710560900125326 /* DebugWebviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618236882710560900125326 /* DebugWebviewViewController.swift */; };
6182374325D3DFD5006A375B /* CrashReportingWithRUMIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6182374225D3DFD5006A375B /* CrashReportingWithRUMIntegrationTests.swift */; };
6184751526EFCF1300C7C9C5 /* DatadogTestsObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6184751426EFCF1300C7C9C5 /* DatadogTestsObserver.swift */; };
Expand Down Expand Up @@ -493,6 +494,7 @@
61FF283024BC5E2D000B3D9B /* RUMEventFileOutputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FF282F24BC5E2D000B3D9B /* RUMEventFileOutputTests.swift */; };
61FF416225EE5FF400CE35EC /* CrashReportingWithLoggingIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FF416125EE5FF400CE35EC /* CrashReportingWithLoggingIntegrationTests.swift */; };
61FF9A4525AC5DEA001058CC /* RUMViewIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FF9A4425AC5DEA001058CC /* RUMViewIdentity.swift */; };
61FFFB89278457D400401A28 /* KronosMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FFFB88278457D300401A28 /* KronosMonitor.swift */; };
9E26E6B924C87693000B3270 /* RUMDataModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E26E6B824C87693000B3270 /* RUMDataModels.swift */; };
9E2EF44F2694FA14008A7DAE /* VitalInfoSamplerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2EF44E2694FA14008A7DAE /* VitalInfoSamplerTests.swift */; };
9E307C3224C8846D0039607E /* RUMDataModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E26E6B824C87693000B3270 /* RUMDataModels.swift */; };
Expand Down Expand Up @@ -950,6 +952,7 @@
617B954124BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMMonitorConfigurationTests.swift; sourceTree = "<group>"; };
617CD0DC24CEDDD300B0B557 /* RUMUserActionScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMUserActionScopeTests.swift; sourceTree = "<group>"; };
617CEB382456BC3A00AD4669 /* TracingUUID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingUUID.swift; sourceTree = "<group>"; };
61815C05278867D1004A666C /* KronosMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KronosMonitorTests.swift; sourceTree = "<group>"; };
618236882710560900125326 /* DebugWebviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugWebviewViewController.swift; sourceTree = "<group>"; };
6182374225D3DFD5006A375B /* CrashReportingWithRUMIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportingWithRUMIntegrationTests.swift; sourceTree = "<group>"; };
6184751426EFCF1300C7C9C5 /* DatadogTestsObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatadogTestsObserver.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1175,6 +1178,7 @@
61FF282F24BC5E2D000B3D9B /* RUMEventFileOutputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMEventFileOutputTests.swift; sourceTree = "<group>"; };
61FF416125EE5FF400CE35EC /* CrashReportingWithLoggingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportingWithLoggingIntegrationTests.swift; sourceTree = "<group>"; };
61FF9A4425AC5DEA001058CC /* RUMViewIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewIdentity.swift; sourceTree = "<group>"; };
61FFFB88278457D300401A28 /* KronosMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KronosMonitor.swift; sourceTree = "<group>"; };
9E0542CA25F8EBBE007A3D0B /* Kronos.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Kronos.xcframework; path = ../Carthage/Build/Kronos.xcframework; sourceTree = "<group>"; };
9E26E6B824C87693000B3270 /* RUMDataModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMDataModels.swift; sourceTree = "<group>"; };
9E2EF44E2694FA14008A7DAE /* VitalInfoSamplerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VitalInfoSamplerTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2545,6 +2549,14 @@
path = UUIDs;
sourceTree = "<group>";
};
61815C04278867BB004A666C /* Kronos */ = {
isa = PBXGroup;
children = (
61815C05278867D1004A666C /* KronosMonitorTests.swift */,
);
path = Kronos;
sourceTree = "<group>";
};
6182374125D3DFB8006A375B /* CrashReporting */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3107,6 +3119,7 @@
children = (
61F1878325FA121F0022CE9A /* InternalMonitoringFeature.swift */,
61F1878C25FA33A90022CE9A /* InternalMonitor.swift */,
61FFFB8A2784593B00401A28 /* Kronos */,
);
path = InternalMonitoring;
sourceTree = "<group>";
Expand All @@ -3115,6 +3128,7 @@
isa = PBXGroup;
children = (
61F187FB25FA7DD60022CE9A /* InternalMonitoringFeatureTests.swift */,
61815C04278867BB004A666C /* Kronos */,
);
path = InternalMonitoring;
sourceTree = "<group>";
Expand Down Expand Up @@ -3288,6 +3302,14 @@
path = RUMEventOutputs;
sourceTree = "<group>";
};
61FFFB8A2784593B00401A28 /* Kronos */ = {
isa = PBXGroup;
children = (
61FFFB88278457D300401A28 /* KronosMonitor.swift */,
);
path = Kronos;
sourceTree = "<group>";
};
9E06058F26EF904200F5F935 /* LongTasks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4111,6 +4133,7 @@
61D3E0D3277B23F1008BE766 /* KronosDNSResolver.swift in Sources */,
6149FB3A2529D17F00EE387A /* InternalURLsFilter.swift in Sources */,
611529A525E3DD51004F740E /* ValuePublisher.swift in Sources */,
61FFFB89278457D400401A28 /* KronosMonitor.swift in Sources */,
618DCFD724C7265300589570 /* RUMUUID.swift in Sources */,
61B038662527247800518F3C /* URLSessionInterceptor.swift in Sources */,
61B03898252724DE00518F3C /* TracingHTTPHeaders.swift in Sources */,
Expand Down Expand Up @@ -4347,6 +4370,7 @@
61F1A623249B811200075390 /* Encoding.swift in Sources */,
6114FE3B25768AA90084E372 /* ConsentProviderTests.swift in Sources */,
61133C642423990D00786299 /* LoggerTests.swift in Sources */,
61815C06278867D1004A666C /* KronosMonitorTests.swift in Sources */,
617B953D24BF4D8F00E6F443 /* RUMMonitorTests.swift in Sources */,
D244B3A3271EDACD003E1B29 /* SwiftUIExtensionsTests.swift in Sources */,
61F187FC25FA7DD60022CE9A /* InternalMonitoringFeatureTests.swift in Sources */,
Expand Down
33 changes: 31 additions & 2 deletions Datadog/E2ETests/NTP/KronosE2ETests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,45 @@
@testable import Datadog

class KronosE2ETests: E2ETests {
Copy link
Member Author

@ncreated ncreated Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is to also collect this telemetry from our E2E tests and run full KronosMonitor logic in CI environment.

/// The logger sending additional telemetry on Kronos execution. These logs are available in Mobile Integrations org.
/// The logger sending logs on Kronos execution. These logs are available in Mobile Integrations org.
private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional
/// The logger sending telemetry on internal Kronos execution. These logs are available in Mobile Integrations org.
private var telemetryLogger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional
private let queue = DispatchQueue(label: "kronos-monitor-queue")

override func setUp() {
super.setUp()
logger = Logger
.builder
.set(loggerName: "kronos-e2e")
.build()
telemetryLogger = Logger.builder
.set(loggerName: "kronos-e2e-internal-telemetry")
.sendNetworkInfo(true)
.build()
}

override func tearDown() {
logger = nil
telemetryLogger = nil
super.tearDown()
}

/// Creates kronos monitor for checking connections to all IPs resolved from NTP pool and sending additional telemetry on their statuses.
private func createKronosMonitor() -> KronosMonitor? {
if #available(iOS 14.2, *) {
let monitor = KronosInternalMonitor(
queue: queue,
connectionMonitor: IPConnectionMonitor(queue: queue)
)
// Here we redirect IM's logger to E2E Kronos logger (`telemetryLogger`) to send data to Mobile Integrations org, not IM's org
monitor.export(to: InternalMonitor(sdkLogger: telemetryLogger))
return monitor
} else {
return nil
}
}

/// TODO: RUMM-1859: Add E2E tests for monitoring Kronos in nightly tests
func test_kronos_clock_performs_sync_using_datadog_ntp_pool() { // E2E:wip
/// The result of `KronosClock.sync()`.
Expand Down Expand Up @@ -58,6 +81,7 @@ class KronosE2ETests: E2ETests {
KronosClock.sync(
from: pool,
samples: numberOfSamplesForEachIP,
monitor: createKronosMonitor(),
first: { date, offset in // this closure could not be called if all samples to all servers resulted with failure
result.firstReceivedDate = date
result.firstReceivedOffset = offset
Expand Down Expand Up @@ -122,6 +146,7 @@ class KronosE2ETests: E2ETests {

func performKronosNTPClientQuery() -> KronosNTPClientQueryResult {
let testTimeout: TimeInterval = 30
let monitor = createKronosMonitor()

// Given
let pool = "2.datadog.pool.ntp.org" // a pool resolved to multiple IPv4 and IPv6 addresses (e.g. 4 + 4)
Expand All @@ -136,18 +161,22 @@ class KronosE2ETests: E2ETests {
let completionExpectation = expectation(description: "It completes all samples for all IPs")
var result = KronosNTPClientQueryResult()

monitor?.notifySyncStart(from: pool) // must be notified by hand because normally it's called from `KronosClock.sync()`

KronosNTPClient()
.query(
pool: pool,
numberOfSamples: numberOfSamplesForEachIP,
maximumServers: .max, // query all resolved IPs in the pool - to include both IPv4 and IPv6
timeout: timeoutForEachSample
timeout: timeoutForEachSample,
monitor: monitor
) { offset, completed, total in
result.receivedOffsets.append(offset)
result.numberOfCompletedSamples = completed
result.expectedNumberOfSamples = total

if completed == total {
monitor?.notifySyncEnd(serverOffset: offset) // must be notified by hand because normally it's called from `KronosClock.sync()`
completionExpectation.fulfill()
}
}
Expand Down
11 changes: 10 additions & 1 deletion Sources/Datadog/Core/System/Time/ServerDateProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ internal class NTPServerDateProvider: ServerDateProvider {
/// Server offset publisher.
private let publisher: ValuePublisher<TimeInterval?> = ValuePublisher(initialValue: nil)

/// Monitor collecting Kronos telemetry - only enabled if Internal Monitoring is configured.
private let kronosMonitor: KronosMonitor?

init(kronosMonitor: KronosMonitor? = nil) {
self.kronosMonitor = kronosMonitor
}

/// Returns the server time offset or `nil` if not yet determined.
/// This offset gets more precise while synchronization is pending.
var offset: TimeInterval? {
Expand All @@ -29,14 +36,16 @@ internal class NTPServerDateProvider: ServerDateProvider {
func synchronize(with pool: String, completion: @escaping (TimeInterval?) -> Void) {
KronosClock.sync(
from: pool,
monitor: kronosMonitor,
first: { [weak self] _, offset in
self?.publisher.publishAsync(offset)
},
completion: { [weak self] now, offset in
// Kronos only notifies for the first and last samples.
// In case, the last sample does not return an offset, we calculate the offset
// from the returned `now` parameter. The `now` parameter in this callback
// is `Clock.now`, so it is possible to have `now` but not `offset`.
// is `Clock.now` and it can be either offset computed from prior samples or persisted
// in user defaults from previous app session.
if let offset = offset {
self?.publisher.publishAsync(offset)
} else if let now = now {
Expand Down
16 changes: 15 additions & 1 deletion Sources/Datadog/Datadog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,19 @@ public class Datadog {
throw ProgrammerError(description: "SDK is already initialized.")
}

let kronosMonitor: KronosMonitor?
#if DD_SDK_ENABLE_INTERNAL_MONITORING
// Collect Kronos telemetry only if internal monitoring is compiled and enabled
kronosMonitor = configuration.internalMonitoring != nil ? KronosInternalMonitor() : nil
#else
kronosMonitor = nil
#endif

let consentProvider = ConsentProvider(initialConsent: initialTrackingConsent)
let dateProvider = SystemDateProvider()
let dateCorrector = DateCorrector(
deviceDateProvider: dateProvider,
serverDateProvider: NTPServerDateProvider()
serverDateProvider: NTPServerDateProvider(kronosMonitor: kronosMonitor)
)
let userInfoProvider = UserInfoProvider()
let networkConnectionInfoProvider = NetworkConnectionInfoProvider()
Expand Down Expand Up @@ -305,6 +313,12 @@ public class Datadog {
Global.crashReporter = CrashReporter(crashReportingFeature: crashReportingFeature)
Global.crashReporter?.sendCrashReportIfFound()
}

// If Internal Monitoring is enabled and Kronos internal monitor is configured,
// export result of NTP sync to IM.
if let internalMonitoringFeature = InternalMonitoringFeature.instance {
kronosMonitor?.export(to: internalMonitoringFeature.monitor)
}
}

internal init(
Expand Down
Loading