def test_processor_process_not_exists(self): meter_provider = metrics.MeterProvider() meter = meter_provider.get_meter(__name__) processor = Processor(True, meter_provider.resource) aggregator = SumAggregator() metric = metrics.Counter("available memory", "available memory", "bytes", int, meter) labels = () _batch_map = {} batch_key = (metric, SumAggregator, tuple(), labels) aggregator.update(1.0) processor._batch_map = _batch_map record = metrics.Record(metric, labels, aggregator) processor.process(record) self.assertEqual(len(processor._batch_map), 1) self.assertIsNotNone(processor._batch_map.get(batch_key)) self.assertEqual(processor._batch_map.get(batch_key).current, 0) self.assertEqual(processor._batch_map.get(batch_key).checkpoint, 1.0)
class Accumulator(metrics_api.Meter): """See `opentelemetry.metrics.Meter`. Args: source: The `MeterProvider` that created this meter. instrumentation_info: The `InstrumentationInfo` for this meter. """ def __init__( self, source: "MeterProvider", instrumentation_info: "InstrumentationInfo", ): self.instrumentation_info = instrumentation_info self.processor = Processor(source.stateful, source.resource) self.metrics = set() self.observers = set() self.metrics_lock = threading.Lock() self.observers_lock = threading.Lock() self.view_manager = ViewManager() def collect(self) -> None: """Collects all the metrics created with this `Meter` for export. Utilizes the processor to create checkpoints of the current values in each aggregator belonging to the metrics that were created with this meter instance. """ self._collect_metrics() self._collect_observers() def _collect_metrics(self) -> None: for metric in self.metrics: if not metric.enabled: continue to_remove = [] with metric.bound_instruments_lock: for ( labels, bound_instrument, ) in metric.bound_instruments.items(): for view_data in bound_instrument.view_datas: accumulation = Accumulation(metric, view_data.labels, view_data.aggregator) self.processor.process(accumulation) if bound_instrument.ref_count() == 0: to_remove.append(labels) # Remove handles that were released for labels in to_remove: del metric.bound_instruments[labels] def _collect_observers(self) -> None: with self.observers_lock: for observer in self.observers: if not observer.enabled: continue if not observer.run(): continue for labels, aggregator in observer.aggregators.items(): accumulation = Accumulation(observer, labels, aggregator) self.processor.process(accumulation) def record_batch( self, labels: Dict[str, str], record_tuples: Sequence[Tuple[metrics_api.Metric, metrics_api.ValueT]], ) -> None: """See `opentelemetry.metrics.Meter.record_batch`.""" # TODO: Avoid enconding the labels for each instrument, encode once # and reuse. for metric, value in record_tuples: metric.UPDATE_FUNCTION(value, labels) def create_counter( self, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], enabled: bool = True, ) -> metrics_api.Counter: """See `opentelemetry.metrics.Meter.create_counter`.""" counter = Counter(name, description, unit, value_type, self, enabled=enabled) with self.metrics_lock: self.metrics.add(counter) return counter def create_updowncounter( self, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], enabled: bool = True, ) -> metrics_api.UpDownCounter: """See `opentelemetry.metrics.Meter.create_updowncounter`.""" counter = UpDownCounter(name, description, unit, value_type, self, enabled=enabled) with self.metrics_lock: self.metrics.add(counter) return counter def create_valuerecorder( self, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], enabled: bool = True, ) -> metrics_api.ValueRecorder: """See `opentelemetry.metrics.Meter.create_valuerecorder`.""" recorder = ValueRecorder(name, description, unit, value_type, self, enabled=enabled) with self.metrics_lock: self.metrics.add(recorder) return recorder def register_sumobserver( self, callback: metrics_api.ObserverCallbackT, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], label_keys: Sequence[str] = (), enabled: bool = True, ) -> metrics_api.SumObserver: ob = SumObserver(callback, name, description, unit, value_type, label_keys, enabled) with self.observers_lock: self.observers.add(ob) return ob def register_updownsumobserver( self, callback: metrics_api.ObserverCallbackT, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], label_keys: Sequence[str] = (), enabled: bool = True, ) -> metrics_api.UpDownSumObserver: ob = UpDownSumObserver(callback, name, description, unit, value_type, label_keys, enabled) with self.observers_lock: self.observers.add(ob) return ob def register_valueobserver( self, callback: metrics_api.ObserverCallbackT, name: str, description: str, unit: str, value_type: Type[metrics_api.ValueT], label_keys: Sequence[str] = (), enabled: bool = True, ) -> metrics_api.ValueObserver: ob = ValueObserver(callback, name, description, unit, value_type, label_keys, enabled) with self.observers_lock: self.observers.add(ob) return ob def unregister_observer(self, observer: metrics_api.Observer) -> None: with self.observers_lock: self.observers.remove(observer) def register_view(self, view): self.view_manager.register_view(view) def unregister_view(self, view): self.view_manager.unregister_view(view)