LCOV - code coverage report
Current view: top level - src/metrics/instruments - counter.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.5 % 40 37
Test Date: 2025-11-15 13:23:01 Functions: - 0 0

            Line data    Source code
       1              : // Licensed under the Apache License, Version 2.0
       2              : // Copyright 2025, Michael Bushe, All rights reserved.
       3              : 
       4              : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
       5              : 
       6              : import '../data/metric.dart';
       7              : import '../data/metric_point.dart';
       8              : import '../meter.dart';
       9              : import '../storage/sum_storage.dart';
      10              : import 'base_instrument.dart';
      11              : 
      12              : /// A synchronous instrument that records monotonically increasing values.
      13              : ///
      14              : /// A Counter is used to measure a non-negative, monotonically increasing value.
      15              : /// Counters only allow positive increments and are appropriate for values that
      16              : /// never decrease, such as:
      17              : /// - Request count
      18              : /// - Completed operations
      19              : /// - Error count
      20              : /// - CPU time used
      21              : /// - Bytes sent/received
      22              : ///
      23              : /// If the value can decrease, use an UpDownCounter instead.
      24              : ///
      25              : /// More information:
      26              : /// https://opentelemetry.io/docs/specs/otel/metrics/api/#counter
      27              : class Counter<T extends num> implements APICounter<T>, SDKInstrument {
      28              :   /// The underlying API Counter.
      29              :   final APICounter<T> _apiCounter;
      30              : 
      31              :   /// The Meter that created this Counter.
      32              :   final Meter _meter;
      33              : 
      34              :   /// Storage for accumulating counter measurements.
      35              :   final SumStorage<T> _storage = SumStorage<T>(isMonotonic: true);
      36              : 
      37              :   /// Creates a new Counter instance.
      38              :   ///
      39              :   /// @param apiCounter The API Counter to delegate API calls to
      40              :   /// @param meter The Meter that created this Counter
      41            8 :   Counter({
      42              :     required APICounter<T> apiCounter,
      43              :     required Meter meter,
      44              :   })  : _apiCounter = apiCounter,
      45              :         _meter = meter {
      46           40 :     _meter.provider.registerInstrument(_meter.name, this);
      47              :   }
      48              : 
      49              :   /// Gets the name of this counter.
      50            8 :   @override
      51           16 :   String get name => _apiCounter.name;
      52              : 
      53              :   /// Gets the unit of measurement for this counter.
      54            7 :   @override
      55           14 :   String? get unit => _apiCounter.unit;
      56              : 
      57              :   /// Gets the description of this counter.
      58            7 :   @override
      59           14 :   String? get description => _apiCounter.description;
      60              : 
      61              :   /// Checks if this counter is enabled.
      62              :   ///
      63              :   /// If false, measurements will be dropped and not recorded.
      64            8 :   @override
      65           16 :   bool get enabled => _meter.enabled;
      66              : 
      67              :   /// Gets the meter that created this counter.
      68            8 :   @override
      69            8 :   APIMeter get meter => _meter;
      70              : 
      71              :   /// Always true for Counter instruments.
      72            1 :   @override
      73              :   bool get isCounter => true;
      74              : 
      75              :   /// Always false for Counter instruments.
      76            1 :   @override
      77              :   bool get isUpDownCounter => false;
      78              : 
      79              :   /// Always false for Counter instruments.
      80            1 :   @override
      81              :   bool get isGauge => false;
      82              : 
      83              :   /// Always false for Counter instruments.
      84            1 :   @override
      85              :   bool get isHistogram => false;
      86              : 
      87              :   /// Records a measurement with this counter.
      88              :   ///
      89              :   /// This method increments the counter by the given value. The value must be
      90              :   /// non-negative, or an ArgumentError will be thrown.
      91              :   ///
      92              :   /// @param value The amount to increment the counter by (must be non-negative)
      93              :   /// @param attributes Optional attributes to associate with this measurement
      94              :   /// @throws ArgumentError if value is negative
      95            8 :   @override
      96              :   void add(T value, [Attributes? attributes]) {
      97              :     // First use the API implementation (no-op by default)
      98           16 :     _apiCounter.add(value, attributes);
      99              : 
     100              :     // Check for negative values
     101            8 :     if (value < 0) {
     102            1 :       throw ArgumentError('Counter value must be non-negative');
     103              :     }
     104              : 
     105              :     // Only record if enabled
     106            8 :     if (!enabled) return;
     107              : 
     108              :     // Record the measurement in our storage
     109           16 :     _storage.record(value, attributes);
     110              :   }
     111              : 
     112              :   /// Records a measurement with attributes specified as a map.
     113              :   ///
     114              :   /// This is a convenience method that converts the map to Attributes
     115              :   /// and calls add().
     116              :   ///
     117              :   /// @param value The amount to increment the counter by (must be non-negative)
     118              :   /// @param attributeMap Map of attribute names to values
     119            0 :   @override
     120              :   void addWithMap(T value, Map<String, Object> attributeMap) {
     121              :     // Just convert to Attributes and call add
     122              :     final attributes =
     123            0 :         attributeMap.isEmpty ? null : attributeMap.toAttributes();
     124            0 :     add(value, attributes);
     125              :   }
     126              : 
     127              :   /// Gets the current value of the counter for a specific set of attributes.
     128              :   ///
     129              :   /// If no attributes are provided, returns the sum of all values across all attributes.
     130              :   ///
     131              :   /// @param attributes Optional attributes to filter by
     132              :   /// @return The current value of the counter
     133            2 :   T getValue([Attributes? attributes]) {
     134            4 :     return _storage.getValue(attributes);
     135              :   }
     136              : 
     137              :   /// Gets the current points for this counter.
     138              :   ///
     139              :   /// This is used by the SDK to collect metrics for export.
     140              :   ///
     141              :   /// @return A list of metric points containing the current counter values
     142            6 :   List<MetricPoint<T>> collectPoints() {
     143           12 :     return _storage.collectPoints();
     144              :   }
     145              : 
     146              :   /// Collects metrics for this counter.
     147              :   ///
     148              :   /// This method is called by the SDK to collect metrics for export.
     149              :   ///
     150              :   /// @return A list of metrics containing the current counter values
     151            6 :   @override
     152              :   List<Metric> collectMetrics() {
     153            7 :     if (!enabled) return [];
     154              : 
     155              :     // Get the points from storage
     156            6 :     final points = collectPoints();
     157              : 
     158            6 :     if (points.isEmpty) return [];
     159              : 
     160            6 :     final metric = Metric(
     161            6 :       name: name,
     162            6 :       description: description,
     163            6 :       unit: unit,
     164              :       type: MetricType.sum,
     165              :       points: points,
     166              :     );
     167              : 
     168            6 :     return [metric];
     169              :   }
     170              : 
     171              :   /// Resets the counter.
     172              :   ///
     173              :   /// This is only used for Delta temporality and should not be called
     174              :   /// by application code.
     175            2 :   void reset() {
     176            4 :     _storage.reset();
     177              :   }
     178              : }
        

Generated by: LCOV version 2.0-1