endHistogramTimer method
End a histogram timer and generate metric event
Implementation
Future<void> endHistogramTimer(
String key,
String? fbl,
String? operation,
String? view,
String? state, {
int? timestamp,
}) async {
final hub = _hub;
if (!_isInitialized || hub == null) {
ObslyLogger.warn('MetricsController not initialized');
return;
}
// Check if metrics is enabled
final config = ConfigController.instance.config;
if (!(config?.enableMetrics ?? true)) {
ObslyLogger.debug('Metrics disabled, ignoring endHistogramTimer call');
return;
}
if (!_isTimerSessionValid()) {
ObslyLogger.warn('Invalid session for histogram timer');
return;
}
try {
final timerKey = _createTimerKey(key, fbl, operation, view);
// Check if timer exists - silently return if not found (normal for deeplinks, etc.)
if (!_histogramTimers.containsKey(timerKey)) {
return;
}
// Calculate duration
final startTime = _histogramTimers.remove(timerKey)!;
final endTime = timestamp ?? DateTime.now().millisecondsSinceEpoch;
final durationMs = endTime - startTime;
// Calculate le (bucket) using UX-appropriate millisecond-based thresholds
final buckets = [100.0, 300.0, 500.0, 1000.0, 3000.0, 5000.0, 30000.0]; // UX-appropriate buckets + 30s catch-all
double? le;
for (final bucket in buckets) {
if (durationMs <= bucket) {
le = bucket;
break;
}
}
final currentView =
NavigationIntegrationV2.isNavigationAvailable ? NavigationIntegrationV2.getCurrentViewName() : view;
final dimensions = Dimension(
fbl: (fbl?.isNotEmpty ?? false) ? fbl! : '', // Pass empty if not provided, Hub will use session fallback
operation: (operation?.isNotEmpty ?? false)
? operation!
: '', // Pass empty if not provided, Hub will use session fallback
view: (currentView?.isNotEmpty ?? false)
? currentView!
: '', // Pass empty if not provided, Hub will use session fallback
state: state ?? '',
app: '', // Will be filled by Hub with app info
platform: '', // Will be filled by Hub with app info
version: '', // Will be filled by Hub with app info
le: le,
);
final event = MetricEventBase(
key: key,
value: 1, // Count = 1 (similar to JavaScript implementation)
dimensions: dimensions,
metricType: MetricType.histogram.value,
duration: durationMs, // Send calculated duration
);
final reservation = hub.reserveEventMetadata();
hub.captureEvent(event, reservation);
ObslyLogger.verbose('📊 Histogram timer ended: $timerKey (${durationMs}s, le: $le)');
} catch (e) {
ObslyLogger.error('Error ending histogram timer: $e');
}
}