LCOV - code coverage report
Current view: top level - lib/src/metrics/storage - gauge_storage.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 97.4 % 39 38
Test Date: 2026-08-27 23:42:02 Functions: - 0 0

            Line data    Source code
       1              : // Copyright The OpenTelemetry Authors
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : 
       4              : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
       5              : 
       6              : import '../data/metric_point.dart';
       7              : import '../exemplar_filter.dart';
       8              : import '../exemplar_reservoir.dart';
       9              : import 'metric_storage.dart';
      10              : 
      11              : /// GaugeStorage is used for storing the last recorded value for each set of attributes.
      12              : class GaugeStorage<T extends num> extends NumericStorage<T>
      13              :     with ExemplarSampling<T> {
      14              :   /// Map of attribute sets to gauge data.
      15              :   final Map<Attributes, _GaugePointData<T>> _points = {};
      16              : 
      17              :   /// The exemplar filter used by this storage.
      18              :   @override
      19              :   final ExemplarFilter exemplarFilter;
      20              : 
      21              :   /// Creates a new GaugeStorage instance.
      22           12 :   GaugeStorage({ExemplarFilter? exemplarFilter})
      23              :       : exemplarFilter = exemplarFilter ?? const TraceBasedExemplarFilter();
      24              : 
      25              :   /// Records a measurement with the given attributes and context.
      26           10 :   @override
      27              :   void record(T value,
      28              :       [Attributes? attributes, Context? context, DateTime? timestamp]) {
      29              :     // Create a normalized key for lookup
      30            5 :     final key = attributes ?? _emptyAttributes();
      31           10 :     final existingKey = _findMatchingKey(key);
      32              : 
      33              :     _GaugePointData<T> pointData;
      34              :     if (existingKey != null) {
      35           16 :       pointData = _points[existingKey]!;
      36            8 :       pointData.value = value;
      37           16 :       pointData.updateTime = DateTime.now();
      38              :     } else {
      39           10 :       pointData = _GaugePointData<T>(
      40              :         value: value,
      41           10 :         updateTime: DateTime.now(),
      42              :         reservoir:
      43           10 :             SimpleFixedSizeExemplarReservoir(1), // Simple fixed size of 1
      44              :       );
      45              :       // Always update with the latest value
      46           20 :       _points[key] = pointData;
      47              :     }
      48              : 
      49           22 :     maybeOffer(pointData.reservoir, value, key, context ?? Context.current,
      50           10 :         timestamp ?? DateTime.now());
      51              :   }
      52              : 
      53              :   /// Helper to get empty attributes safely
      54            5 :   Attributes _emptyAttributes() {
      55              :     // If OTelFactory is not initialized yet, create an empty attributes directly
      56            5 :     if (OTelFactory.otelFactory == null) {
      57            0 :       return OTelAPI.attributes(); // Use the API's static method instead
      58              :     }
      59           10 :     return OTelFactory.otelFactory!.attributes();
      60              :   }
      61              : 
      62              :   /// Gets the current value for the given attributes.
      63              :   /// Returns 0 if no value has been recorded for these attributes.
      64            5 :   @override
      65              :   T getValue([Attributes? attributes]) {
      66              :     // Create a normalized key for lookup
      67            2 :     final key = attributes ?? _emptyAttributes();
      68              : 
      69              :     // Find matching attributes
      70            5 :     final existingKey = _findMatchingKey(key);
      71              : 
      72              :     if (existingKey != null) {
      73           15 :       return _points[existingKey]!.value;
      74              :     } else {
      75              :       // Convert 0 to the appropriate generic type
      76            1 :       if (T == int) {
      77              :         return 0 as T;
      78            1 :       } else if (T == double) {
      79              :         return 0.0 as T;
      80              :       } else {
      81              :         return 0 as T;
      82              :       }
      83              :     }
      84              :   }
      85              : 
      86              :   /// Finds a key in the points map that equals the given key
      87           10 :   Attributes? _findMatchingKey(Attributes key) {
      88           30 :     for (final existingKey in _points.keys) {
      89           10 :       if (existingKey == key) {
      90              :         // Using the == operator which should call equals
      91              :         return existingKey;
      92              :       }
      93              :     }
      94              :     return null;
      95              :   }
      96              : 
      97              :   /// Collects the current set of metric points.
      98            9 :   @override
      99              :   List<MetricPoint<T>> collectPoints() {
     100            9 :     final now = DateTime.now();
     101              : 
     102           36 :     return _points.entries.map((entry) {
     103            9 :       final data = entry.value;
     104              : 
     105            9 :       return MetricPoint<T>.gauge(
     106            9 :         attributes: entry.key,
     107            9 :         startTime: data.updateTime, // For gauges, start time is the update time
     108              :         time: now,
     109            9 :         value: data.value,
     110           27 :         exemplars: data.reservoir.collectAndReset(entry.key),
     111              :       );
     112            9 :     }).toList();
     113              :   }
     114              : 
     115              :   /// Resets all points (not typically used for Gauges, but required by interface).
     116            1 :   @override
     117              :   void reset() {
     118            2 :     _points.clear();
     119              :   }
     120              : }
     121              : 
     122              : /// Data for a single gauge point.
     123              : class _GaugePointData<T extends num> {
     124              :   /// The current value.
     125              :   T value;
     126              : 
     127              :   /// The time this value was recorded.
     128              :   DateTime updateTime;
     129              : 
     130              :   /// Reservoir for this point.
     131              :   final ExemplarReservoir reservoir;
     132              : 
     133           10 :   _GaugePointData(
     134              :       {required this.value, required this.updateTime, required this.reservoir});
     135              : }
        

Generated by: LCOV version 2.0-1