Skip to content

Commit 286d31a

Browse files
Hongyan JiangGitHub Enterprise
authored andcommitted
Suspend beacon flushing (on low battery and/or cellular network) becomes configurable to apps
1 parent 4e34124 commit 286d31a

File tree

9 files changed

+192
-9
lines changed

9 files changed

+192
-9
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Fix unit test cases that failed in command line execution
66
- Fix unit test cases that failed in Xcode 15
77
- Change beacon id from 128 bit UUID to 64 bit hex string
8+
- Suspend beacon flushing (on low battery and/or cellular network) becomes configurable
89

910
## 1.6.5
1011
- Add crash to mobile feature list and send to Instana backend

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ To install the iOS agent, use Swift Package Manager (via Xcode) or CocoaPods.
3030

3131
1. Open Xcode.
3232
2. Open your Xcode project.
33-
2. Select menu File -> Add Package Dependencies...
34-
3. In the window that pops up, enter repository https://github.com/instana/iOSAgent to top right edit field "Search or Enter Package URL".
33+
2. Select menu **`File`** -> **`Add Package Dependencies...`**
34+
3. In the window that pops up, enter the repository https://github.com/instana/iOSAgent in the **Search or Enter Package URL** field. Then, select **`iosagent`** from the search result and click **`Add Package`** button.
3535

3636
#### CocoaPods
3737

Sources/InstanaAgent/Beacons/Reporter.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ public class Reporter {
1414
internal var sendFirstBeacon = true // first beacon is sent all by itself, not in a batch
1515
private var slowSendStartTime: Date?
1616
private var inSlowModeBeforeFlush = false
17-
private var lastFlushStartTime: Double?
18-
private var flusher: BeaconFlusher?
17+
internal var lastFlushStartTime: Double?
18+
internal var flusher: BeaconFlusher?
1919
internal var send: BeaconFlusher.Sender?
2020
private let rateLimiter: ReporterRateLimiter
2121
private let batterySafeForNetworking: () -> Bool

Sources/InstanaAgent/Configuration/InstanaConfiguraton.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,17 @@ class InstanaConfiguration {
7575
var isValid: Bool { !key.isEmpty && !reportingURL.absoluteString.isEmpty }
7676

7777
required init(reportingURL: URL, key: String, httpCaptureConfig: HTTPCaptureConfig,
78-
enableCrashReporting: Bool, slowSendInterval: Instana.Types.Seconds,
78+
enableCrashReporting: Bool, suspendReporting: Set<SuspendReporting>? = nil,
79+
slowSendInterval: Instana.Types.Seconds,
7980
usiRefreshTimeIntervalInHrs: Double) {
8081
self.reportingURL = reportingURL
8182
self.key = key
8283
self.httpCaptureConfig = httpCaptureConfig
83-
suspendReporting = SuspendReporting.defaults
8484
monitorTypes = MonitorTypes.current
8585
if enableCrashReporting {
8686
monitorTypes.insert(.crash)
8787
}
88+
self.suspendReporting = suspendReporting ?? SuspendReporting.defaults
8889
self.slowSendInterval = slowSendInterval
8990
self.usiRefreshTimeIntervalInHrs = usiRefreshTimeIntervalInHrs
9091
reporterSendDebounce = Defaults.reporterSendDebounce
@@ -98,11 +99,15 @@ class InstanaConfiguration {
9899
}
99100

100101
static func `default`(key: String, reportingURL: URL, httpCaptureConfig: HTTPCaptureConfig = .automatic,
101-
enableCrashReporting: Bool, slowSendInterval: Instana.Types.Seconds = 0.0,
102+
enableCrashReporting: Bool,
103+
suspendReporting: Set<SuspendReporting>? = nil,
104+
slowSendInterval: Instana.Types.Seconds = 0.0,
102105
usiRefreshTimeIntervalInHrs: Double = defaultUsiRefreshTimeIntervalInHrs)
103106
-> InstanaConfiguration {
104107
self.init(reportingURL: reportingURL, key: key, httpCaptureConfig: httpCaptureConfig,
105-
enableCrashReporting: enableCrashReporting, slowSendInterval: slowSendInterval,
108+
enableCrashReporting: enableCrashReporting,
109+
suspendReporting: suspendReporting,
110+
slowSendInterval: slowSendInterval,
106111
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs)
107112
}
108113
}

Sources/InstanaAgent/Instana.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,24 @@ import Foundation
8484
var httpCaptureConfig = HTTPCaptureConfig.automatic
8585
var collectionEnabled = true
8686
var enableCrashReporting = false
87+
var suspendReporting = InstanaConfiguration.SuspendReporting.defaults
8788
var slowSendInterval = 0.0
8889
var usiRefreshTimeIntervalInHrs = defaultUsiRefreshTimeIntervalInHrs
8990
if let options = options {
9091
httpCaptureConfig = options.httpCaptureConfig
9192
collectionEnabled = options.collectionEnabled
9293
enableCrashReporting = options.enableCrashReporting
9394

95+
let suspendReportingOnLowBattery = options.suspendReportingOnLowBattery
96+
let suspendReportingOnCellular = options.suspendReportingOnCellular
97+
suspendReporting = []
98+
if suspendReportingOnLowBattery {
99+
suspendReporting.insert(InstanaConfiguration.SuspendReporting.lowBattery)
100+
}
101+
if suspendReportingOnCellular {
102+
suspendReporting.insert(InstanaConfiguration.SuspendReporting.cellularConnection)
103+
}
104+
94105
let debounce = InstanaConfiguration.Defaults.reporterSendDebounce
95106
if options.slowSendInterval != 0.0,
96107
options.slowSendInterval < debounce || options.slowSendInterval > maxSlowSendInterval {
@@ -104,6 +115,7 @@ import Foundation
104115
let config = InstanaConfiguration.default(key: key, reportingURL: reportingURL,
105116
httpCaptureConfig: httpCaptureConfig,
106117
enableCrashReporting: enableCrashReporting,
118+
suspendReporting: suspendReporting,
107119
slowSendInterval: slowSendInterval,
108120
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs)
109121
let session = InstanaSession(configuration: config, propertyHandler: InstanaPropertyHandler(),

Sources/InstanaAgent/InstanaSetupOptions.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Foundation
88
public var httpCaptureConfig: HTTPCaptureConfig
99
public var collectionEnabled: Bool
1010
public var enableCrashReporting: Bool
11+
public var suspendReportingOnLowBattery: Bool
12+
public var suspendReportingOnCellular: Bool
1113
public var slowSendInterval: Instana.Types.Seconds
1214
public var usiRefreshTimeIntervalInHrs: Double
1315

@@ -22,11 +24,15 @@ import Foundation
2224
@objc public
2325
init(httpCaptureConfig: HTTPCaptureConfig = .automatic,
2426
collectionEnabled: Bool = true, enableCrashReporting: Bool = false,
27+
suspendReportingOnLowBattery: Bool = false,
28+
suspendReportingOnCellular: Bool = false,
2529
slowSendInterval: Instana.Types.Seconds = 0.0,
2630
usiRefreshTimeIntervalInHrs: Double = defaultUsiRefreshTimeIntervalInHrs) {
2731
self.httpCaptureConfig = httpCaptureConfig
2832
self.collectionEnabled = collectionEnabled
2933
self.enableCrashReporting = enableCrashReporting
34+
self.suspendReportingOnLowBattery = suspendReportingOnLowBattery
35+
self.suspendReportingOnCellular = suspendReportingOnCellular
3036
self.slowSendInterval = slowSendInterval
3137
self.usiRefreshTimeIntervalInHrs = usiRefreshTimeIntervalInHrs
3238
}

Tests/InstanaAgentTests/Beacons/ReporterTests.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ class ReporterTests: InstanaTestCase {
3636
AssertTrue(didSubmit)
3737
}
3838

39+
func test_collection_not_enabled() {
40+
// Given
41+
session = InstanaSession.mock(configuration: config)
42+
session.collectionEnabled = false
43+
44+
var didSubmit = false
45+
let submittedToQueue = expectation(description: "Submitted To Queue")
46+
let reporter = Reporter(session, batterySafeForNetworking: { true }, networkUtility: .wifi)
47+
48+
// When
49+
reporter.submit(AlertBeacon(alertType: .lowMemory)) {result in
50+
didSubmit = result
51+
submittedToQueue.fulfill()
52+
}
53+
wait(for: [submittedToQueue], timeout: 3.0)
54+
55+
// Then
56+
AssertFalse(didSubmit)
57+
}
58+
3959
func test_submit_rateLimit_two_NOT_exceeded() {
4060
// Given
4161
let submittedToQueue1 = expectation(description: "Submitted First Beacon")
@@ -1012,6 +1032,50 @@ class ReporterTests: InstanaTestCase {
10121032
AssertTrue(resultErrors.contains(instErr))
10131033
}
10141034

1035+
func test_canScheduleFlush_not_allowed_while_flushing() {
1036+
// Given
1037+
let reporter = Reporter(session, batterySafeForNetworking: { true }, networkUtility: .wifi)
1038+
let corebeacons = try! CoreBeaconFactory(session).map([HTTPBeacon.createMock()])
1039+
reporter.queue.add(corebeacons)
1040+
1041+
// When
1042+
reporter.scheduleFlush()
1043+
1044+
// Then
1045+
XCTAssertFalse(reporter.canScheduleFlush())
1046+
}
1047+
1048+
func test_canScheduleFlush_lastFlushStartTime_nil() {
1049+
// Given
1050+
let reporter = Reporter(session, batterySafeForNetworking: { true }, networkUtility: .wifi)
1051+
let corebeacons = try! CoreBeaconFactory(session).map([HTTPBeacon.createMock()])
1052+
reporter.queue.add(corebeacons)
1053+
1054+
// When
1055+
reporter.scheduleFlush()
1056+
1057+
reporter.lastFlushStartTime = nil // Force scheduling 2nd flushing
1058+
1059+
// Then
1060+
XCTAssertTrue(reporter.canScheduleFlush())
1061+
}
1062+
1063+
1064+
func test_canScheduleFlush_maxFlushingTimeExceeded() {
1065+
// Given
1066+
let reporter = Reporter(session, batterySafeForNetworking: { true }, networkUtility: .wifi)
1067+
let corebeacons = try! CoreBeaconFactory(session).map([HTTPBeacon.createMock()])
1068+
reporter.queue.add(corebeacons)
1069+
1070+
// When
1071+
reporter.scheduleFlush()
1072+
1073+
// last flush time is stale, force flushing
1074+
reporter.lastFlushStartTime = reporter.lastFlushStartTime! - (10.0+1) * 60
1075+
// Then
1076+
XCTAssertTrue(reporter.canScheduleFlush())
1077+
}
1078+
10151079
func test_submit_and_flush_shouldNotCause_RetainCycle() {
10161080
// Given
10171081
let waitForCompletion = expectation(description: "waitForSend")
@@ -1254,6 +1318,23 @@ class ReporterTests: InstanaTestCase {
12541318
}
12551319
AssertTrue(reporter.queue.isFull)
12561320
}
1321+
1322+
func test_runBackgroundFlush() {
1323+
// Given
1324+
let reporter = Reporter(session, batterySafeForNetworking: { true }, networkUtility: .wifi)
1325+
1326+
XCTAssertNil(reporter.flusher)
1327+
1328+
// When
1329+
let corebeacons = try! CoreBeaconFactory(session).map([HTTPBeacon.createMock()])
1330+
reporter.queue.add(corebeacons)
1331+
1332+
reporter.runBackgroundFlush()
1333+
Thread.sleep(forTimeInterval: 1)
1334+
1335+
// Then
1336+
XCTAssertNotNil(reporter.flusher)
1337+
}
12571338
}
12581339

12591340

Tests/InstanaAgentTests/InstanaTests.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class InstanaTests: InstanaTestCase {
4545
let options = InstanaSetupOptions(httpCaptureConfig: .automaticAndManual,
4646
collectionEnabled: false)
4747
options.enableCrashReporting = true
48+
options.suspendReportingOnLowBattery = true
49+
options.suspendReportingOnCellular = true
4850
options.slowSendInterval = 20.0
4951
let ret = Instana.setup(key: key, reportingURL: reportingURL, options: options)
5052

@@ -87,6 +89,15 @@ class InstanaTests: InstanaTestCase {
8789
AssertFalse(ret2)
8890
}
8991

92+
func test_setup_invalid_configuration_empty_key() {
93+
// Given
94+
let reportingURL = URL(string: "http://www.instana.com")!
95+
_ = Instana.setup(key: "", reportingURL: reportingURL, options: nil)
96+
97+
// Then
98+
AssertFalse(Instana.current!.session.configuration.isValid)
99+
}
100+
90101
func test_setup() {
91102
// Given
92103
let key = "KEY"
@@ -706,4 +717,70 @@ class InstanaTests: InstanaTestCase {
706717
// Covers negative case for empty current of Instana
707718
XCTAssertFalse(cancelled)
708719
}
720+
721+
@available(*, deprecated)
722+
func test_setup_deprecated1() {
723+
// Given
724+
let key = "KEY"
725+
let reportingURL = URL(string: "http://www.instana.com")!
726+
727+
Instana.setup(key: key, reportingURL: reportingURL)
728+
729+
// Then
730+
AssertEqualAndNotNil(Instana.key, key)
731+
AssertEqualAndNotNil(Instana.reportingURL, reportingURL)
732+
AssertTrue(Instana.collectionEnabled)
733+
AssertTrue(Instana.current!.session.collectionEnabled)
734+
AssertEqualAndNotNil(Instana.sessionID, Instana.current?.session.id.uuidString)
735+
736+
let config = Instana.current?.session.configuration
737+
XCTAssertNotNil(config)
738+
AssertEqualAndNotNil(config!.key, key)
739+
AssertEqualAndNotNil(config!.reportingURL, reportingURL)
740+
AssertEqualAndNotNil(config!.httpCaptureConfig, .automatic)
741+
AssertEqualAndNotNil(config!.slowSendInterval, 0.0)
742+
AssertEqualAndNotNil(config!.usiRefreshTimeIntervalInHrs, defaultUsiRefreshTimeIntervalInHrs)
743+
AssertFalse(config!.monitorTypes.contains(.crash))
744+
745+
let session = Instana.current?.session
746+
XCTAssertNotNil(session)
747+
AssertTrue(session!.collectionEnabled)
748+
}
749+
750+
@available(*, deprecated)
751+
func test_setup_deprecated2() {
752+
// Given
753+
let key = "KEY"
754+
let reportingURL = URL(string: "http://www.instana.com")!
755+
756+
Instana.setup(key: key, reportingURL: reportingURL,
757+
httpCaptureConfig: .manual,
758+
collectionEnabled: true,
759+
enableCrashReporting: true)
760+
761+
// Then
762+
AssertEqualAndNotNil(Instana.key, key)
763+
AssertEqualAndNotNil(Instana.reportingURL, reportingURL)
764+
AssertTrue(Instana.collectionEnabled)
765+
AssertTrue(Instana.current!.session.collectionEnabled)
766+
AssertEqualAndNotNil(Instana.sessionID, Instana.current?.session.id.uuidString)
767+
768+
let config = Instana.current?.session.configuration
769+
XCTAssertNotNil(config)
770+
AssertEqualAndNotNil(config!.key, key)
771+
AssertEqualAndNotNil(config!.reportingURL, reportingURL)
772+
AssertEqualAndNotNil(config!.httpCaptureConfig, .manual)
773+
AssertEqualAndNotNil(config!.slowSendInterval, 0.0)
774+
AssertEqualAndNotNil(config!.usiRefreshTimeIntervalInHrs, defaultUsiRefreshTimeIntervalInHrs)
775+
AssertTrue(config!.monitorTypes.contains(.crash))
776+
777+
let session = Instana.current?.session
778+
XCTAssertNotNil(session)
779+
AssertTrue(session!.collectionEnabled)
780+
}
781+
782+
func test_setup_not_called() {
783+
Instana.current = nil
784+
AssertFalse(Instana.collectionEnabled)
785+
}
709786
}

Tests/InstanaAgentTests/Monitors/HTTP/HTTPMarkerTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ class HTTPMarkerTests: InstanaTestCase {
6161
let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: ["KEY": "VALUE"])!
6262
let marker = HTTPMarker(url: url, method: "GET", trigger: .automatic, delegate: Delegate())
6363
let responseSize = HTTPMarker.Size(response)
64-
let excpectedHeaderSize = Instana.Types.Bytes(NSKeyedArchiver.archivedData(withRootObject: response.allHeaderFields).count)
64+
let excpectedHeaderSize = try! Instana.Types.Bytes(
65+
NSKeyedArchiver.archivedData(withRootObject: response.allHeaderFields, requiringSecureCoding: false).count)
6566

6667
// When
6768
marker.set(responseSize: responseSize)

0 commit comments

Comments
 (0)