LCOV - code coverage report
Current view: top level - lib/src/metrics/instruments - counter.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 45 45
Test Date: 2026-10-11 16:35:14 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.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;
      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           18 :   Counter({required APICounter<T> apiCounter, required Meter meter})
      42              :       : _apiCounter = apiCounter,
      43              :         _meter = meter,
      44           18 :         _storage = SumStorage<T>(
      45              :           isMonotonic: true,
      46           36 :           exemplarFilter: meter.provider.exemplarFilter,
      47              :         ) {
      48           90 :     _meter.provider.registerInstrument(_meter.name, this);
      49              :   }
      50              : 
      51              :   /// Gets the name of this counter.
      52           18 :   @override
      53           36 :   String get name => _apiCounter.name;
      54              : 
      55              :   /// Gets the unit of measurement for this counter.
      56           13 :   @override
      57           26 :   String? get unit => _apiCounter.unit;
      58              : 
      59              :   /// Gets the description of this counter.
      60           13 :   @override
      61           26 :   String? get description => _apiCounter.description;
      62              : 
      63              :   /// Checks if this counter is enabled.
      64              :   ///
      65              :   /// If false, measurements will be dropped and not recorded.
      66           16 :   @override
      67           32 :   bool isEnabled() => _meter.isEnabled();
      68              : 
      69              :   /// Gets the meter that created this counter.
      70           18 :   @override
      71           18 :   APIMeter get meter => _meter;
      72              : 
      73            1 :   @override
      74            2 :   InstrumentAdvisory? get advisory => _apiCounter.advisory;
      75              : 
      76              :   /// Always true for Counter instruments.
      77            1 :   @override
      78              :   bool get isCounter => true;
      79              : 
      80              :   /// Always false for Counter instruments.
      81            1 :   @override
      82              :   bool get isUpDownCounter => false;
      83              : 
      84              :   /// Always false for Counter instruments.
      85            1 :   @override
      86              :   bool get isGauge => false;
      87              : 
      88              :   /// Always false for Counter instruments.
      89            1 :   @override
      90              :   bool get isHistogram => false;
      91              : 
      92              :   /// Records a measurement with this counter.
      93              :   ///
      94              :   /// This method increments the counter by the given value. The value must be
      95              :   /// non-negative, or an ArgumentError will be thrown.
      96              :   ///
      97              :   /// @param value The amount to increment the counter by (must be non-negative)
      98              :   /// @param attributes Optional attributes to associate with this measurement
      99              :   /// @throws ArgumentError if value is negative
     100           16 :   @override
     101              :   void add(T value, [Attributes? attributes]) {
     102              :     // First use the API implementation (no-op by default)
     103           32 :     _apiCounter.add(value, attributes);
     104              : 
     105              :     // Check for negative values
     106           16 :     if (value < 0) {
     107            1 :       throw ArgumentError('Counter value must be non-negative');
     108              :     }
     109              : 
     110              :     // Only record if enabled
     111           16 :     if (!isEnabled()) return;
     112              : 
     113              :     // Record the measurement in our storage
     114           48 :     _storage.record(value, attributes, Context.current);
     115              :   }
     116              : 
     117              :   /// Records a measurement with attributes specified as a map.
     118              :   ///
     119              :   /// This is a convenience method that converts the map to Attributes
     120              :   /// and calls add().
     121              :   ///
     122              :   /// @param value The amount to increment the counter by (must be non-negative)
     123              :   /// @param attributeMap Map of attribute names to values
     124            1 :   @override
     125              :   void addWithMap(T value, Map<String, Object> attributeMap) {
     126              :     // Just convert to Attributes and call add
     127              :     final attributes =
     128            2 :         attributeMap.isEmpty ? null : attributeMap.toAttributes();
     129            1 :     add(value, attributes);
     130              :   }
     131              : 
     132              :   /// Gets the current value of the counter for a specific set of attributes.
     133              :   ///
     134              :   /// If no attributes are provided, returns the sum of all values across all attributes.
     135              :   ///
     136              :   /// @param attributes Optional attributes to filter by
     137              :   /// @return The current value of the counter
     138            4 :   T getValue([Attributes? attributes]) {
     139            8 :     return _storage.getValue(attributes);
     140              :   }
     141              : 
     142              :   /// Gets the current points for this counter.
     143              :   ///
     144              :   /// This is used by the SDK to collect metrics for export.
     145              :   ///
     146              :   /// @return A list of metric points containing the current counter values
     147           12 :   List<MetricPoint<T>> collectPoints() {
     148           24 :     return _storage.collectPoints();
     149              :   }
     150              : 
     151              :   /// Collects metrics for this counter.
     152              :   ///
     153              :   /// This method is called by the SDK to collect metrics for export.
     154              :   ///
     155              :   /// @return A list of metrics containing the current counter values
     156           12 :   @override
     157              :   List<Metric> collectMetrics() {
     158           13 :     if (!isEnabled()) return [];
     159              : 
     160              :     // Get the points from storage
     161           12 :     final points = collectPoints();
     162              : 
     163           12 :     if (points.isEmpty) return [];
     164              : 
     165           12 :     final metric = Metric(
     166           12 :       name: name,
     167           12 :       description: description,
     168           12 :       unit: unit,
     169              :       type: MetricType.sum,
     170           24 :       isMonotonic: _storage.isMonotonic,
     171              :       points: points,
     172              :     );
     173              : 
     174           12 :     return [metric];
     175              :   }
     176              : 
     177              :   /// Resets the counter.
     178              :   ///
     179              :   /// This is only used for Delta temporality and should not be called
     180              :   /// by application code.
     181            2 :   void reset() {
     182            4 :     _storage.reset();
     183              :   }
     184              : }
        

Generated by: LCOV version 2.0-1