Skip to content

Commit adfe129

Browse files
author
Ignacio Bonafonte
authored
Merge pull request #217 from bryce-b/network-info
added NetworkStatus package & injected it into network instrumentation
2 parents 921aacf + fa75387 commit adfe129

File tree

9 files changed

+359
-1
lines changed

9 files changed

+359
-1
lines changed

Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ let package = Package(
3838
.library(name: "libInMemoryExporter", type: .static, targets: ["InMemoryExporter"]),
3939
.library(name: "DatadogExporter", type: .dynamic, targets: ["DatadogExporter"]),
4040
.library(name: "libDatadogExporter", type: .static, targets: ["DatadogExporter"]),
41+
.library(name: "NetworkStatus", type: .static, targets: ["NetworkStatus"]),
42+
.library(name: "libNetworkStatus", type: .static, targets: ["NetworkStatus"]),
4143
.executable(name: "simpleExporter", targets: ["SimpleExporter"]),
4244
.executable(name: "loggingTracer", targets: ["LoggingTracer"]),
4345
],
@@ -48,6 +50,8 @@ let package = Package(
4850
.package(name: "grpc-swift", url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0"),
4951
.package(name: "swift-atomics", url: "https://github.com/apple/swift-atomics.git", from: "0.0.1"),
5052
.package(name: "swift-metrics", url: "https://github.com/apple/swift-metrics.git", from: "2.1.1"),
53+
.package(name: "Reachability", url: "https://github.com/ashleymills/Reachability.swift", .branch("master")),
54+
5155
],
5256
targets: [
5357
.target(name: "OpenTelemetryApi",
@@ -60,9 +64,13 @@ let package = Package(
6064
path: "Sources/Instrumentation/SDKResourceExtension",
6165
exclude: ["README.md"]),
6266
.target(name: "URLSessionInstrumentation",
63-
dependencies: ["OpenTelemetrySdk"],
67+
dependencies: ["OpenTelemetrySdk", "NetworkStatus"],
6468
path: "Sources/Instrumentation/URLSession",
6569
exclude: ["README.md"]),
70+
.target(name: "NetworkStatus",
71+
dependencies: ["Reachability"],
72+
path: "Sources/Instrumentation/NetworkStatus",
73+
linkerSettings: [.linkedFramework("CoreTelephony")]),
6674
.target(name: "SignPostIntegration",
6775
dependencies: ["OpenTelemetrySdk"],
6876
path: "Sources/Instrumentation/SignPostIntegration",
@@ -104,6 +112,9 @@ let package = Package(
104112
dependencies: ["OpenTelemetrySdk"],
105113
path: "Sources/Exporters/DatadogExporter",
106114
exclude: ["NOTICE", "README.md"]),
115+
.testTarget(name: "NetworkStatusTests",
116+
dependencies: ["NetworkStatus"],
117+
path: "Tests/InstrumentationTests/NetworkStatusTests"),
107118
.testTarget(name: "OpenTelemetryApiTests",
108119
dependencies: ["OpenTelemetryApi"],
109120
path: "Tests/OpenTelemetryApiTests"),
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import Foundation
7+
import Reachability
8+
9+
public class NetworkMonitor : NetworkMonitorProtocol {
10+
public private(set) var reachability :Reachability
11+
12+
public init() throws {
13+
reachability = try Reachability()
14+
try reachability.startNotifier()
15+
}
16+
17+
deinit {
18+
reachability.stopNotifier()
19+
}
20+
21+
public func getConnection() -> Connection {
22+
switch reachability.connection {
23+
case .wifi:
24+
return .wifi
25+
case .cellular:
26+
return .cellular
27+
case .unavailable:
28+
return .unavailable
29+
}
30+
}
31+
32+
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import Foundation
7+
8+
public enum Connection {
9+
case unavailable, wifi, cellular
10+
}
11+
public protocol NetworkMonitorProtocol {
12+
func getConnection() -> Connection;
13+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#if os(iOS)
7+
8+
import CoreTelephony
9+
import Foundation
10+
import Network
11+
import Reachability
12+
13+
public class NetworkStatus {
14+
public private(set) var networkInfo: CTTelephonyNetworkInfo
15+
public private(set) var networkMonitor: NetworkMonitorProtocol
16+
public convenience init() throws {
17+
self.init(with: try NetworkMonitor())
18+
}
19+
20+
public init(with monitor: NetworkMonitorProtocol, info: CTTelephonyNetworkInfo = CTTelephonyNetworkInfo()) {
21+
networkMonitor = monitor
22+
networkInfo = info
23+
}
24+
25+
public func status() -> (String, String?, CTCarrier?) {
26+
switch networkMonitor.getConnection() {
27+
case .wifi:
28+
return ("wifi", nil, nil)
29+
case .cellular:
30+
if #available(iOS 13.0, *) {
31+
if let serviceId = networkInfo.dataServiceIdentifier, let value = networkInfo.serviceCurrentRadioAccessTechnology?[serviceId] {
32+
return ("cell", simpleConnectionName(connectionType: value), networkInfo.serviceSubscriberCellularProviders?[networkInfo.dataServiceIdentifier!])
33+
}
34+
} else {
35+
if let radioType = networkInfo.currentRadioAccessTechnology {
36+
return ("cell", simpleConnectionName(connectionType: radioType), networkInfo.subscriberCellularProvider)
37+
}
38+
}
39+
return ("cell", "unknown", nil)
40+
case .unavailable:
41+
return ("unavailable", nil, nil)
42+
}
43+
}
44+
45+
func simpleConnectionName(connectionType: String) -> String {
46+
switch connectionType {
47+
case "CTRadioAccessTechnologyEdge":
48+
return "EDGE"
49+
case "CTRadioAccessTechnologyCDMA1x":
50+
return "CDMA"
51+
case "CTRadioAccessTechnologyGPRS":
52+
return "GPRS"
53+
case "CTRadioAccessTechnologyWCDMA":
54+
return "WCDMA"
55+
case "CTRadioAccessTechnologyHSDPA":
56+
return "HSDPA"
57+
case "CTRadioAccessTechnologyHSUPA":
58+
return "HSUPA"
59+
case "CTRadioAccessTechnologyCDMAEVDORev0":
60+
return "EVDO_0"
61+
case "CTRadioAccessTechnologyCDMAEVDORevA":
62+
return "EVDO_A"
63+
case "CTRadioAccessTechnologyCDMAEVDORevB":
64+
return "EVDO_B"
65+
case "CTRadioAccessTechnologyeHRPD":
66+
return "HRPD"
67+
case "CTRadioAccessTechnologyLTE":
68+
return "LTE"
69+
case "CTRadioAccessTechnologyNRNSA":
70+
return "NRNSA"
71+
case "CTRadioAccessTechnologyNR":
72+
return "NR"
73+
default:
74+
return "unknown"
75+
}
76+
}
77+
}
78+
79+
#endif // os(iOS)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#if os(iOS)
7+
import CoreTelephony
8+
import Foundation
9+
import Network
10+
import OpenTelemetryApi
11+
public class NetworkStatusInjector {
12+
private var netstat: NetworkStatus
13+
14+
public init(netstat: NetworkStatus) {
15+
self.netstat = netstat
16+
}
17+
18+
public func inject(span: Span) {
19+
let (type, subtype, carrier) = netstat.status()
20+
span.setAttribute(key: "net.host.connection.type", value: AttributeValue.string(type))
21+
22+
if let subtype: String = subtype {
23+
span.setAttribute(key: "net.host.connection.subtype", value: AttributeValue.string(subtype))
24+
}
25+
26+
if let carrierInfo: CTCarrier = carrier {
27+
if let carrierName = carrierInfo.carrierName {
28+
span.setAttribute(key: "net.host.carrier.name", value: AttributeValue.string(carrierName))
29+
}
30+
31+
if let isoCountryCode = carrierInfo.isoCountryCode {
32+
span.setAttribute(key: "net.host.carrier.icc", value: AttributeValue.string(isoCountryCode))
33+
}
34+
35+
if let mobileCountryCode = carrierInfo.mobileCountryCode {
36+
span.setAttribute(key: "net.host.carrier.mcc", value: AttributeValue.string(mobileCountryCode))
37+
}
38+
39+
if let mobileNetworkCode = carrierInfo.mobileNetworkCode {
40+
span.setAttribute(key: "net.host.carrier.mnc", value: AttributeValue.string(mobileNetworkCode))
41+
}
42+
}
43+
}
44+
}
45+
#endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#if os(iOS)
7+
import Foundation
8+
import CoreTelephony
9+
10+
public protocol NetworkStatusProtocol {
11+
var networkMonitor : NetworkMonitorProtocol { get }
12+
func getStatus() -> (String, CTCarrier?)
13+
}
14+
#endif

Sources/Instrumentation/URLSession/URLSessionLogger.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import Foundation
77
import OpenTelemetryApi
88
import OpenTelemetrySdk
99

10+
#if os(iOS)
11+
import NetworkStatus
12+
#endif //os(iOS)
13+
1014
class URLSessionLogger {
1115
static var runningSpans = [String: Span]()
1216
static var runningSpansQueue = DispatchQueue(label: "io.opentelemetry.URLSessionLogger")
@@ -61,6 +65,13 @@ class URLSessionLogger {
6165
returnRequest = instrumentedRequest(for: request, span: span, instrumentation: instrumentation)
6266
}
6367

68+
#if os(iOS)
69+
if let injector = self.netstatInjector {
70+
injector.inject(span: span)
71+
}
72+
#endif
73+
74+
6475
instrumentation.configuration.createdRequest?(returnRequest ?? request, span)
6576

6677
return returnRequest ?? request

0 commit comments

Comments
 (0)