From 0032966c2c600f608461d5e9a75d397627fb6557 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Tue, 20 May 2025 12:26:53 -0700 Subject: [PATCH 01/22] DEMRUM-773 Initial Network Info method --- .../SplunkAgent.xcodeproj/project.pbxproj | 42 +++++++++ .../SplunkNetworkInfo/NetworkInfo.swift | 87 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift diff --git a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj index ca5cea2f..63122014 100644 --- a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj +++ b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj @@ -741,6 +741,7 @@ 52D945692DC0A62D00DE8220 /* SplunkWebViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SplunkWebViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52D945A72DC0A70700DE8220 /* SplunkWebViewProxy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SplunkWebViewProxy.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52D945AF2DC0A70700DE8220 /* SplunkWebViewProxyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SplunkWebViewProxyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BA3376982DDD042300F45723 /* NetworkInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfo.swift; sourceTree = ""; }; BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesSpanProcessor.swift; sourceTree = ""; }; BA4C08512DC83AF0008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesLogRecordProcessor.swift; sourceTree = ""; }; BA7A63BB2DB8196800A44570 /* MutableAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableAttributesTests.swift; sourceTree = ""; }; @@ -1281,6 +1282,7 @@ 4B5A5BD62D5E4FBC009DA0D5 /* SplunkSlowFrameDetector */, 4B5A5BC32D5E4E33009DA0D5 /* SplunkCommon */, 4B5A5B932D5E4C79009DA0D5 /* SplunkNetwork */, + BA3376932DDD020700F45723 /* SplunkNetworkInfo */, 4B536BF12B67FADC004A6C7C /* Configurations */, E4E9747A2B1643EE00ACB469 /* Sources */, E46896332B21C8FF00727A6A /* Tests */, @@ -2317,6 +2319,46 @@ path = WebViewInstrumentation; sourceTree = ""; }; + BA3376932DDD020700F45723 /* SplunkNetworkInfo */ = { + isa = PBXGroup; + children = ( + BA3376942DDD023D00F45723 /* Sources */, + BA3376952DDD024800F45723 /* Tests */, + ); + path = SplunkNetworkInfo; + sourceTree = ""; + }; + BA3376942DDD023D00F45723 /* Sources */ = { + isa = PBXGroup; + children = ( + BA3376962DDD025E00F45723 /* SplunkNetworkInfo */, + ); + path = Sources; + sourceTree = ""; + }; + BA3376952DDD024800F45723 /* Tests */ = { + isa = PBXGroup; + children = ( + BA3376972DDD027100F45723 /* SplunkNetworkInfoTests */, + ); + path = Tests; + sourceTree = ""; + }; + BA3376962DDD025E00F45723 /* SplunkNetworkInfo */ = { + isa = PBXGroup; + children = ( + BA3376982DDD042300F45723 /* NetworkInfo.swift */, + ); + path = SplunkNetworkInfo; + sourceTree = ""; + }; + BA3376972DDD027100F45723 /* SplunkNetworkInfoTests */ = { + isa = PBXGroup; + children = ( + ); + path = SplunkNetworkInfoTests; + sourceTree = ""; + }; BA7A63BA2DB818AD00A44570 /* Model */ = { isa = PBXGroup; children = ( diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift new file mode 100644 index 00000000..09608970 --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -0,0 +1,87 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import Network +import OpenTelemetryApi + +public class NetworkInfo { + public enum ConnectionType: String { + case wifi + case cellular + case wiredEthernet + case other + case unavailable + } + + public static let shared = NetworkMonitor() + + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "NetworkMonitorQueue") + private let tracer: Tracer + + public private(set) var isConnected: Bool = false + public private(set) var connectionType: ConnectionType = .unavailable + public private(set) var isVPNActive: Bool = false + + public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? + + private init(tracer: Tracer? = nil) { + self.tracer = tracer ?? OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkMonitor", instrumentationVersion: "1.0") + + monitor.pathUpdateHandler = { [weak self] path in + guard let self = self else { return } + self.isConnected = path.status == .satisfied + self.connectionType = self.getConnectionType(path) + self.isVPNActive = path.availableInterfaces.contains(where: { iface in + iface.type == .other && + (iface.name.lowercased().contains("utun") || + iface.name.lowercased().contains("ppp") || + iface.name.lowercased().contains("ipsec")) + }) + self.sendNetworkChangeSpan() + self.statusChangeHandler?(self.isConnected, self.connectionType, self.isVPNActive) + } + monitor.start(queue: queue) + // Send initial state span + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in + self?.sendNetworkChangeSpan() + } + } + + private func getConnectionType(_ path: NWPath) -> ConnectionType { + if path.usesInterfaceType(.wifi) { + return .wifi + } else if path.usesInterfaceType(.cellular) { + return .cellular + } else if path.usesInterfaceType(.wiredEthernet) { + return .wiredEthernet + } else if path.status == .unsatisfied { + return .unavailable + } else { + return .other + } + } + + private func sendNetworkChangeSpan() { + let span = tracer.spanBuilder(spanName: "network.change").startSpan() + span.setAttribute(key: "network.connected", value: isConnected) + span.setAttribute(key: "network.type", value: connectionType.rawValue) + span.setAttribute(key: "network.vpn", value: isVPNActive) + span.end() + } +} From ed48d3cb911e3e77ddbd7f1df9800770596cb123 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 26 May 2025 19:27:38 -0700 Subject: [PATCH 02/22] DEMRUM-773 Network Info module support --- .../Modules/Pool/DefaultModulesPool.swift | 5 ++ .../SplunkAgent.xcodeproj/project.pbxproj | 14 +++++ .../Module/NetworkInfo+Module.swift | 51 ++++++++++++++++++ .../Module/NetworkInfoConfiguration.swift | 22 ++++++++ .../NetworkInfoRemoteConfiguration.swift | 54 +++++++++++++++++++ .../SplunkNetworkInfo/NetworkInfo.swift | 8 +-- 6 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift create mode 100644 SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift create mode 100644 SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift index 0b0577db..b90d3e59 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift @@ -70,6 +70,11 @@ class DefaultModulesPool: AgentModulesPool { knownModules.append(NetworkInstrumentation.self) #endif + // Network Info + #if canImport(SplunkNetworkInfo) + knownModules.append(NetworkInfo.self) + #endif + // Slow Frame Detector #if canImport(SplunkSlowFrameDetector) knownModules.append(SlowFrameDetector.self) diff --git a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj index 63122014..933d88ec 100644 --- a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj +++ b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj @@ -742,6 +742,9 @@ 52D945A72DC0A70700DE8220 /* SplunkWebViewProxy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SplunkWebViewProxy.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52D945AF2DC0A70700DE8220 /* SplunkWebViewProxyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SplunkWebViewProxyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BA3376982DDD042300F45723 /* NetworkInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfo.swift; sourceTree = ""; }; + BA33769A2DDD2AD800F45723 /* NetworkInfoRemoteConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfoRemoteConfiguration.swift; sourceTree = ""; }; + BA33769B2DDD2ADC00F45723 /* NetworkInfoConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfoConfiguration.swift; sourceTree = ""; }; + BA33769C2DDD2AE100F45723 /* NetworkInfo+Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkInfo+Module.swift"; sourceTree = ""; }; BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesSpanProcessor.swift; sourceTree = ""; }; BA4C08512DC83AF0008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesLogRecordProcessor.swift; sourceTree = ""; }; BA7A63BB2DB8196800A44570 /* MutableAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableAttributesTests.swift; sourceTree = ""; }; @@ -2348,6 +2351,7 @@ isa = PBXGroup; children = ( BA3376982DDD042300F45723 /* NetworkInfo.swift */, + BA3376992DDD2A9900F45723 /* Module */, ); path = SplunkNetworkInfo; sourceTree = ""; @@ -2359,6 +2363,16 @@ path = SplunkNetworkInfoTests; sourceTree = ""; }; + BA3376992DDD2A9900F45723 /* Module */ = { + isa = PBXGroup; + children = ( + BA33769C2DDD2AE100F45723 /* NetworkInfo+Module.swift */, + BA33769B2DDD2ADC00F45723 /* NetworkInfoConfiguration.swift */, + BA33769A2DDD2AD800F45723 /* NetworkInfoRemoteConfiguration.swift */, + ); + path = Module; + sourceTree = ""; + }; BA7A63BA2DB818AD00A44570 /* Model */ = { isa = PBXGroup; children = ( diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift new file mode 100644 index 00000000..67646c68 --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift @@ -0,0 +1,51 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + + +public struct NetworkInfoData: ModuleEventData {} + +public struct NetworkInfoMetadata: ModuleEventMetadata { + public var timestamp = Date() + public var eventName: String = "network.change" +} + +extension NetworkInfo: Module { + + // MARK: - Module types + + public typealias Configuration = NetworkInfoConfiguration + public typealias RemoteConfiguration = NetworkInfoRemoteConfiguration + + public typealias EventMetadata = NetworkInfoMetadata + public typealias EventData = NetworkInfoData + + + // MARK: - Module methods + + public func install(with configuration: (any ModuleConfiguration)?, remoteConfiguration: (any RemoteModuleConfiguration)?) { + startDetection() + } + + + // MARK: - Type transparency helpers + + public func deleteData(for metadata: any ModuleEventMetadata) {} + public func onPublish(data: @escaping (NetworkInfoMetadata, NetworkInfoData) -> Void) {} +} diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift new file mode 100644 index 00000000..30fe9067 --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift @@ -0,0 +1,22 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + +/// NetworkInfo module configuration, minimal configuration for module conformance. +public struct NetworkInfoConfiguration: ModuleConfiguration {} diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift new file mode 100644 index 00000000..ef1f7001 --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift @@ -0,0 +1,54 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + +/// NetworkInfo remote configuration. +public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { + + // MARK: - Internal decoding + + struct NetworkInfo: Decodable { + let enabled: Bool + } + + struct MRUMRoot: Decodable { + let appStart: NetworkInfo + } + + struct Configuration: Decodable { + let mrum: MRUMRoot + } + + struct Root: Decodable { + let configuration: Configuration + } + + + // MARK: - Public + + public var enabled: Bool + + public init?(from data: Data) { + guard let root = try? JSONDecoder().decode(Root.self, from: data) else { + return nil + } + + enabled = root.configuration.mrum.networkInfo.enabled + } +} diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index 09608970..bca8d164 100644 --- a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -25,7 +25,7 @@ public class NetworkInfo { case cellular case wiredEthernet case other - case unavailable + case lost } public static let shared = NetworkMonitor() @@ -35,7 +35,7 @@ public class NetworkInfo { private let tracer: Tracer public private(set) var isConnected: Bool = false - public private(set) var connectionType: ConnectionType = .unavailable + public private(set) var connectionType: ConnectionType = .lost public private(set) var isVPNActive: Bool = false public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? @@ -71,7 +71,7 @@ public class NetworkInfo { } else if path.usesInterfaceType(.wiredEthernet) { return .wiredEthernet } else if path.status == .unsatisfied { - return .unavailable + return .lost } else { return .other } @@ -80,7 +80,7 @@ public class NetworkInfo { private func sendNetworkChangeSpan() { let span = tracer.spanBuilder(spanName: "network.change").startSpan() span.setAttribute(key: "network.connected", value: isConnected) - span.setAttribute(key: "network.type", value: connectionType.rawValue) + span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) span.setAttribute(key: "network.vpn", value: isVPNActive) span.end() } From a36e67a03096543fa6bc5867fd32aec116700a73 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 26 May 2025 19:42:45 -0700 Subject: [PATCH 03/22] DEMRUM-773 Network Info module support --- Package.swift | 16 + .../SplunkAgent.xcodeproj/project.pbxproj | 519 +++++++++++++++++- .../SplunkNetworkInfoTests.swift | 27 + 3 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift diff --git a/Package.swift b/Package.swift index 883224cd..ea55c185 100644 --- a/Package.swift +++ b/Package.swift @@ -79,6 +79,22 @@ let package = Package( path: "SplunkNetwork/Tests" ), + // MARK: Splunk Network Info + + .target( + name: "SplunkNetworkInfo", + dependencies: [ + "SplunkCommon", + "SplunkOpenTelemetry" + ], + path: "SplunkNetworkInfo/Sources" + ), + .testTarget( + name: "SplunkNetworkInfoTests", + dependencies: ["SplunkNetworkInfo"], + path: "SplunkNetworkInfo/Tests" + ), + // MARK: Splunk Common .target( diff --git a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj index 933d88ec..2291ccdd 100644 --- a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj +++ b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj @@ -177,6 +177,7 @@ 52D945C42DC0A71200DE8220 /* SplunkWebView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D945612DC0A62C00DE8220 /* SplunkWebView.framework */; }; 52D945C52DC0A73700DE8220 /* SplunkCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9640842D60FD04009A2E7F /* SplunkCommon.framework */; platformFilters = (ios, maccatalyst, tvos, ); }; 52D945C92DC0A7F500DE8220 /* CiscoLogger in Frameworks */ = {isa = PBXBuildFile; productRef = 52D945C82DC0A7F500DE8220 /* CiscoLogger */; }; + BA3376F82DE55DA500F45723 /* SplunkAgent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3384F2A22AC879E900512D79 /* SplunkAgent.framework */; }; BA4C084F2DC8398E008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */; }; BA4C08502DC8398E008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */; }; BA4C08522DC83AFD008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C08512DC83AF0008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift */; }; @@ -512,6 +513,13 @@ remoteGlobalIDString = 4B9640832D60FD04009A2E7F; remoteInfo = SplunkCommon; }; + BA3376F92DE55DA500F45723 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3384F2992AC879E900512D79 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3384F2A12AC879E900512D79; + remoteInfo = SplunkAgent; + }; E468962E2B21C85800727A6A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 3384F2992AC879E900512D79 /* Project object */; @@ -745,6 +753,8 @@ BA33769A2DDD2AD800F45723 /* NetworkInfoRemoteConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfoRemoteConfiguration.swift; sourceTree = ""; }; BA33769B2DDD2ADC00F45723 /* NetworkInfoConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInfoConfiguration.swift; sourceTree = ""; }; BA33769C2DDD2AE100F45723 /* NetworkInfo+Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkInfo+Module.swift"; sourceTree = ""; }; + BA3376D52DE55D2600F45723 /* SplunkNetworkInfo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SplunkNetworkInfo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BA3376F42DE55DA500F45723 /* SplunkNetworkInfoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SplunkNetworkInfoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesSpanProcessor.swift; sourceTree = ""; }; BA4C08512DC83AF0008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTLPGlobalAttributesLogRecordProcessor.swift; sourceTree = ""; }; BA7A63BB2DB8196800A44570 /* MutableAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableAttributesTests.swift; sourceTree = ""; }; @@ -887,6 +897,32 @@ E4FAEEB62B6A9F81008D4E6E /* RemoteConfiguration.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = RemoteConfiguration.json; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + BA3376DB2DE55D2600F45723 /* Exceptions for "SplunkNetworkInfo" folder in "SplunkNetworkInfo" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + publicHeaders = ( + SplunkNetworkInfo.h, + ); + target = BA3376D42DE55D2600F45723 /* SplunkNetworkInfo */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + BA3376DB2DE55D2600F45723 /* Exceptions for "SplunkNetworkInfo" folder in "SplunkNetworkInfo" target */, + ); + path = SplunkNetworkInfo; + sourceTree = ""; + }; + BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = SplunkNetworkInfoTests; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 3384F29F2AC879E900512D79 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -1103,6 +1139,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BA3376D22DE55D2600F45723 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BA3376F12DE55DA500F45723 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BA3376F82DE55DA500F45723 /* SplunkAgent.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; E46896262B21C85800727A6A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1290,6 +1341,8 @@ E4E9747A2B1643EE00ACB469 /* Sources */, E46896332B21C8FF00727A6A /* Tests */, E4F2E4EC2B1721CB006EBA69 /* Tools */, + BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */, + BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */, 3384F2A32AC879E900512D79 /* Products */, E45F8C952BC5881E007AC144 /* Packages */, 526521F42CB8937800DB3BB9 /* Frameworks */, @@ -1323,6 +1376,8 @@ 52D945692DC0A62D00DE8220 /* SplunkWebViewTests.xctest */, 52D945A72DC0A70700DE8220 /* SplunkWebViewProxy.framework */, 52D945AF2DC0A70700DE8220 /* SplunkWebViewProxyTests.xctest */, + BA3376D52DE55D2600F45723 /* SplunkNetworkInfo.framework */, + BA3376F42DE55DA500F45723 /* SplunkNetworkInfoTests.xctest */, ); name = Products; sourceTree = ""; @@ -3118,6 +3173,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BA3376D02DE55D2600F45723 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -3623,6 +3685,52 @@ productReference = 52D945AF2DC0A70700DE8220 /* SplunkWebViewProxyTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + BA3376D42DE55D2600F45723 /* SplunkNetworkInfo */ = { + isa = PBXNativeTarget; + buildConfigurationList = BA3376DC2DE55D2600F45723 /* Build configuration list for PBXNativeTarget "SplunkNetworkInfo" */; + buildPhases = ( + BA3376D02DE55D2600F45723 /* Headers */, + BA3376D12DE55D2600F45723 /* Sources */, + BA3376D22DE55D2600F45723 /* Frameworks */, + BA3376D32DE55D2600F45723 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */, + ); + name = SplunkNetworkInfo; + packageProductDependencies = ( + ); + productName = SplunkNetworkInfo; + productReference = BA3376D52DE55D2600F45723 /* SplunkNetworkInfo.framework */; + productType = "com.apple.product-type.framework"; + }; + BA3376F32DE55DA500F45723 /* SplunkNetworkInfoTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BA3376FB2DE55DA500F45723 /* Build configuration list for PBXNativeTarget "SplunkNetworkInfoTests" */; + buildPhases = ( + BA3376F02DE55DA500F45723 /* Sources */, + BA3376F12DE55DA500F45723 /* Frameworks */, + BA3376F22DE55DA500F45723 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BA3376FA2DE55DA500F45723 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */, + ); + name = SplunkNetworkInfoTests; + packageProductDependencies = ( + ); + productName = SplunkNetworkInfoTests; + productReference = BA3376F42DE55DA500F45723 /* SplunkNetworkInfoTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; E46896282B21C85800727A6A /* SplunkAgentTests */ = { isa = PBXNativeTarget; buildConfigurationList = E46896322B21C85800727A6A /* Build configuration list for PBXNativeTarget "SplunkAgentTests" */; @@ -3649,7 +3757,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1630; + LastSwiftUpdateCheck = 1620; LastUpgradeCheck = 1630; TargetAttributes = { 3384F2A12AC879E900512D79 = { @@ -3721,6 +3829,12 @@ 52D945AE2DC0A70700DE8220 = { CreatedOnToolsVersion = 16.3; }; + BA3376D42DE55D2600F45723 = { + CreatedOnToolsVersion = 16.2; + }; + BA3376F32DE55DA500F45723 = { + CreatedOnToolsVersion = 16.2; + }; E46896282B21C85800727A6A = { CreatedOnToolsVersion = 15.0.1; }; @@ -3768,6 +3882,8 @@ 52D945682DC0A62D00DE8220 /* SplunkWebViewTests */, 52D945A62DC0A70700DE8220 /* SplunkWebViewProxy */, 52D945AE2DC0A70700DE8220 /* SplunkWebViewProxyTests */, + BA3376D42DE55D2600F45723 /* SplunkNetworkInfo */, + BA3376F32DE55DA500F45723 /* SplunkNetworkInfoTests */, ); }; /* End PBXProject section */ @@ -3936,6 +4052,20 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BA3376D32DE55D2600F45723 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BA3376F22DE55DA500F45723 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E46896272B21C85800727A6A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4328,6 +4458,20 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BA3376D12DE55D2600F45723 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BA3376F02DE55DA500F45723 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E46896252B21C85800727A6A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4551,6 +4695,11 @@ target = 4B9640832D60FD04009A2E7F /* SplunkCommon */; targetProxy = 52D945CC2DC0A84D00DE8220 /* PBXContainerItemProxy */; }; + BA3376FA2DE55DA500F45723 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3384F2A12AC879E900512D79 /* SplunkAgent */; + targetProxy = BA3376F92DE55DA500F45723 /* PBXContainerItemProxy */; + }; E468962F2B21C85800727A6A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3384F2A12AC879E900512D79 /* SplunkAgent */; @@ -9336,6 +9485,348 @@ }; name = "Release-staticlib"; }; + BA3376DD2DE55D2600F45723 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BA3376DE2DE55D2600F45723 /* Debug-mh_dylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-mh_dylib"; + }; + BA3376DF2DE55D2600F45723 /* Debug-staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-staticlib"; + }; + BA3376E02DE55D2600F45723 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BA3376E12DE55D2600F45723 /* Release-mh_dylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-mh_dylib"; + }; + BA3376E22DE55D2600F45723 /* Release-staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfo; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-staticlib"; + }; + BA3376FC2DE55DA500F45723 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BA3376FD2DE55DA500F45723 /* Debug-mh_dylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-mh_dylib"; + }; + BA3376FE2DE55DA500F45723 /* Debug-staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-staticlib"; + }; + BA3376FF2DE55DA500F45723 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BA3377002DE55DA500F45723 /* Release-mh_dylib */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-mh_dylib"; + }; + BA3377012DE55DA500F45723 /* Release-staticlib */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 3GU8KX3K7W; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.splunk.SplunkNetworkInfoTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-staticlib"; + }; E46896302B21C85800727A6A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 4B536BFF2B693BED004A6C7C /* Debug-mh_dylib.xcconfig */; @@ -9702,6 +10193,32 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + BA3376DC2DE55D2600F45723 /* Build configuration list for PBXNativeTarget "SplunkNetworkInfo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BA3376DD2DE55D2600F45723 /* Debug */, + BA3376DE2DE55D2600F45723 /* Debug-mh_dylib */, + BA3376DF2DE55D2600F45723 /* Debug-staticlib */, + BA3376E02DE55D2600F45723 /* Release */, + BA3376E12DE55D2600F45723 /* Release-mh_dylib */, + BA3376E22DE55D2600F45723 /* Release-staticlib */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BA3376FB2DE55DA500F45723 /* Build configuration list for PBXNativeTarget "SplunkNetworkInfoTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BA3376FC2DE55DA500F45723 /* Debug */, + BA3376FD2DE55DA500F45723 /* Debug-mh_dylib */, + BA3376FE2DE55DA500F45723 /* Debug-staticlib */, + BA3376FF2DE55DA500F45723 /* Release */, + BA3377002DE55DA500F45723 /* Release-mh_dylib */, + BA3377012DE55DA500F45723 /* Release-staticlib */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; E46896322B21C85800727A6A /* Build configuration list for PBXNativeTarget "SplunkAgentTests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift b/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift new file mode 100644 index 00000000..d7a14a1d --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift @@ -0,0 +1,27 @@ +// +/* +Copyright 2024 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +import Testing + +struct SplunkNetworkInfoTests { + + @Test func example() async throws { + // Write your test here and use APIs like `#expect(...)` to check expected conditions. + } + +} From 2f2bd1f9455fb84af9622105894c2534c0493355 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 26 May 2025 19:43:44 -0700 Subject: [PATCH 04/22] DEMRUM-773 Network Info module support --- .../SplunkNetworkInfo.md | 13 +++++++++ .../SplunkNetworkInfo/SplunkNetworkInfo.h | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md create mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md new file mode 100644 index 00000000..cf8bdccb --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md @@ -0,0 +1,13 @@ +# ``SplunkNetworkInfo`` + +Summary + +## Overview + +Text + +## Topics + +### Group + +- ``Symbol`` \ No newline at end of file diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h new file mode 100644 index 00000000..a6f5642b --- /dev/null +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h @@ -0,0 +1,29 @@ +// +/* +Copyright 2024 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#import + +//! Project version number for SplunkNetworkInfo. +FOUNDATION_EXPORT double SplunkNetworkInfoVersionNumber; + +//! Project version string for SplunkNetworkInfo. +FOUNDATION_EXPORT const unsigned char SplunkNetworkInfoVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + From eb2073f9686e7e376c74f5c778a6a6327f239408 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 26 May 2025 20:08:22 -0700 Subject: [PATCH 05/22] DEMRUM-773 Network Info module support --- .../SplunkAgent.xcodeproj/project.pbxproj | 19 +++++++++---------- .../Module/NetworkInfo+Module.swift | 0 .../Module/NetworkInfoConfiguration.swift | 0 .../NetworkInfoRemoteConfiguration.swift | 3 +-- .../SplunkNetworkInfo/NetworkInfo.swift | 12 ++++++++---- .../SplunkNetworkInfo.md | 0 .../SplunkNetworkInfo.h | 0 7 files changed, 18 insertions(+), 16 deletions(-) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift (100%) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift (100%) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift (95%) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/Sources/SplunkNetworkInfo/NetworkInfo.swift (91%) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/SplunkNetworkInfo.docc/SplunkNetworkInfo.md (100%) rename SplunkAgent/SplunkNetworkInfo/{ => SplunkNetworkInfo}/SplunkNetworkInfo.h (100%) diff --git a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj index 2291ccdd..0e1b66e2 100644 --- a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj +++ b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj @@ -916,11 +916,6 @@ path = SplunkNetworkInfo; sourceTree = ""; }; - BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = SplunkNetworkInfoTests; - sourceTree = ""; - }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1336,13 +1331,12 @@ 4B5A5BD62D5E4FBC009DA0D5 /* SplunkSlowFrameDetector */, 4B5A5BC32D5E4E33009DA0D5 /* SplunkCommon */, 4B5A5B932D5E4C79009DA0D5 /* SplunkNetwork */, + BA33771E2DE5606F00F45723 /* SplunkNetworkInfo */, BA3376932DDD020700F45723 /* SplunkNetworkInfo */, 4B536BF12B67FADC004A6C7C /* Configurations */, E4E9747A2B1643EE00ACB469 /* Sources */, E46896332B21C8FF00727A6A /* Tests */, E4F2E4EC2B1721CB006EBA69 /* Tools */, - BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */, - BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */, 3384F2A32AC879E900512D79 /* Products */, E45F8C952BC5881E007AC144 /* Packages */, 526521F42CB8937800DB3BB9 /* Frameworks */, @@ -2428,6 +2422,14 @@ path = Module; sourceTree = ""; }; + BA33771E2DE5606F00F45723 /* SplunkNetworkInfo */ = { + isa = PBXGroup; + children = ( + BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */, + ); + path = SplunkNetworkInfo; + sourceTree = ""; + }; BA7A63BA2DB818AD00A44570 /* Model */ = { isa = PBXGroup; children = ( @@ -3721,9 +3723,6 @@ dependencies = ( BA3376FA2DE55DA500F45723 /* PBXTargetDependency */, ); - fileSystemSynchronizedGroups = ( - BA3376F52DE55DA500F45723 /* SplunkNetworkInfoTests */, - ); name = SplunkNetworkInfoTests; packageProductDependencies = ( ); diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift similarity index 100% rename from SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift similarity index 100% rename from SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift similarity index 95% rename from SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift index ef1f7001..2f9c132e 100644 --- a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift @@ -16,7 +16,6 @@ limitations under the License. */ import Foundation -import SplunkCommon /// NetworkInfo remote configuration. public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { @@ -28,7 +27,7 @@ public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { } struct MRUMRoot: Decodable { - let appStart: NetworkInfo + let networkInfo: NetworkInfo } struct Configuration: Decodable { diff --git a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift similarity index 91% rename from SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index bca8d164..d32575e1 100644 --- a/SplunkAgent/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -17,7 +17,6 @@ limitations under the License. import Foundation import Network -import OpenTelemetryApi public class NetworkInfo { public enum ConnectionType: String { @@ -32,7 +31,7 @@ public class NetworkInfo { private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitorQueue") - private let tracer: Tracer + private var tracer: Tracer public private(set) var isConnected: Bool = false public private(set) var connectionType: ConnectionType = .lost @@ -40,8 +39,13 @@ public class NetworkInfo { public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? - private init(tracer: Tracer? = nil) { - self.tracer = tracer ?? OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkMonitor", instrumentationVersion: "1.0") + // MARK: - Initialization + + // Module conformance + public required init() {} + + public func startDetection() { + self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkMonitor", instrumentationVersion: "1.0") monitor.pathUpdateHandler = { [weak self] path in guard let self = self else { return } diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md similarity index 100% rename from SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h similarity index 100% rename from SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo.h rename to SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h From 5d32b2f32a3c12e04ff811f4ae07448680aeb636 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Tue, 27 May 2025 07:28:35 -0700 Subject: [PATCH 06/22] DEMRUM-773 Network Info module support --- .../SplunkAgent.xcodeproj/project.pbxproj | 36 +++++++++++++++++++ .../NetworkInfoRemoteConfiguration.swift | 1 + .../SplunkNetworkInfo/NetworkInfo.swift | 9 ++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj index 0e1b66e2..6601263e 100644 --- a/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj +++ b/SplunkAgent/SplunkAgent.xcodeproj/project.pbxproj @@ -178,6 +178,9 @@ 52D945C52DC0A73700DE8220 /* SplunkCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9640842D60FD04009A2E7F /* SplunkCommon.framework */; platformFilters = (ios, maccatalyst, tvos, ); }; 52D945C92DC0A7F500DE8220 /* CiscoLogger in Frameworks */ = {isa = PBXBuildFile; productRef = 52D945C82DC0A7F500DE8220 /* CiscoLogger */; }; BA3376F82DE55DA500F45723 /* SplunkAgent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3384F2A22AC879E900512D79 /* SplunkAgent.framework */; }; + BA33771F2DE5FFA400F45723 /* SplunkCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9640842D60FD04009A2E7F /* SplunkCommon.framework */; }; + BA3377202DE5FFA400F45723 /* SplunkCommon.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9640842D60FD04009A2E7F /* SplunkCommon.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + BA3377252DE6014900F45723 /* OpenTelemetryApi in Frameworks */ = {isa = PBXBuildFile; productRef = BA3377242DE6014900F45723 /* OpenTelemetryApi */; }; BA4C084F2DC8398E008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */; }; BA4C08502DC8398E008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C084E2DC83988008BFD5E /* OTLPGlobalAttributesSpanProcessor.swift */; }; BA4C08522DC83AFD008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4C08512DC83AF0008BFD5E /* OTLPGlobalAttributesLogRecordProcessor.swift */; }; @@ -520,6 +523,13 @@ remoteGlobalIDString = 3384F2A12AC879E900512D79; remoteInfo = SplunkAgent; }; + BA3377212DE5FFA400F45723 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3384F2992AC879E900512D79 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4B9640832D60FD04009A2E7F; + remoteInfo = SplunkCommon; + }; E468962E2B21C85800727A6A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 3384F2992AC879E900512D79 /* Project object */; @@ -568,6 +578,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + BA3377232DE5FFA400F45723 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + BA3377202DE5FFA400F45723 /* SplunkCommon.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -1138,6 +1159,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BA33771F2DE5FFA400F45723 /* SplunkCommon.framework in Frameworks */, + BA3377252DE6014900F45723 /* OpenTelemetryApi in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3695,16 +3718,19 @@ BA3376D12DE55D2600F45723 /* Sources */, BA3376D22DE55D2600F45723 /* Frameworks */, BA3376D32DE55D2600F45723 /* Resources */, + BA3377232DE5FFA400F45723 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + BA3377222DE5FFA400F45723 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( BA3376D62DE55D2600F45723 /* SplunkNetworkInfo */, ); name = SplunkNetworkInfo; packageProductDependencies = ( + BA3377242DE6014900F45723 /* OpenTelemetryApi */, ); productName = SplunkNetworkInfo; productReference = BA3376D52DE55D2600F45723 /* SplunkNetworkInfo.framework */; @@ -4699,6 +4725,11 @@ target = 3384F2A12AC879E900512D79 /* SplunkAgent */; targetProxy = BA3376F92DE55DA500F45723 /* PBXContainerItemProxy */; }; + BA3377222DE5FFA400F45723 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4B9640832D60FD04009A2E7F /* SplunkCommon */; + targetProxy = BA3377212DE5FFA400F45723 /* PBXContainerItemProxy */; + }; E468962F2B21C85800727A6A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3384F2A12AC879E900512D79 /* SplunkAgent */; @@ -10330,6 +10361,11 @@ package = 4B9642812D613B32009A2E7F /* XCRemoteSwiftPackageReference "smartlook-ios-sdk-private" */; productName = CiscoLogger; }; + BA3377242DE6014900F45723 /* OpenTelemetryApi */ = { + isa = XCSwiftPackageProductDependency; + package = 4B0F23872D79F2C000EA575A /* XCRemoteSwiftPackageReference "opentelemetry-swift" */; + productName = OpenTelemetryApi; + }; C791ADFA2DAE72D5002AAA2B /* OpenTelemetryProtocolExporter */ = { isa = XCSwiftPackageProductDependency; package = 4B0F23872D79F2C000EA575A /* XCRemoteSwiftPackageReference "opentelemetry-swift" */; diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift index 2f9c132e..0b1cbd79 100644 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift @@ -16,6 +16,7 @@ limitations under the License. */ import Foundation +import SplunkCommon /// NetworkInfo remote configuration. public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index d32575e1..a5d79a57 100644 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -17,6 +17,7 @@ limitations under the License. import Foundation import Network +import OpenTelemetryApi public class NetworkInfo { public enum ConnectionType: String { @@ -27,7 +28,7 @@ public class NetworkInfo { case lost } - public static let shared = NetworkMonitor() + public static let shared = NetworkInfo() private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitorQueue") @@ -42,11 +43,11 @@ public class NetworkInfo { // MARK: - Initialization // Module conformance - public required init() {} + public required init() { + self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkInfo", instrumentationVersion: "1.0") + } public func startDetection() { - self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkMonitor", instrumentationVersion: "1.0") - monitor.pathUpdateHandler = { [weak self] path in guard let self = self else { return } self.isConnected = path.status == .satisfied From 8a36b8f984acb5e1ec788d64ddac05758be918df Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 2 Jun 2025 16:32:36 -0700 Subject: [PATCH 07/22] DEMRUM-773 Move various files --- .../Module/NetworkInfo+Module.swift | 51 ---------- .../Module/NetworkInfoConfiguration.swift | 22 ----- .../NetworkInfoRemoteConfiguration.swift | 54 ----------- .../SplunkNetworkInfo/NetworkInfo.swift | 92 ------------------- .../SplunkNetworkInfo.md | 13 --- .../SplunkNetworkInfo/SplunkNetworkInfo.h | 29 ------ .../SplunkNetworkInfoTests.swift | 27 ------ 7 files changed, 288 deletions(-) delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md delete mode 100644 SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h delete mode 100644 SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift deleted file mode 100644 index 67646c68..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -/* -Copyright 2025 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import Foundation -import SplunkCommon - - -public struct NetworkInfoData: ModuleEventData {} - -public struct NetworkInfoMetadata: ModuleEventMetadata { - public var timestamp = Date() - public var eventName: String = "network.change" -} - -extension NetworkInfo: Module { - - // MARK: - Module types - - public typealias Configuration = NetworkInfoConfiguration - public typealias RemoteConfiguration = NetworkInfoRemoteConfiguration - - public typealias EventMetadata = NetworkInfoMetadata - public typealias EventData = NetworkInfoData - - - // MARK: - Module methods - - public func install(with configuration: (any ModuleConfiguration)?, remoteConfiguration: (any RemoteModuleConfiguration)?) { - startDetection() - } - - - // MARK: - Type transparency helpers - - public func deleteData(for metadata: any ModuleEventMetadata) {} - public func onPublish(data: @escaping (NetworkInfoMetadata, NetworkInfoData) -> Void) {} -} diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift deleted file mode 100644 index 30fe9067..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -/* -Copyright 2025 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import Foundation -import SplunkCommon - -/// NetworkInfo module configuration, minimal configuration for module conformance. -public struct NetworkInfoConfiguration: ModuleConfiguration {} diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift deleted file mode 100644 index 0b1cbd79..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -/* -Copyright 2025 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import Foundation -import SplunkCommon - -/// NetworkInfo remote configuration. -public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { - - // MARK: - Internal decoding - - struct NetworkInfo: Decodable { - let enabled: Bool - } - - struct MRUMRoot: Decodable { - let networkInfo: NetworkInfo - } - - struct Configuration: Decodable { - let mrum: MRUMRoot - } - - struct Root: Decodable { - let configuration: Configuration - } - - - // MARK: - Public - - public var enabled: Bool - - public init?(from data: Data) { - guard let root = try? JSONDecoder().decode(Root.self, from: data) else { - return nil - } - - enabled = root.configuration.mrum.networkInfo.enabled - } -} diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift deleted file mode 100644 index a5d79a57..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -/* -Copyright 2025 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import Foundation -import Network -import OpenTelemetryApi - -public class NetworkInfo { - public enum ConnectionType: String { - case wifi - case cellular - case wiredEthernet - case other - case lost - } - - public static let shared = NetworkInfo() - - private let monitor = NWPathMonitor() - private let queue = DispatchQueue(label: "NetworkMonitorQueue") - private var tracer: Tracer - - public private(set) var isConnected: Bool = false - public private(set) var connectionType: ConnectionType = .lost - public private(set) var isVPNActive: Bool = false - - public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? - - // MARK: - Initialization - - // Module conformance - public required init() { - self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkInfo", instrumentationVersion: "1.0") - } - - public func startDetection() { - monitor.pathUpdateHandler = { [weak self] path in - guard let self = self else { return } - self.isConnected = path.status == .satisfied - self.connectionType = self.getConnectionType(path) - self.isVPNActive = path.availableInterfaces.contains(where: { iface in - iface.type == .other && - (iface.name.lowercased().contains("utun") || - iface.name.lowercased().contains("ppp") || - iface.name.lowercased().contains("ipsec")) - }) - self.sendNetworkChangeSpan() - self.statusChangeHandler?(self.isConnected, self.connectionType, self.isVPNActive) - } - monitor.start(queue: queue) - // Send initial state span - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in - self?.sendNetworkChangeSpan() - } - } - - private func getConnectionType(_ path: NWPath) -> ConnectionType { - if path.usesInterfaceType(.wifi) { - return .wifi - } else if path.usesInterfaceType(.cellular) { - return .cellular - } else if path.usesInterfaceType(.wiredEthernet) { - return .wiredEthernet - } else if path.status == .unsatisfied { - return .lost - } else { - return .other - } - } - - private func sendNetworkChangeSpan() { - let span = tracer.spanBuilder(spanName: "network.change").startSpan() - span.setAttribute(key: "network.connected", value: isConnected) - span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) - span.setAttribute(key: "network.vpn", value: isVPNActive) - span.end() - } -} diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md deleted file mode 100644 index cf8bdccb..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.docc/SplunkNetworkInfo.md +++ /dev/null @@ -1,13 +0,0 @@ -# ``SplunkNetworkInfo`` - -Summary - -## Overview - -Text - -## Topics - -### Group - -- ``Symbol`` \ No newline at end of file diff --git a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h b/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h deleted file mode 100644 index a6f5642b..00000000 --- a/SplunkAgent/SplunkNetworkInfo/SplunkNetworkInfo/SplunkNetworkInfo.h +++ /dev/null @@ -1,29 +0,0 @@ -// -/* -Copyright 2024 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - - -#import - -//! Project version number for SplunkNetworkInfo. -FOUNDATION_EXPORT double SplunkNetworkInfoVersionNumber; - -//! Project version string for SplunkNetworkInfo. -FOUNDATION_EXPORT const unsigned char SplunkNetworkInfoVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift b/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift deleted file mode 100644 index d7a14a1d..00000000 --- a/SplunkAgent/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -/* -Copyright 2024 Splunk Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - - -import Testing - -struct SplunkNetworkInfoTests { - - @Test func example() async throws { - // Write your test here and use APIs like `#expect(...)` to check expected conditions. - } - -} From 1387c06b19711bf4b199e18fe2d7a4981a81c1b7 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 2 Jun 2025 16:33:33 -0700 Subject: [PATCH 08/22] DEMRUM-773 Move various files --- .../Module/NetworkInfo+Module.swift | 51 ++++++++++ .../Module/NetworkInfoConfiguration.swift | 22 +++++ .../NetworkInfoRemoteConfiguration.swift | 54 +++++++++++ .../SplunkNetworkInfo/NetworkInfo.swift | 92 +++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift create mode 100644 SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift create mode 100644 SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift create mode 100644 SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift new file mode 100644 index 00000000..67646c68 --- /dev/null +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift @@ -0,0 +1,51 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + + +public struct NetworkInfoData: ModuleEventData {} + +public struct NetworkInfoMetadata: ModuleEventMetadata { + public var timestamp = Date() + public var eventName: String = "network.change" +} + +extension NetworkInfo: Module { + + // MARK: - Module types + + public typealias Configuration = NetworkInfoConfiguration + public typealias RemoteConfiguration = NetworkInfoRemoteConfiguration + + public typealias EventMetadata = NetworkInfoMetadata + public typealias EventData = NetworkInfoData + + + // MARK: - Module methods + + public func install(with configuration: (any ModuleConfiguration)?, remoteConfiguration: (any RemoteModuleConfiguration)?) { + startDetection() + } + + + // MARK: - Type transparency helpers + + public func deleteData(for metadata: any ModuleEventMetadata) {} + public func onPublish(data: @escaping (NetworkInfoMetadata, NetworkInfoData) -> Void) {} +} diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift new file mode 100644 index 00000000..30fe9067 --- /dev/null +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift @@ -0,0 +1,22 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + +/// NetworkInfo module configuration, minimal configuration for module conformance. +public struct NetworkInfoConfiguration: ModuleConfiguration {} diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift new file mode 100644 index 00000000..0b1cbd79 --- /dev/null +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift @@ -0,0 +1,54 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import SplunkCommon + +/// NetworkInfo remote configuration. +public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { + + // MARK: - Internal decoding + + struct NetworkInfo: Decodable { + let enabled: Bool + } + + struct MRUMRoot: Decodable { + let networkInfo: NetworkInfo + } + + struct Configuration: Decodable { + let mrum: MRUMRoot + } + + struct Root: Decodable { + let configuration: Configuration + } + + + // MARK: - Public + + public var enabled: Bool + + public init?(from data: Data) { + guard let root = try? JSONDecoder().decode(Root.self, from: data) else { + return nil + } + + enabled = root.configuration.mrum.networkInfo.enabled + } +} diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift new file mode 100644 index 00000000..a5d79a57 --- /dev/null +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -0,0 +1,92 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import Foundation +import Network +import OpenTelemetryApi + +public class NetworkInfo { + public enum ConnectionType: String { + case wifi + case cellular + case wiredEthernet + case other + case lost + } + + public static let shared = NetworkInfo() + + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "NetworkMonitorQueue") + private var tracer: Tracer + + public private(set) var isConnected: Bool = false + public private(set) var connectionType: ConnectionType = .lost + public private(set) var isVPNActive: Bool = false + + public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? + + // MARK: - Initialization + + // Module conformance + public required init() { + self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkInfo", instrumentationVersion: "1.0") + } + + public func startDetection() { + monitor.pathUpdateHandler = { [weak self] path in + guard let self = self else { return } + self.isConnected = path.status == .satisfied + self.connectionType = self.getConnectionType(path) + self.isVPNActive = path.availableInterfaces.contains(where: { iface in + iface.type == .other && + (iface.name.lowercased().contains("utun") || + iface.name.lowercased().contains("ppp") || + iface.name.lowercased().contains("ipsec")) + }) + self.sendNetworkChangeSpan() + self.statusChangeHandler?(self.isConnected, self.connectionType, self.isVPNActive) + } + monitor.start(queue: queue) + // Send initial state span + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in + self?.sendNetworkChangeSpan() + } + } + + private func getConnectionType(_ path: NWPath) -> ConnectionType { + if path.usesInterfaceType(.wifi) { + return .wifi + } else if path.usesInterfaceType(.cellular) { + return .cellular + } else if path.usesInterfaceType(.wiredEthernet) { + return .wiredEthernet + } else if path.status == .unsatisfied { + return .lost + } else { + return .other + } + } + + private func sendNetworkChangeSpan() { + let span = tracer.spanBuilder(spanName: "network.change").startSpan() + span.setAttribute(key: "network.connected", value: isConnected) + span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) + span.setAttribute(key: "network.vpn", value: isVPNActive) + span.end() + } +} From 877915baf639f0a2245ae0121c3ec56f1b9edd7d Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 2 Jun 2025 16:43:16 -0700 Subject: [PATCH 09/22] DEMRUM-773 Connect Module to default pool --- Package.swift | 1 + .../SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Package.swift b/Package.swift index 089d4c90..6958b768 100644 --- a/Package.swift +++ b/Package.swift @@ -57,6 +57,7 @@ func generateMainTargets() -> [Target] { "SplunkCrashReports", "SplunkSessionReplayProxy", "SplunkNetwork", + "SplunkNetworkInfo", "SplunkSlowFrameDetector", "SplunkOpenTelemetry", "SplunkAppStart", diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift index b90d3e59..f84032f8 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift @@ -25,6 +25,10 @@ internal import SplunkCommon internal import SplunkNetwork #endif +#if canImport(SplunkNetworkInfo) + internal import SplunkNetworkInfo +#endif + #if canImport(CiscoSessionReplay) internal import CiscoSessionReplay internal import SplunkSessionReplayProxy From 6277e4e3e4f7d8f623259281d395c46ea0265b4f Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:37:34 -0700 Subject: [PATCH 10/22] DEMRUM-773 Connect Module to SharedAppState --- .../Agent/Modules/SplunkRum+Modules.swift | 9 ++++++++ .../SplunkNetworkInfo/NetworkInfo.swift | 23 ++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift index 71685d3b..fc110292 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift @@ -19,6 +19,7 @@ import Foundation internal import CiscoSessionReplay internal import SplunkAppStart internal import SplunkNetwork +internal import SplunkNetworkInfo #if canImport(SplunkCrashReports) internal import SplunkCrashReports @@ -53,6 +54,7 @@ extension SplunkRum { customizeSessionReplay() customizeNetwork() customizeAppStart() + customizeNetworkInfo() customizeWebViewInstrumentation() } @@ -113,6 +115,13 @@ extension SplunkRum { appStartModule?.sharedState = sharedState } + /// Configure NetworkInfo module + private func customizeNetworkInfo() { + let networkInfoModule = modulesManager?.module(ofType: SplunkNetworkInfo.NetworkInfo.self) + + networkInfoModule?.sharedState = sharedState + } + /// Configure WebView intrumentation module private func customizeWebViewInstrumentation() { // Get WebViewInstrumentation module, set its sharedState diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index a5d79a57..93fd5978 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -17,6 +17,7 @@ limitations under the License. import Foundation import Network +import SplunkCommon import OpenTelemetryApi public class NetworkInfo { @@ -28,11 +29,13 @@ public class NetworkInfo { case lost } + /// An instance of the Agent shared state object, which is used to obtain agent's state, e.g. a session id. + public unowned var sharedState: AgentSharedState? + public static let shared = NetworkInfo() private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitorQueue") - private var tracer: Tracer public private(set) var isConnected: Bool = false public private(set) var connectionType: ConnectionType = .lost @@ -43,9 +46,7 @@ public class NetworkInfo { // MARK: - Initialization // Module conformance - public required init() { - self.tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "NetworkInfo", instrumentationVersion: "1.0") - } + public required init() { } public func startDetection() { monitor.pathUpdateHandler = { [weak self] path in @@ -83,10 +84,20 @@ public class NetworkInfo { } private func sendNetworkChangeSpan() { - let span = tracer.spanBuilder(spanName: "network.change").startSpan() + + let tracer = OpenTelemetry.instance + .tracerProvider + .get( + instrumentationName: "NetworkInfo", + instrumentationVersion: sharedState?.agentVersion + ) + + let span = tracer.spanBuilder(spanName: "network.change") + .setStartTime(time: Date()) + .startSpan() span.setAttribute(key: "network.connected", value: isConnected) span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) span.setAttribute(key: "network.vpn", value: isVPNActive) - span.end() + span.end(time: Date()) } } From 338e009444d123199985f1a6bad68c091099f42a Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:24:40 -0700 Subject: [PATCH 11/22] DEMRUM-773 Indicate VPN as a network.connection.type --- .../xcshareddata/swiftpm/Package.resolved | 11 +++++++- .../SplunkNetworkInfo/NetworkInfo.swift | 25 +++++++++---------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Applications/DevelApp/DevelApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Applications/DevelApp/DevelApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c22a803d..a96d6b64 100644 --- a/Applications/DevelApp/DevelApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Applications/DevelApp/DevelApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "6bba8ac9b558d13b8127757ab7f2d63f10ad35b1cd565e9caf8ec84f565f9c0f", + "originHash" : "114ce2756ea96e50892e5a52e50134984f6a901303a049f0857cffd1b7047be9", "pins" : [ { "identity" : "grpc-swift", @@ -28,6 +28,15 @@ "version" : "0.5.2" } }, + { + "identity" : "plcrashreporter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/microsoft/plcrashreporter", + "state" : { + "revision" : "8c61e5e38e9f737dd68512ed1ea5ab081244ad65", + "version" : "1.12.0" + } + }, { "identity" : "swift-algorithms", "kind" : "remoteSourceControl", diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index 93fd5978..d8fd8362 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -25,6 +25,7 @@ public class NetworkInfo { case wifi case cellular case wiredEthernet + case vpn case other case lost } @@ -39,9 +40,8 @@ public class NetworkInfo { public private(set) var isConnected: Bool = false public private(set) var connectionType: ConnectionType = .lost - public private(set) var isVPNActive: Bool = false - public var statusChangeHandler: ((Bool, ConnectionType, Bool) -> Void)? + public var statusChangeHandler: ((Bool, ConnectionType) -> Void)? // MARK: - Initialization @@ -53,14 +53,8 @@ public class NetworkInfo { guard let self = self else { return } self.isConnected = path.status == .satisfied self.connectionType = self.getConnectionType(path) - self.isVPNActive = path.availableInterfaces.contains(where: { iface in - iface.type == .other && - (iface.name.lowercased().contains("utun") || - iface.name.lowercased().contains("ppp") || - iface.name.lowercased().contains("ipsec")) - }) self.sendNetworkChangeSpan() - self.statusChangeHandler?(self.isConnected, self.connectionType, self.isVPNActive) + self.statusChangeHandler?(self.isConnected, self.connectionType) } monitor.start(queue: queue) // Send initial state span @@ -79,12 +73,18 @@ public class NetworkInfo { } else if path.status == .unsatisfied { return .lost } else { - return .other + // Check for VPN + let isVPN = path.availableInterfaces.contains(where: { iface in + iface.type == .other && + (iface.name.lowercased().contains("utun") || + iface.name.lowercased().contains("ppp") || + iface.name.lowercased().contains("ipsec")) + }) + return isVPN ? .vpn : .other } } private func sendNetworkChangeSpan() { - let tracer = OpenTelemetry.instance .tracerProvider .get( @@ -95,9 +95,8 @@ public class NetworkInfo { let span = tracer.spanBuilder(spanName: "network.change") .setStartTime(time: Date()) .startSpan() - span.setAttribute(key: "network.connected", value: isConnected) + span.setAttribute(key: "network.status", value: isConnected) span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) - span.setAttribute(key: "network.vpn", value: isVPNActive) span.end(time: Date()) } } From b77a0f6356ee035e2f0361dc49305aa785ebcec6 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:43:51 -0700 Subject: [PATCH 12/22] DEMRUM-773 Return network.status as string rather than boolean --- SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index d8fd8362..00751c41 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -95,7 +95,7 @@ public class NetworkInfo { let span = tracer.spanBuilder(spanName: "network.change") .setStartTime(time: Date()) .startSpan() - span.setAttribute(key: "network.status", value: isConnected) + span.setAttribute(key: "network.status", value: isConnected ? "available" : "lost") span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) span.end(time: Date()) } From 7ef0816b2ba7a832829073d0f8004c8f13b1cde1 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:59:06 -0700 Subject: [PATCH 13/22] DEMRUM-773 Remove status change span at app start --- SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index 00751c41..72842050 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -57,10 +57,6 @@ public class NetworkInfo { self.statusChangeHandler?(self.isConnected, self.connectionType) } monitor.start(queue: queue) - // Send initial state span - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in - self?.sendNetworkChangeSpan() - } } private func getConnectionType(_ path: NWPath) -> ConnectionType { From 3206086b4cab535a0bae088b2ddf7b33e2424778 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 13:01:26 -0700 Subject: [PATCH 14/22] DEMRUM-773 Update package.swift re review comment --- Package.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 6958b768..7ec57cfe 100644 --- a/Package.swift +++ b/Package.swift @@ -102,7 +102,8 @@ func generateMainTargets() -> [Target] { path: "SplunkNetwork/Tests" ), - // MARK: Splunk Network Info + + // MARK: - Splunk Network Info .target( name: "SplunkNetworkInfo", @@ -118,7 +119,8 @@ func generateMainTargets() -> [Target] { path: "SplunkNetworkInfo/Tests" ), - // MARK: Splunk Common + + // MARK: - Splunk Common .target( name: "SplunkCommon", From 886d212b54c9913e8e3426c70781e17391ea6d87 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:43:05 -0700 Subject: [PATCH 15/22] DEMRUM-773 Only signal change when relevant paramters change --- .../Sources/SplunkNetworkInfo/NetworkInfo.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift index 72842050..30b7f6f8 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift @@ -41,6 +41,10 @@ public class NetworkInfo { public private(set) var isConnected: Bool = false public private(set) var connectionType: ConnectionType = .lost + // Track previous state + private var previousStatus: String? + private var previousType: ConnectionType? + public var statusChangeHandler: ((Bool, ConnectionType) -> Void)? // MARK: - Initialization @@ -53,7 +57,18 @@ public class NetworkInfo { guard let self = self else { return } self.isConnected = path.status == .satisfied self.connectionType = self.getConnectionType(path) - self.sendNetworkChangeSpan() + + let currentStatus = self.isConnected ? "available" : "lost" + + if let prevStatus = self.previousStatus, + let prevType = self.previousType, + (currentStatus != prevStatus || self.connectionType != prevType) { + self.sendNetworkChangeSpan() + } + + self.previousStatus = currentStatus + self.previousType = self.connectionType + self.statusChangeHandler?(self.isConnected, self.connectionType) } monitor.start(queue: queue) From 8f1d9fc21c90ae52eb8c9ec3128e3d27cb6d9197 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:43:25 -0700 Subject: [PATCH 16/22] DEMRUM-773 Unit Test --- .../SplunkNetworkInfoTests.swift | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift diff --git a/SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift b/SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift new file mode 100644 index 00000000..bbd7d3d6 --- /dev/null +++ b/SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift @@ -0,0 +1,44 @@ +// +/* +Copyright 2025 Splunk Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import XCTest +import Network +@testable import SplunkNetworkInfo + +final class NetworkInfoTests: XCTestCase { + func testInitialState() { + let networkInfo = NetworkInfo() + XCTAssertFalse(networkInfo.isConnected) + XCTAssertEqual(networkInfo.connectionType, .lost) + } + + func testNetworkMonitoring() { + let networkInfo = NetworkInfo() + let exp = expectation(description: "Network status change") + + // Set up handler to verify network changes + networkInfo.statusChangeHandler = { isConnected, type in + // Just verify we got a callback + exp.fulfill() + } + + // Start monitoring + networkInfo.startDetection() + + wait(for: [exp], timeout: 5.0) + } +} From ecdccec546c304529281e62131d547eadf16c12b Mon Sep 17 00:00:00 2001 From: Aditi Sharma Date: Tue, 17 Jun 2025 16:50:49 -0700 Subject: [PATCH 17/22] Added module config. Add subtype for connection. Renamed to Network Monitor --- .../Modules/Pool/DefaultModulesPool.swift | 8 +- .../Agent/Modules/SplunkRum+Modules.swift | 12 +-- .../Module/NetworkMonitor+Module.swift | 23 +++-- .../Module/NetworkMonitorConfiguration.swift | 18 +++- .../NetworkMonitorRemoteConfiguration.swift | 10 +- .../SplunkNetworkMonitor/NetworkMonitor.swift | 95 ++++++++++++++++--- .../SplunkNetworkMonitorTests.swift | 18 ++-- 7 files changed, 136 insertions(+), 48 deletions(-) rename SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift => SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift (58%) rename SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift => SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorConfiguration.swift (51%) rename SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift => SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorRemoteConfiguration.swift (80%) rename SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift => SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift (51%) rename SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift => SplunkNetworkMonitor/Tests/SplunkNetworkMonitorTests/SplunkNetworkMonitorTests.swift (70%) diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift index f84032f8..5c3feb73 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift @@ -25,8 +25,8 @@ internal import SplunkCommon internal import SplunkNetwork #endif -#if canImport(SplunkNetworkInfo) - internal import SplunkNetworkInfo +#if canImport(SplunkNetworkMonitor) + internal import SplunkNetworkMonitor #endif #if canImport(CiscoSessionReplay) @@ -75,8 +75,8 @@ class DefaultModulesPool: AgentModulesPool { #endif // Network Info - #if canImport(SplunkNetworkInfo) - knownModules.append(NetworkInfo.self) + #if canImport(SplunkNetworkMonitor) + knownModules.append(NetworkMonitor.self) #endif // Slow Frame Detector diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift index fc110292..b1359c27 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift @@ -19,7 +19,7 @@ import Foundation internal import CiscoSessionReplay internal import SplunkAppStart internal import SplunkNetwork -internal import SplunkNetworkInfo +internal import SplunkNetworkMonitor #if canImport(SplunkCrashReports) internal import SplunkCrashReports @@ -54,7 +54,7 @@ extension SplunkRum { customizeSessionReplay() customizeNetwork() customizeAppStart() - customizeNetworkInfo() + customizeNetworkMonitor() customizeWebViewInstrumentation() } @@ -115,11 +115,11 @@ extension SplunkRum { appStartModule?.sharedState = sharedState } - /// Configure NetworkInfo module - private func customizeNetworkInfo() { - let networkInfoModule = modulesManager?.module(ofType: SplunkNetworkInfo.NetworkInfo.self) + /// Configure NetworkMonitor module + private func customizeNetworkMonitor() { + let networkMonitorModule = modulesManager?.module(ofType: SplunkNetworkMonitor.NetworkMonitor.self) - networkInfoModule?.sharedState = sharedState + networkMonitorModule?.sharedState = sharedState } /// Configure WebView intrumentation module diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift similarity index 58% rename from SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift rename to SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift index 67646c68..b50e2f44 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfo+Module.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift @@ -19,33 +19,38 @@ import Foundation import SplunkCommon -public struct NetworkInfoData: ModuleEventData {} +public struct NetworkMonitorData: ModuleEventData {} -public struct NetworkInfoMetadata: ModuleEventMetadata { +public struct NetworkMonitorMetadata: ModuleEventMetadata { public var timestamp = Date() public var eventName: String = "network.change" } -extension NetworkInfo: Module { +extension NetworkMonitor: Module { // MARK: - Module types - public typealias Configuration = NetworkInfoConfiguration - public typealias RemoteConfiguration = NetworkInfoRemoteConfiguration + public typealias Configuration = NetworkMonitorConfiguration + public typealias RemoteConfiguration = NetworkMonitorRemoteConfiguration - public typealias EventMetadata = NetworkInfoMetadata - public typealias EventData = NetworkInfoData + public typealias EventMetadata = NetworkMonitorMetadata + public typealias EventData = NetworkMonitorData // MARK: - Module methods public func install(with configuration: (any ModuleConfiguration)?, remoteConfiguration: (any RemoteModuleConfiguration)?) { - startDetection() + let config = configuration as? Configuration + + // Start the network monitor if it's enabled or if no configuration is provided. + if config?.isEnabled ?? true { + startDetection() + } } // MARK: - Type transparency helpers public func deleteData(for metadata: any ModuleEventMetadata) {} - public func onPublish(data: @escaping (NetworkInfoMetadata, NetworkInfoData) -> Void) {} + public func onPublish(data: @escaping (NetworkMonitorMetadata, NetworkMonitorData) -> Void) {} } diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorConfiguration.swift similarity index 51% rename from SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift rename to SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorConfiguration.swift index 30fe9067..3df452b1 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoConfiguration.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorConfiguration.swift @@ -18,5 +18,19 @@ limitations under the License. import Foundation import SplunkCommon -/// NetworkInfo module configuration, minimal configuration for module conformance. -public struct NetworkInfoConfiguration: ModuleConfiguration {} +/// NetworkMonitor module configuration, minimal configuration for module conformance. +public struct NetworkMonitorConfiguration: ModuleConfiguration { + + // MARK: - Module management + + /// Indicates whether the Module is enabled. Default value is `true`. + public var isEnabled: Bool = true + + /// Initializes new module configuration with preconfigured values. + /// + /// - Parameters: + /// - isEnabled: A `Boolean` value sets whether the module is enabled. + public init(isEnabled: Bool) { + self.isEnabled = isEnabled + } +} diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorRemoteConfiguration.swift similarity index 80% rename from SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift rename to SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorRemoteConfiguration.swift index 0b1cbd79..87dbd482 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/Module/NetworkInfoRemoteConfiguration.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitorRemoteConfiguration.swift @@ -18,17 +18,17 @@ limitations under the License. import Foundation import SplunkCommon -/// NetworkInfo remote configuration. -public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { +/// NetworkMonitor remote configuration. +public struct NetworkMonitorRemoteConfiguration: RemoteModuleConfiguration { // MARK: - Internal decoding - struct NetworkInfo: Decodable { + struct NetworkMonitor: Decodable { let enabled: Bool } struct MRUMRoot: Decodable { - let networkInfo: NetworkInfo + let NetworkMonitor: NetworkMonitor } struct Configuration: Decodable { @@ -49,6 +49,6 @@ public struct NetworkInfoRemoteConfiguration: RemoteModuleConfiguration { return nil } - enabled = root.configuration.mrum.networkInfo.enabled + enabled = root.configuration.mrum.NetworkMonitor.enabled } } diff --git a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift similarity index 51% rename from SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift rename to SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift index 30b7f6f8..14f11a86 100644 --- a/SplunkNetworkInfo/Sources/SplunkNetworkInfo/NetworkInfo.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift @@ -15,31 +15,35 @@ See the License for the specific language governing permissions and limitations under the License. */ +import CoreTelephony import Foundation import Network -import SplunkCommon import OpenTelemetryApi +import SplunkCommon -public class NetworkInfo { +public class NetworkMonitor { public enum ConnectionType: String { case wifi case cellular case wiredEthernet case vpn case other - case lost + case unavailable } /// An instance of the Agent shared state object, which is used to obtain agent's state, e.g. a session id. public unowned var sharedState: AgentSharedState? - public static let shared = NetworkInfo() + public static let shared = NetworkMonitor() private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitorQueue") + private let telephonyInfo = CTTelephonyNetworkInfo() + public private(set) var currentRadioAccessTechnology: String? + public private(set) var isConnected: Bool = false - public private(set) var connectionType: ConnectionType = .lost + public private(set) var connectionType: ConnectionType = .unavailable // Track previous state private var previousStatus: String? @@ -50,7 +54,7 @@ public class NetworkInfo { // MARK: - Initialization // Module conformance - public required init() { } + public required init() {} public func startDetection() { monitor.pathUpdateHandler = { [weak self] path in @@ -62,16 +66,32 @@ public class NetworkInfo { if let prevStatus = self.previousStatus, let prevType = self.previousType, - (currentStatus != prevStatus || self.connectionType != prevType) { + currentStatus != prevStatus || self.connectionType != prevType { self.sendNetworkChangeSpan() } - self.previousStatus = currentStatus self.previousType = self.connectionType self.statusChangeHandler?(self.isConnected, self.connectionType) } monitor.start(queue: queue) + + // Radio Access Technologies detection (connection subtype in Otel) + NotificationCenter.default.addObserver( + self, + selector: #selector(radioAccessChanged), + name: .CTServiceRadioAccessTechnologyDidChange, + object: nil + ) + + // Initial fetch of radio access technologies + updateRadioAccessTechnologies() + } + + public func stopDetection() { + monitor.cancel() + monitor.pathUpdateHandler = nil + NotificationCenter.default.removeObserver(self, name: .CTServiceRadioAccessTechnologyDidChange, object: nil) } private func getConnectionType(_ path: NWPath) -> ConnectionType { @@ -82,7 +102,7 @@ public class NetworkInfo { } else if path.usesInterfaceType(.wiredEthernet) { return .wiredEthernet } else if path.status == .unsatisfied { - return .lost + return .unavailable } else { // Check for VPN let isVPN = path.availableInterfaces.contains(where: { iface in @@ -99,15 +119,64 @@ public class NetworkInfo { let tracer = OpenTelemetry.instance .tracerProvider .get( - instrumentationName: "NetworkInfo", + instrumentationName: "NetworkMonitor", instrumentationVersion: sharedState?.agentVersion ) + // Getting current timestamp to set zero length span as start and end time + let timestamp = Date() let span = tracer.spanBuilder(spanName: "network.change") - .setStartTime(time: Date()) - .startSpan() + .setStartTime(time: timestamp) + .startSpan() span.setAttribute(key: "network.status", value: isConnected ? "available" : "lost") span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) - span.end(time: Date()) + if currentRadioAccessTechnology != "Unknown" { + span.setAttribute(key: "network.connection.subtype", value: currentRadioAccessTechnology!) + } + span.end(time: timestamp) + } + + private func updateRadioAccessTechnologies() { + currentRadioAccessTechnology = getCurrentRadioAccessTechnology() + } + + @objc private func radioAccessChanged() { + updateRadioAccessTechnologies() + sendNetworkChangeSpan() + } + + private func getCurrentRadioAccessTechnology() -> String? { + // Pick the first available radio access technology + let radioTechnology = telephonyInfo.serviceCurrentRadioAccessTechnology?.values.first ?? "Unknown" + switch radioTechnology { + case CTRadioAccessTechnologyGPRS: + return "GPRS (2G)" + case CTRadioAccessTechnologyEdge: + return "EDGE (2G)" + case CTRadioAccessTechnologyWCDMA: + return "WCDMA (3G)" + case CTRadioAccessTechnologyHSDPA: + return "HSDPA (3G)" + case CTRadioAccessTechnologyHSUPA: + return "HSUPA (3G)" + case CTRadioAccessTechnologyCDMA1x: + return "CDMA1x (2G)" + case CTRadioAccessTechnologyCDMAEVDORev0: + return "CDMA EV-DO Rev. 0 (3G)" + case CTRadioAccessTechnologyCDMAEVDORevA: + return "CDMA EV-DO Rev. A (3G)" + case CTRadioAccessTechnologyCDMAEVDORevB: + return "CDMA EV-DO Rev. B (3G)" + case CTRadioAccessTechnologyeHRPD: + return "eHRPD (3G)" + case CTRadioAccessTechnologyLTE: + return "LTE (4G)" + case CTRadioAccessTechnologyNRNSA: + return "NRNSA (5G Non-Standalone)" + case CTRadioAccessTechnologyNR: + return "NR (5G Standalone)" + default: + return "Unknown" + } } } diff --git a/SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift b/SplunkNetworkMonitor/Tests/SplunkNetworkMonitorTests/SplunkNetworkMonitorTests.swift similarity index 70% rename from SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift rename to SplunkNetworkMonitor/Tests/SplunkNetworkMonitorTests/SplunkNetworkMonitorTests.swift index bbd7d3d6..0c481687 100644 --- a/SplunkNetworkInfo/Tests/SplunkNetworkInfoTests/SplunkNetworkInfoTests.swift +++ b/SplunkNetworkMonitor/Tests/SplunkNetworkMonitorTests/SplunkNetworkMonitorTests.swift @@ -15,29 +15,29 @@ See the License for the specific language governing permissions and limitations under the License. */ -import XCTest import Network -@testable import SplunkNetworkInfo +@testable import SplunkNetworkMonitor +import XCTest -final class NetworkInfoTests: XCTestCase { +final class NetworkMonitorTests: XCTestCase { func testInitialState() { - let networkInfo = NetworkInfo() - XCTAssertFalse(networkInfo.isConnected) - XCTAssertEqual(networkInfo.connectionType, .lost) + let NetworkMonitor = NetworkMonitor() + XCTAssertFalse(NetworkMonitor.isConnected) + XCTAssertEqual(NetworkMonitor.connectionType, .lost) } func testNetworkMonitoring() { - let networkInfo = NetworkInfo() + let NetworkMonitor = NetworkMonitor() let exp = expectation(description: "Network status change") // Set up handler to verify network changes - networkInfo.statusChangeHandler = { isConnected, type in + NetworkMonitor.statusChangeHandler = { isConnected, type in // Just verify we got a callback exp.fulfill() } // Start monitoring - networkInfo.startDetection() + NetworkMonitor.startDetection() wait(for: [exp], timeout: 5.0) } From 8426037fba1471b426b375a0d6bd32d4f6fd7b19 Mon Sep 17 00:00:00 2001 From: Aditi Sharma Date: Tue, 17 Jun 2025 17:35:58 -0700 Subject: [PATCH 18/22] Updated comments --- Package.swift | 2 +- .../SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 141e64ed..c3318ff6 100644 --- a/Package.swift +++ b/Package.swift @@ -128,7 +128,7 @@ func generateMainTargets() -> [Target] { ), - // MARK: - Splunk Network Info + // MARK: - Splunk Network Monitor .target( name: "SplunkNetworkMonitor", diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift index 4bad6ade..efa621af 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/Pool/DefaultModulesPool.swift @@ -83,7 +83,7 @@ class DefaultModulesPool: AgentModulesPool { knownModules.append(NetworkInstrumentation.self) #endif - // Network Info + // Network Monitor #if canImport(SplunkNetworkMonitor) knownModules.append(NetworkMonitor.self) #endif From 138965f9356f0371513eb4ad008eaaf9168717b1 Mon Sep 17 00:00:00 2001 From: Aditi Sharma Date: Tue, 17 Jun 2025 17:42:46 -0700 Subject: [PATCH 19/22] Resolved merge conflicts in files --- .../SplunkAgent/Agent/Modules/SplunkRum+Modules.swift | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift index e476c3b8..c707c0ef 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift @@ -56,12 +56,9 @@ extension SplunkRum { customizeNavigation() customizeNetwork() customizeAppStart() -<<<<<<< HEAD customizeNetworkMonitor() - customizeWebViewInstrumentation() -======= customizeWebView() ->>>>>>> feature/next-gen + } /// Perform operations specific to the SessionReplay module. @@ -154,7 +151,6 @@ extension SplunkRum { appStartModule?.sharedState = sharedState } -<<<<<<< HEAD /// Configure NetworkMonitor module private func customizeNetworkMonitor() { let networkMonitorModule = modulesManager?.module(ofType: SplunkNetworkMonitor.NetworkMonitor.self) @@ -162,12 +158,8 @@ extension SplunkRum { networkMonitorModule?.sharedState = sharedState } - /// Configure WebView intrumentation module - private func customizeWebViewInstrumentation() { -======= /// Configure WebView Instrumentation module with shared state. private func customizeWebView() { ->>>>>>> feature/next-gen // Get WebViewInstrumentation module, set its sharedState let moduleType = SplunkWebView.WebViewInstrumentationInternal.self From 4261cdbfb2e2be29398685bc627eb87e09df1456 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Tue, 17 Jun 2025 17:43:39 -0700 Subject: [PATCH 20/22] DEMRUM-773: Update package.swift --- Package.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Package.swift b/Package.swift index 7ec57cfe..118d88bb 100644 --- a/Package.swift +++ b/Package.swift @@ -57,7 +57,7 @@ func generateMainTargets() -> [Target] { "SplunkCrashReports", "SplunkSessionReplayProxy", "SplunkNetwork", - "SplunkNetworkInfo", + "SplunkNetworkMonitor", "SplunkSlowFrameDetector", "SplunkOpenTelemetry", "SplunkAppStart", @@ -103,20 +103,20 @@ func generateMainTargets() -> [Target] { ), - // MARK: - Splunk Network Info - + // MARK: - Splunk Network Monitor + .target( - name: "SplunkNetworkInfo", + name: "SplunkNetworkMonitor", dependencies: [ "SplunkCommon", "SplunkOpenTelemetry" ], - path: "SplunkNetworkInfo/Sources" + path: "SplunkNetworkMonitor/Sources" ), .testTarget( - name: "SplunkNetworkInfoTests", - dependencies: ["SplunkNetworkInfo"], - path: "SplunkNetworkInfo/Tests" + name: "SplunkNetworkMonitorTests", + dependencies: ["SplunkNetworkMonitor"], + path: "SplunkNetworkMonitor/Tests" ), From 21b0ec1d7641a7b5596d089ff566baebcfa68e29 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Thu, 26 Jun 2025 17:18:00 -0700 Subject: [PATCH 21/22] DEMRUM-773: Updated per review comments --- Package.swift | 8 ++--- .../Agent/Modules/SplunkRum+Modules.swift | 4 --- .../Module/NetworkMonitor+Module.swift | 1 - .../SplunkNetworkMonitor/NetworkMonitor.swift | 31 +++++++++++++------ 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Package.swift b/Package.swift index 4518bd7d..091d8527 100644 --- a/Package.swift +++ b/Package.swift @@ -135,7 +135,7 @@ func generateMainTargets() -> [Target] { name: "SplunkNetworkMonitor", dependencies: [ "SplunkCommon", - "SplunkOpenTelemetry" + .product(name: "OpenTelemetryApi", package: "opentelemetry-swift") ], path: "SplunkNetworkMonitor/Sources" ), @@ -144,10 +144,10 @@ func generateMainTargets() -> [Target] { dependencies: ["SplunkNetworkMonitor"], path: "SplunkNetworkMonitor/Tests" ), - - + + // MARK: - Splunk Common - + .target( name: "SplunkCommon", path: "SplunkCommon/Sources" diff --git a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift index 24c3befb..b2b14efb 100644 --- a/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift +++ b/SplunkAgent/Sources/SplunkAgent/Agent/Modules/SplunkRum+Modules.swift @@ -57,13 +57,9 @@ extension SplunkRum { customizeNavigation() customizeNetwork() customizeAppStart() -<<<<<<< feature/DEMRUM-773-Network-Info-Module customizeNetworkMonitor() -======= customizeCustomTracking() ->>>>>>> feature/next-gen customizeWebView() - } /// Perform operations specific to the SessionReplay module. diff --git a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift index b50e2f44..a77f3e23 100644 --- a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/Module/NetworkMonitor+Module.swift @@ -18,7 +18,6 @@ limitations under the License. import Foundation import SplunkCommon - public struct NetworkMonitorData: ModuleEventData {} public struct NetworkMonitorMetadata: ModuleEventMetadata { diff --git a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift index 14f11a86..b9f6733a 100644 --- a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift @@ -22,6 +22,10 @@ import OpenTelemetryApi import SplunkCommon public class NetworkMonitor { + + + // MARK: - Public + public enum ConnectionType: String { case wifi case cellular @@ -36,26 +40,35 @@ public class NetworkMonitor { public static let shared = NetworkMonitor() + public var statusChangeHandler: ((Bool, ConnectionType) -> Void)? + + + // MARK: - Private + private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitorQueue") + private var previousStatus: String? + private var previousType: ConnectionType? private let telephonyInfo = CTTelephonyNetworkInfo() - public private(set) var currentRadioAccessTechnology: String? + + // MARK: - Nested + + public private(set) var currentRadioAccessTechnology: String? public private(set) var isConnected: Bool = false public private(set) var connectionType: ConnectionType = .unavailable - // Track previous state - private var previousStatus: String? - private var previousType: ConnectionType? - - public var statusChangeHandler: ((Bool, ConnectionType) -> Void)? // MARK: - Initialization // Module conformance public required init() {} + deinit { + stopDetection() + } + public func startDetection() { monitor.pathUpdateHandler = { [weak self] path in guard let self = self else { return } @@ -130,7 +143,7 @@ public class NetworkMonitor { .startSpan() span.setAttribute(key: "network.status", value: isConnected ? "available" : "lost") span.setAttribute(key: "network.connection.type", value: connectionType.rawValue) - if currentRadioAccessTechnology != "Unknown" { + if currentRadioAccessTechnology != nil { span.setAttribute(key: "network.connection.subtype", value: currentRadioAccessTechnology!) } span.end(time: timestamp) @@ -147,7 +160,7 @@ public class NetworkMonitor { private func getCurrentRadioAccessTechnology() -> String? { // Pick the first available radio access technology - let radioTechnology = telephonyInfo.serviceCurrentRadioAccessTechnology?.values.first ?? "Unknown" + let radioTechnology = telephonyInfo.serviceCurrentRadioAccessTechnology?.values.first ?? nil switch radioTechnology { case CTRadioAccessTechnologyGPRS: return "GPRS (2G)" @@ -176,7 +189,7 @@ public class NetworkMonitor { case CTRadioAccessTechnologyNR: return "NR (5G Standalone)" default: - return "Unknown" + return nil } } } From 201ea0cca8f4168236e9070d51078dd77053f127 Mon Sep 17 00:00:00 2001 From: SMickelsn <122052675+SMickelsn@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:41:48 -0700 Subject: [PATCH 22/22] DEMRUM-773: Updated per review comments --- Package.swift | 3 ++- .../Sources/SplunkNetworkMonitor/NetworkMonitor.swift | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index d3b544ca..7b25ffc4 100644 --- a/Package.swift +++ b/Package.swift @@ -136,7 +136,8 @@ func generateMainTargets() -> [Target] { name: "SplunkNetworkMonitor", dependencies: [ "SplunkCommon", - .product(name: "OpenTelemetryApi", package: "opentelemetry-swift") + .product(name: "OpenTelemetryApi", package: "opentelemetry-swift"), + resolveDependency("logger") ], path: "SplunkNetworkMonitor/Sources" ), diff --git a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift index b9f6733a..c130cbdb 100644 --- a/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift +++ b/SplunkNetworkMonitor/Sources/SplunkNetworkMonitor/NetworkMonitor.swift @@ -81,11 +81,10 @@ public class NetworkMonitor { let prevType = self.previousType, currentStatus != prevStatus || self.connectionType != prevType { self.sendNetworkChangeSpan() + self.statusChangeHandler?(self.isConnected, self.connectionType) } self.previousStatus = currentStatus self.previousType = self.connectionType - - self.statusChangeHandler?(self.isConnected, self.connectionType) } monitor.start(queue: queue)