Skip to content

Commit

Permalink
Support hybrid Agent Id and version if iOSAgent is invoked by flutter…
Browse files Browse the repository at this point in the history
…-agent or react-native-agent
  • Loading branch information
Hongyan Jiang authored and GitHub Enterprise committed Jan 19, 2024
1 parent 987936f commit d79dce2
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 17 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Add more exceptionType processing to crash beacon
- Display crash terminationReason as meta data rather than error message
- Add Objective-C target ObjectiveCAppExample to InstanaAgentExample
- Support hybrid agent id and version (if invoked by flutter-agent/react-native-agent)

## 1.6.7
- Add more raw crash payload info to stackTrace
Expand Down
11 changes: 11 additions & 0 deletions Sources/InstanaAgent/Beacons/CoreBeacon/CoreBeacon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,17 @@ struct CoreBeacon: Codable {
func isCrashPayloadField(fieldKey: String) -> Bool {
return fieldKey == "st" || fieldKey == "ast"
}

// If invoked by flutter-agent(f) or react-native-agent(r),
// put calling agent's id and version after iOSAgent version
static func getInstanaAgentVersion(hybridAgentId: String?, hybridAgentVersion: String?) -> String {
let iOSAgentVersion = InstanaSystemUtils.agentVersion
guard let hybridAgentId = hybridAgentId, !hybridAgentId.isEmpty,
let hybridAgentVersion = hybridAgentVersion, !hybridAgentVersion.isEmpty else {
return iOSAgentVersion
}
return "\(iOSAgentVersion):\(hybridAgentId):\(hybridAgentVersion)"
}
}

extension CoreBeacon: Hashable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class CoreBeaconFactory {
var cbeacon = CoreBeacon.createDefault(viewName: beacon.viewName, key: conf.key,
timestamp: beacon.timestamp,
sid: session.id, usi: session.usi,
id: beacon.id, mobileFeatures: mobileFeatures)
id: beacon.id, mobileFeatures: mobileFeatures,
hybridAgentId: conf.hybridAgentId,
hybridAgentVersion: conf.hybridAgentVersion)
cbeacon.append(properties)
switch beacon {
case let item as HTTPBeacon:
Expand Down Expand Up @@ -185,6 +187,8 @@ extension CoreBeacon {
usi: UUID?,
id: String,
mobileFeatures: String?,
hybridAgentId: String?,
hybridAgentVersion: String?,
connection: NetworkUtility.ConnectionType = InstanaSystemUtils.networkUtility.connectionType,
ect: NetworkUtility.CellularType? = nil)
-> CoreBeacon {
Expand All @@ -203,7 +207,8 @@ extension CoreBeacon {
osn: InstanaSystemUtils.systemName,
osv: InstanaSystemUtils.systemVersion,
dmo: InstanaSystemUtils.deviceModel,
agv: InstanaSystemUtils.agentVersion,
agv: CoreBeacon.getInstanaAgentVersion(hybridAgentId: hybridAgentId,
hybridAgentVersion: hybridAgentVersion),
ro: String(InstanaSystemUtils.isDeviceJailbroken),
vw: String(Int(InstanaSystemUtils.screenSize.width)),
vh: String(Int(InstanaSystemUtils.screenSize.height)),
Expand Down
17 changes: 14 additions & 3 deletions Sources/InstanaAgent/Configuration/InstanaConfiguraton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,16 @@ class InstanaConfiguration {
var preQueueUsageTime: TimeInterval
var reporterRateLimits: [ReporterRateLimitConfig]
var isValid: Bool { !key.isEmpty && !reportingURL.absoluteString.isEmpty }
// set if iOSAgent is invoked by flutter-agent or react-native-agent
var hybridAgentId: String?
var hybridAgentVersion: String?

required init(reportingURL: URL, key: String, httpCaptureConfig: HTTPCaptureConfig,
enableCrashReporting: Bool, suspendReporting: Set<SuspendReporting>? = nil,
slowSendInterval: Instana.Types.Seconds,
usiRefreshTimeIntervalInHrs: Double) {
usiRefreshTimeIntervalInHrs: Double,
hybridAgentId: String?,
hybridAgentVersion: String?) {
self.reportingURL = reportingURL
self.key = key
self.httpCaptureConfig = httpCaptureConfig
Expand All @@ -88,6 +93,8 @@ class InstanaConfiguration {
self.suspendReporting = suspendReporting ?? SuspendReporting.defaults
self.slowSendInterval = slowSendInterval
self.usiRefreshTimeIntervalInHrs = usiRefreshTimeIntervalInHrs
self.hybridAgentId = hybridAgentId
self.hybridAgentVersion = hybridAgentVersion
reporterSendDebounce = Defaults.reporterSendDebounce
reporterSendLowBatteryDebounce = Defaults.reporterSendLowBatteryDebounce
maxRetries = Defaults.maxRetries
Expand All @@ -102,12 +109,16 @@ class InstanaConfiguration {
enableCrashReporting: Bool,
suspendReporting: Set<SuspendReporting>? = nil,
slowSendInterval: Instana.Types.Seconds = 0.0,
usiRefreshTimeIntervalInHrs: Double = defaultUsiRefreshTimeIntervalInHrs)
usiRefreshTimeIntervalInHrs: Double = defaultUsiRefreshTimeIntervalInHrs,
hybridAgentId: String? = nil,
hybridAgentVersion: String? = nil)
-> InstanaConfiguration {
self.init(reportingURL: reportingURL, key: key, httpCaptureConfig: httpCaptureConfig,
enableCrashReporting: enableCrashReporting,
suspendReporting: suspendReporting,
slowSendInterval: slowSendInterval,
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs)
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs,
hybridAgentId: hybridAgentId,
hybridAgentVersion: hybridAgentVersion)
}
}
24 changes: 23 additions & 1 deletion Sources/InstanaAgent/Instana.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ import Foundation
/// - Returns: true on success, false on error
@objc
public static func setup(key: String, reportingURL: URL, options: InstanaSetupOptions?) -> Bool {
return setupInternal(key: key, reportingURL: reportingURL, options: options, hybridOptions: nil)
}

/// Internal use, configures and sets up the Instana agent.
///
/// - Parameters:
/// - hybridOptions: hybrid agent configuration options (set if invoked by Instana flutter-agent or react-native-agent)
///
/// - Returns: true on success, false on error
@objc
public static func setupInternal(key: String, reportingURL: URL, options: InstanaSetupOptions?,
hybridOptions: HybridAgentOptions?) -> Bool {
var httpCaptureConfig = HTTPCaptureConfig.automatic
var collectionEnabled = true
var enableCrashReporting = false
Expand Down Expand Up @@ -112,12 +124,22 @@ import Foundation

usiRefreshTimeIntervalInHrs = options.usiRefreshTimeIntervalInHrs
}

var hybridAgentId: String?
var hybridAgentVersion: String?
if let hybridOptions = hybridOptions {
hybridAgentId = hybridOptions.id
hybridAgentVersion = hybridOptions.version
}

let config = InstanaConfiguration.default(key: key, reportingURL: reportingURL,
httpCaptureConfig: httpCaptureConfig,
enableCrashReporting: enableCrashReporting,
suspendReporting: suspendReporting,
slowSendInterval: slowSendInterval,
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs)
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs,
hybridAgentId: hybridAgentId,
hybridAgentVersion: hybridAgentVersion)
let session = InstanaSession(configuration: config, propertyHandler: InstanaPropertyHandler(),
collectionEnabled: collectionEnabled)
Instana.current = Instana(session: session)
Expand Down
17 changes: 17 additions & 0 deletions Sources/InstanaAgent/InstanaSetupOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,20 @@ import Foundation
self.usiRefreshTimeIntervalInHrs = usiRefreshTimeIntervalInHrs
}
}

// Hybrid Agent options for setup
@objc public class HybridAgentOptions: NSObject {
public private(set) var id: String
public private(set) var version: String

/// - Parameters:
/// - id: flutter-agent or react-native-agent
/// - version: version of flutter-agent or react-native-agent
@objc public
init(id: String, version: String) {
// remove leading and trailing spaces
// truncate if too long
self.id = String(id.trimmingCharacters(in: .whitespaces).prefix(16))
self.version = String(version.trimmingCharacters(in: .whitespaces).prefix(16))
}
}
39 changes: 37 additions & 2 deletions Tests/InstanaAgentTests/Beacons/CoreBeacon/CoreBeaconTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class CoreBeaconTests: InstanaTestCase {
sid: sessionID,
usi: session.usi,
id: beaconID,
mobileFeatures: "c")
mobileFeatures: "c",
hybridAgentId: nil,
hybridAgentVersion: nil)
coreBeacon.append(props)
wifiCoreBeacon = CoreBeacon.createDefault(viewName: viewName,
key: key,
Expand All @@ -42,6 +44,8 @@ class CoreBeaconTests: InstanaTestCase {
usi: session.usi,
id: beaconID,
mobileFeatures: "c",
hybridAgentId: "f",
hybridAgentVersion: "3.0.6",
connection: .wifi,
ect: .fiveG)
wifiCoreBeacon.append(props)
Expand Down Expand Up @@ -135,7 +139,9 @@ class CoreBeaconTests: InstanaTestCase {
// Given
let configUsi = InstanaConfiguration(reportingURL: .random, key: "KEY", httpCaptureConfig: .automatic,
enableCrashReporting: false, slowSendInterval: 0.0,
usiRefreshTimeIntervalInHrs: usiTrackingNotAllowed)
usiRefreshTimeIntervalInHrs: usiTrackingNotAllowed,
hybridAgentId: nil,
hybridAgentVersion: nil)
let sessionUsi = InstanaSession.mock(configuration: configUsi,
sessionID: sessionID,
metaData: metaData,
Expand All @@ -148,6 +154,8 @@ class CoreBeaconTests: InstanaTestCase {
usi: sessionUsi.usi,
id: beaconID,
mobileFeatures: "c",
hybridAgentId: "nil",
hybridAgentVersion: nil,
connection: .wifi,
ect: .fiveG)
beacon.append(props)
Expand Down Expand Up @@ -282,4 +290,31 @@ class CoreBeaconTests: InstanaTestCase {
XCTAssertTrue(sut!.hasSuffix(""))
XCTAssertEqual(CoreBeacon.maxLengthPerField, 16384)
}

func test_getInstanaAgentVersion() {
let sut = CoreBeacon.getInstanaAgentVersion(hybridAgentId: nil, hybridAgentVersion: nil)
let expected = "\(InstanaSystemUtils.agentVersion)"
XCTAssertEqual(sut, expected)

let sutFlutter = CoreBeacon.getInstanaAgentVersion(hybridAgentId: "f", hybridAgentVersion: "3.0.6")
let expectedFlutter = "\(InstanaSystemUtils.agentVersion):f:3.0.6"
XCTAssertEqual(sutFlutter, expectedFlutter)

let sutRn = CoreBeacon.getInstanaAgentVersion(hybridAgentId: "r", hybridAgentVersion: "2.0.3")
let expectedRn = "\(InstanaSystemUtils.agentVersion):r:2.0.3"
XCTAssertEqual(sutRn, expectedRn)

// negative cases
let sutMisConfigVer = CoreBeacon.getInstanaAgentVersion(hybridAgentId: nil, hybridAgentVersion: "misConfigedVersion")
let expectedMisConfigVer = "\(InstanaSystemUtils.agentVersion)"
XCTAssertEqual(sutMisConfigVer, expectedMisConfigVer)

let sutMisConfigId = CoreBeacon.getInstanaAgentVersion(hybridAgentId: "misConfigedId", hybridAgentVersion: nil)
let expectedMisConfigId = "\(InstanaSystemUtils.agentVersion)"
XCTAssertEqual(sutMisConfigId, expectedMisConfigId)

let sutMisConfigEmpty = CoreBeacon.getInstanaAgentVersion(hybridAgentId: "", hybridAgentVersion: " ")
let expectedMisConfigEmpty = "\(InstanaSystemUtils.agentVersion)"
XCTAssertEqual(sutMisConfigEmpty, expectedMisConfigEmpty)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class InstanaSessionTests: InstanaTestCase {
// When
let configUsi = InstanaConfiguration(reportingURL: .random, key: "KEY", httpCaptureConfig: .automatic,
enableCrashReporting: false, slowSendInterval: 0.0,
usiRefreshTimeIntervalInHrs: usiTrackingNotAllowed)
usiRefreshTimeIntervalInHrs: usiTrackingNotAllowed,
hybridAgentId: nil,
hybridAgentVersion: nil)
let sut = InstanaSession(configuration: configUsi, propertyHandler: propertyHandler, collectionEnabled: true)

// Then
Expand All @@ -44,7 +46,9 @@ class InstanaSessionTests: InstanaTestCase {
// When
let configUsi = InstanaConfiguration(reportingURL: .random, key: "KEY", httpCaptureConfig: .automatic,
enableCrashReporting: false, slowSendInterval: 0.0,
usiRefreshTimeIntervalInHrs: (1.0 / 3600.0))
usiRefreshTimeIntervalInHrs: (1.0 / 3600.0),
hybridAgentId: nil,
hybridAgentVersion: nil)
let sut = InstanaSession(configuration: configUsi, propertyHandler: propertyHandler, collectionEnabled: true)
let oldUsi = sut.usi?.uuidString

Expand Down
23 changes: 23 additions & 0 deletions Tests/InstanaAgentTests/InstanaSetupOptionsTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright © 2024 IBM Corp. All rights reserved.
//

import Foundation
import XCTest
@testable import InstanaAgent

class HybridAgentOptionsTests: XCTestCase {
func test_init() {
let mco = HybridAgentOptions(id:"f", version:"3.0.6")
AssertEqualAndNotNil(mco.id, "f")
AssertEqualAndNotNil(mco.version, "3.0.6")

let mcoTooLong = HybridAgentOptions(id:"react-native-agent", version:"2.0.3")
AssertEqualAndNotNil(mcoTooLong.id, "react-native-age")
AssertEqualAndNotNil(mcoTooLong.version, "2.0.3")

let mcoMisConfiged = HybridAgentOptions(id:"", version:"")
AssertEqualAndNotNil(mcoMisConfiged.id, "")
AssertEqualAndNotNil(mcoMisConfiged.version, "")
}
}
22 changes: 22 additions & 0 deletions Tests/InstanaAgentTests/InstanaTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@ class InstanaTests: InstanaTestCase {
AssertEqualAndNotNil(Instana.current?.session.configuration.usiRefreshTimeIntervalInHrs, defaultUsiRefreshTimeIntervalInHrs)
}

func test_setupInternal() {
// Given
let key = "KEY"
let reportingURL = URL(string: "http://www.instana.com")!

let hybridOptions = HybridAgentOptions(id: "f", version:"3.0.6")
_ = Instana.setupInternal(key: key, reportingURL: reportingURL, options: nil, hybridOptions: hybridOptions)

// Then
AssertEqualAndNotNil(Instana.key, key)
AssertTrue(Instana.collectionEnabled)
AssertTrue(Instana.current!.session.collectionEnabled)
AssertEqualAndNotNil(Instana.sessionID, Instana.current?.session.id.uuidString)
AssertEqualAndNotNil(Instana.reportingURL, reportingURL)
AssertEqualAndNotNil(Instana.current?.session.configuration.reportingURL, reportingURL)
AssertEqualAndNotNil(Instana.current?.session.configuration.httpCaptureConfig, .automatic)
XCTAssertNotEqual(Instana.current?.session.configuration,
.default(key: key, reportingURL: reportingURL, enableCrashReporting: false))
AssertEqualAndNotNil(Instana.current?.session.configuration.slowSendInterval, 0.0)
AssertEqualAndNotNil(Instana.current?.session.configuration.usiRefreshTimeIntervalInHrs, defaultUsiRefreshTimeIntervalInHrs)
}

func test_setup_disabled() {
// Given
let key = "KEY"
Expand Down
4 changes: 3 additions & 1 deletion Tests/InstanaAgentTests/Mocks/MockInstanaConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ extension InstanaConfiguration {
httpCaptureConfig: httpCaptureConfig,
enableCrashReporting: true,
slowSendInterval: slowSendInterval,
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs)
usiRefreshTimeIntervalInHrs: usiRefreshTimeIntervalInHrs,
hybridAgentId: nil,
hybridAgentVersion: nil)
config.suspendReporting = []
config.monitorTypes = [.http,
.memoryWarning,
Expand Down
Loading

0 comments on commit d79dce2

Please sign in to comment.