Skip to content

Commit 91877cf

Browse files
ZhaoChaoqunclaude
andcommitted
refactor: migrate latency tracking to TelemetryDeck floatValue
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a450510 commit 91877cf

5 files changed

Lines changed: 14 additions & 29 deletions

File tree

Sources/ASREngineFactory.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@ enum ASREngineFactory {
6363
let success = engine != nil
6464
var params: [String: String] = [
6565
"engine": modelType.rawValue,
66-
"latencyMs": "\(loadMs)",
6766
"success": "\(success)",
6867
]
6968
if !success {
7069
params["errorType"] = "load_failed"
7170
}
72-
AnalyticsService.track("Model.LoadCompleted", parameters: params)
71+
AnalyticsService.track("Model.LoadCompleted", parameters: params, floatValue: Double(loadMs))
7372

7473
return Result(engine: engine)
7574
}

Sources/AnalyticsService.swift

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ enum AnalyticsService {
4949
}
5050

5151
/// Track an analytics event with optional parameters.
52-
static func track(_ event: String, parameters: [String: String] = [:]) {
52+
/// - Parameters:
53+
/// - event: Event name (e.g. "ASR.FlushCompleted").
54+
/// - parameters: String key-value metadata (for filtering and breakdown).
55+
/// - floatValue: Optional numeric value for aggregation (avg/min/max) in TelemetryDeck.
56+
static func track(_ event: String, parameters: [String: String] = [:], floatValue: Double? = nil) {
5357
guard isEnabled else { return }
5458

5559
// Attach default parameters
@@ -58,7 +62,7 @@ enum AnalyticsService {
5862
params["selectedEngine"] = UserDefaults.standard.string(forKey: "selectedASRModel") ?? "streamingParaformer"
5963
params["cloudRewriteEnabled"] = "\(hasCloudRewriteAPIKey)"
6064

61-
TelemetryDeck.signal(event, parameters: params)
65+
TelemetryDeck.signal(event, parameters: params, floatValue: floatValue)
6266
}
6367

6468
// MARK: - Timing Helpers
@@ -78,17 +82,6 @@ enum AnalyticsService {
7882

7983
// MARK: - Bucketing Helpers
8084

81-
/// Map millisecond latency to a privacy-safe bucket string.
82-
static func latencyBucket(ms: Int) -> String {
83-
switch ms {
84-
case ..<500: return "0-500ms"
85-
case 500..<1000: return "500-1000ms"
86-
case 1000..<1500: return "1000-1500ms"
87-
case 1500..<2000: return "1500-2000ms"
88-
default: return "2000ms+"
89-
}
90-
}
91-
9285
/// Map recording duration (seconds) to a privacy-safe bucket.
9386
static func durationBucket(seconds: Double) -> String {
9487
switch seconds {

Sources/CloudRewriteService.swift

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,15 @@ final class CloudRewriteService {
149149
let resolvedModel = await modelProbeTask.value
150150
AnalyticsService.track("CloudRewrite.Completed", parameters: [
151151
"outcome": "rewritten",
152-
"latencyBucket": AnalyticsService.latencyBucket(ms: elapsedMs),
153152
"model": resolvedModel,
154153
"changed": "\(result != text)",
155154
"inputLengthBucket": AnalyticsService.lengthBucket(count: text.count),
156-
])
155+
], floatValue: Double(elapsedMs))
157156
return result
158157
} catch is RewriteTimeoutError {
159158
cloudRewriteLogger.warning("Cloud rewrite timed out (\(Self.rewriteTimeout, privacy: .public)), using original text (\(text.count, privacy: .public) chars)")
160159
AnalyticsService.track("CloudRewrite.Completed", parameters: [
161160
"outcome": "timeout",
162-
"latencyBucket": "timeout",
163161
"inputLengthBucket": AnalyticsService.lengthBucket(count: text.count),
164162
])
165163
return text
@@ -171,30 +169,27 @@ final class CloudRewriteService {
171169
let elapsedMs = Int(startTime.duration(to: .now).components.seconds * 1000)
172170
AnalyticsService.track("CloudRewrite.Completed", parameters: [
173171
"outcome": "error",
174-
"latencyBucket": AnalyticsService.latencyBucket(ms: elapsedMs),
175172
"errorType": "network_\(error.code.rawValue)",
176173
"inputLengthBucket": AnalyticsService.lengthBucket(count: text.count),
177-
])
174+
], floatValue: Double(elapsedMs))
178175
return text
179176
} catch let error as CloudRewriteError {
180177
cloudRewriteLogger.warning("Cloud rewrite service error: \(error.logDescription, privacy: .public). Fallback to original text")
181178
let elapsedMs = Int(startTime.duration(to: .now).components.seconds * 1000)
182179
AnalyticsService.track("CloudRewrite.Completed", parameters: [
183180
"outcome": "error",
184-
"latencyBucket": AnalyticsService.latencyBucket(ms: elapsedMs),
185181
"errorType": error.logDescription,
186182
"inputLengthBucket": AnalyticsService.lengthBucket(count: text.count),
187-
])
183+
], floatValue: Double(elapsedMs))
188184
return text
189185
} catch {
190186
cloudRewriteLogger.warning("Cloud rewrite unknown error: \(error.localizedDescription, privacy: .public). Fallback to original text")
191187
let elapsedMs = Int(startTime.duration(to: .now).components.seconds * 1000)
192188
AnalyticsService.track("CloudRewrite.Completed", parameters: [
193189
"outcome": "error",
194-
"latencyBucket": AnalyticsService.latencyBucket(ms: elapsedMs),
195190
"errorType": "unknown",
196191
"inputLengthBucket": AnalyticsService.lengthBucket(count: text.count),
197-
])
192+
], floatValue: Double(elapsedMs))
198193
return text
199194
}
200195
}

Sources/PostProcessingPipeline.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,12 @@ final class PostProcessingPipeline {
165165
"itnApplied": "\(itnApplied)",
166166
"cscApplied": "\(cscApplied)",
167167
"punctuationApplied": "\(punctuationApplied)",
168-
"totalLatencyMs": "\(totalMs)",
169168
"termNormLatencyMs": "\(termNormMs)",
170169
"itnLatencyMs": "\(itnMs)",
171170
"cscLatencyMs": "\(cscMs)",
172171
"punctLatencyMs": "\(punctMs)",
173172
"cloudRewriteLatencyMs": "\(cloudRewriteMs)",
174173
"termNormChanged": "\(termNormChanged)",
175-
])
174+
], floatValue: Double(totalMs))
176175
}
177176
}

Sources/RecordingManager.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class RecordingManager {
158158
"durationBucket": AnalyticsService.durationBucket(seconds: durationSeconds),
159159
"hasResult": "\(finalText != nil && !(finalText?.isEmpty ?? true))",
160160
"resultLengthBucket": AnalyticsService.lengthBucket(count: finalText?.count ?? 0),
161-
])
161+
], floatValue: durationSeconds)
162162
self.sessionStartTime = nil
163163
}
164164
DispatchQueue.main.async { self.onFinalResult?(finalText) }
@@ -208,10 +208,9 @@ class RecordingManager {
208208
let text = rawText.isEmpty ? fallbackText : rawText
209209
AnalyticsService.track("ASR.FlushCompleted", parameters: [
210210
"engine": self.currentModel.rawValue,
211-
"latencyMs": "\(flushMs)",
212211
"success": "\(!rawText.isEmpty)",
213212
"rawTextLengthBucket": AnalyticsService.lengthBucket(count: text.count),
214-
])
213+
], floatValue: Double(flushMs))
215214
self.handleEvent(.flushComplete(rawText: text))
216215
}
217216
}

0 commit comments

Comments
 (0)