endHistogramTimer method

Future<void> endHistogramTimer(
  1. String key,
  2. String? fbl,
  3. String? operation,
  4. String? view,
  5. String? state, {
  6. int? timestamp,
})

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
    if (!_histogramTimers.containsKey(timerKey)) {
      ObslyLogger.error('Timer not found for key: $timerKey');
      return;
    }

    // Calculate duration
    final startTime = _histogramTimers.remove(timerKey)!;
    final endTime = timestamp ?? DateTime.now().millisecondsSinceEpoch;
    final durationMs = endTime - startTime;

    // Calculate le (bucket) similar to JavaScript implementation
    final buckets = [
      0.001,
      0.01,
      0.1,
      1.0,
      10.0,
      100.0,
      1000.0
    ]; // Common histogram buckets
    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.debug(
        '📊 Histogram timer ended: $timerKey (${durationMs}s, le: $le)');
  } catch (e) {
    ObslyLogger.error('Error ending histogram timer: $e');
  }
}