Skip to content

Commit 2097826

Browse files
yukiwwwangGit Sync Plugin
authored andcommitted
Add metrics reporting
1 parent 73b10cd commit 2097826

5 files changed

Lines changed: 191 additions & 1 deletion

File tree

call/TUICallKit_Swift/Common/Constants.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
// Created by vincepzhang on 2022/12/30.
66
//
77

8+
// Version
9+
let TUICALL_VERSION = "4.0.0.0"
10+
811
// Default avatar
912
let TUI_CALL_DEFAULT_AVATAR: String = "https://imgcache.qq.com/qcloud/public/static//avatar1_100.20191230.png"
1013

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//
2+
// KeyMetrics.swift
3+
// TUICallKit
4+
//
5+
// Created by yukiwwwang on 2026/01/06.
6+
//
7+
8+
import Foundation
9+
import TUICore
10+
import AtomicXCore
11+
12+
#if canImport(TXLiteAVSDK_TRTC)
13+
import TXLiteAVSDK_TRTC
14+
#elseif canImport(TXLiteAVSDK_Professional)
15+
import TXLiteAVSDK_Professional
16+
#endif
17+
18+
class KeyMetrics {
19+
private static let TAG = "KeyMetrics"
20+
private static let API_REPORT_ROOM_ENGINE_EVENT = "reportRoomEngineEvent"
21+
private static var lastReportedCallId: String = ""
22+
23+
enum EventId: Int {
24+
case received = 171010
25+
case wakeup = 171011
26+
}
27+
28+
static func countUV(eventId: EventId, callId: String) {
29+
let isDuplicateCall = (callId == lastReportedCallId) && !callId.isEmpty
30+
if eventId == .received && !callId.isEmpty {
31+
lastReportedCallId = callId
32+
}
33+
34+
if isDuplicateCall && eventId == .received {
35+
Logger.info("\(TAG) skip duplicate report for callId: \(callId)")
36+
return
37+
}
38+
39+
switch eventId {
40+
case .received:
41+
countEvent(eventId: eventId, callId: callId)
42+
case .wakeup:
43+
if callId == lastReportedCallId {
44+
return
45+
}
46+
lastReportedCallId = callId
47+
countEvent(eventId: eventId, callId: callId)
48+
}
49+
}
50+
51+
static func reset() {
52+
lastReportedCallId = ""
53+
}
54+
55+
static func flushMetrics() {
56+
var paramsJson: [String: Any] = [:]
57+
paramsJson["sdkAppId"] = TUILogin.getSdkAppID()
58+
paramsJson["report"] = "report"
59+
60+
var jsonParams: [String: Any] = [:]
61+
jsonParams["api"] = "KeyMetricsStats"
62+
jsonParams["params"] = paramsJson
63+
64+
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonParams),
65+
let jsonString = String(data: jsonData, encoding: .utf8) {
66+
TRTCCloud.sharedInstance().callExperimentalAPI(jsonString)
67+
}
68+
}
69+
70+
private static func countEvent(eventId: EventId, callId: String) {
71+
trackForKibana(eventId: eventId, callId: callId)
72+
trackForTRTC(eventId: eventId)
73+
}
74+
75+
private static func trackForKibana(eventId: EventId, callId: String) {
76+
do {
77+
let extensionJson = buildExtensionJson(callId: callId)
78+
let extensionString = String(data: try JSONSerialization.data(withJSONObject: extensionJson), encoding: .utf8) ?? ""
79+
let payload = buildEventPayload(eventId: eventId, extensionMessage: extensionString)
80+
81+
if let payloadData = try? JSONSerialization.data(withJSONObject: payload),
82+
let payloadString = String(data: payloadData, encoding: .utf8) {
83+
V2TIMManager.sharedInstance()?.callExperimentalAPI(api: API_REPORT_ROOM_ENGINE_EVENT,
84+
param: payloadString as NSObject,
85+
succ: {_ in
86+
Logger.info("\(TAG) trackForKibana success: eventId=\(eventId)")
87+
}, fail: { code, desc in
88+
Logger.error("\(TAG) trackForKibana failed: code=\(code), desc=\(desc ?? "")")
89+
})
90+
}
91+
} catch {
92+
Logger.error("\(TAG) trackForKibana exception: eventId=\(eventId), error=\(error)")
93+
}
94+
}
95+
96+
private static func trackForTRTC(eventId: EventId) {
97+
var paramsJson: [String: Any] = [:]
98+
paramsJson["opt"] = "CountPV"
99+
paramsJson["key"] = eventId.rawValue
100+
paramsJson["withInstanceTrace"] = false
101+
paramsJson["version"] = TUICALL_VERSION
102+
103+
var jsonParams: [String: Any] = [:]
104+
jsonParams["api"] = "KeyMetricsStats"
105+
jsonParams["params"] = paramsJson
106+
107+
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonParams),
108+
let jsonString = String(data: jsonData, encoding: .utf8) {
109+
TRTCCloud.sharedInstance().callExperimentalAPI(jsonString)
110+
}
111+
112+
if TUILogin.getSdkAppID() > 0 {
113+
flushMetrics()
114+
}
115+
}
116+
117+
private static func buildExtensionJson(callId: String) -> [String: Any] {
118+
var json: [String: Any] = [:]
119+
120+
let activeCall = CallStore.shared.state.value.activeCall
121+
122+
// Basic Info
123+
json[JsonKeys.callId] = callId
124+
json[JsonKeys.intRoomId] = Int(activeCall.roomId) ?? 0
125+
json[JsonKeys.strRoomId] = activeCall.roomId
126+
json[JsonKeys.uiKitVersion] = TUICALL_VERSION
127+
128+
// Platform Info
129+
json[JsonKeys.platform] = "ios"
130+
json[JsonKeys.framework] = FrameworkConstants.framework
131+
json[JsonKeys.deviceBrand] = "Apple"
132+
json[JsonKeys.deviceModel] = getDeviceModel()
133+
json[JsonKeys.iosVersion] = UIDevice.current.systemVersion
134+
135+
return json
136+
}
137+
138+
private static func buildEventPayload(eventId: EventId, extensionMessage: String) -> [String: Any] {
139+
var json: [String: Any] = [:]
140+
json[JsonKeys.eventId] = eventId.rawValue
141+
json[JsonKeys.eventCode] = 0
142+
json[JsonKeys.eventResult] = 0
143+
json[JsonKeys.eventMessage] = TUICALL_VERSION
144+
json[JsonKeys.moreMessage] = ""
145+
json[JsonKeys.extensionMessage] = extensionMessage
146+
return json
147+
}
148+
149+
private static func getDeviceModel() -> String {
150+
var systemInfo = utsname()
151+
uname(&systemInfo)
152+
let machineMirror = Mirror(reflecting: systemInfo.machine)
153+
let identifier = machineMirror.children.reduce("") { identifier, element in
154+
guard let value = element.value as? Int8, value != 0 else { return identifier }
155+
return identifier + String(UnicodeScalar(UInt8(value)))
156+
}
157+
return identifier
158+
}
159+
160+
private struct JsonKeys {
161+
// Event Payload Keys
162+
static let eventId = "event_id"
163+
static let eventCode = "event_code"
164+
static let eventResult = "event_result"
165+
static let eventMessage = "event_message"
166+
static let moreMessage = "more_message"
167+
static let extensionMessage = "extension_message"
168+
169+
// Basic Info Keys
170+
static let callId = "call_id"
171+
static let intRoomId = "int_room_id"
172+
static let strRoomId = "str_room_id"
173+
static let uiKitVersion = "ui_kit_version"
174+
175+
// Platform Info Keys
176+
static let platform = "platform"
177+
static let framework = "framework"
178+
static let deviceBrand = "device_brand"
179+
static let deviceModel = "device_model"
180+
static let iosVersion = "ios_version"
181+
static let isForeground = "is_foreground"
182+
static let isScreenLocked = "is_screen_locked"
183+
}
184+
}

call/TUICallKit_Swift/TUICallKitImpl.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ extension TUICallKitImpl {
433433
}
434434
showCallKitViewController(isCaller: true)
435435

436-
case .onCallReceived(_, _, _):
436+
case let .onCallReceived(callId, _, _):
437+
KeyMetrics.countUV(eventId: .received, callId: callId)
437438
showCallKitViewController(isCaller: false)
438439

439440
case let .onCallEnded(callId: _, mediaType: _, reason: reason, userId: userId):

call/TUICallKit_Swift/View/CallMainViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class CallMainViewController: UIViewController {
3838

3939
override func viewDidLoad() {
4040
super.viewDidLoad()
41+
KeyMetrics.countUV(eventId: .wakeup, callId: CallStore.shared.state.value.activeCall.callId)
4142

4243
view.addSubview(mainView)
4344
view.addSubview(floatWindowButton)

call/TUICallKit_Swift/View/Component/IncomingBanner/IncomingBannerViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class IncomingBannerViewController: UIViewController {
7474
super.viewDidLoad()
7575
if isViewReady { return }
7676
isViewReady = true
77+
KeyMetrics.countUV(eventId: .wakeup, callId: CallStore.shared.state.value.activeCall.callId)
7778
constructViewHierarchy()
7879
activateConstraints()
7980
bindInteraction()

0 commit comments

Comments
 (0)