11import logging
22import os
33from threading import Lock
4+ from typing import Iterable
45
56from azure .monitor .opentelemetry .exporter import AzureMonitorMetricExporter
67from opentelemetry import metrics
8+ from opentelemetry .metrics import Observation , CallbackOptions
79from opentelemetry .sdk .metrics import MeterProvider
810from opentelemetry .sdk .metrics .export import PeriodicExportingMetricReader
911
@@ -16,9 +18,7 @@ class Metrics:
1618 _initialised = False
1719
1820 def __new__ (cls , * args , ** kwargs ):
19-
2021 logger .info ("Creating a new instance of Metrics class." )
21-
2222 if cls ._instance is None :
2323 with cls ._lock :
2424 if cls ._instance is None :
@@ -50,7 +50,11 @@ def __init__(self):
5050 self .meter = metrics .get_meter ("lungcs.models" )
5151
5252 self .environment = environment
53- self ._gauges = {}
53+
54+ # store latest gauge values here
55+ self ._gauge_values = {}
56+ self ._gauge_lock = Lock ()
57+ self ._registered_observable_gauges = set ()
5458
5559 self .requests_created = self .meter .create_counter (
5660 name = "requests.created" ,
@@ -66,10 +70,7 @@ def __init__(self):
6670 self .__class__ ._initialised = True
6771
6872 def record_request_created (self , model_name : str ):
69- logger .info (
70- "Metrics: record_request_created(model_name=%s)" ,
71- model_name
72- )
73+ logger .info ("Metrics: record_request_created(model_name=%s)" , model_name )
7374 self .requests_created .add (
7475 1 ,
7576 {
@@ -79,11 +80,7 @@ def record_request_created(self, model_name: str):
7980 )
8081
8182 def record_request_submitted (self , model_name : str ):
82- logger .info (
83- "Metrics: record_request_submitted(model_name=%s)" ,
84- model_name
85- )
86- logger .info ("record_request_submitted." )
83+ logger .info ("Metrics: record_request_submitted(model_name=%s)" , model_name )
8784 self .requests_submitted .add (
8885 1 ,
8986 {
@@ -92,6 +89,18 @@ def record_request_submitted(self, model_name: str):
9289 },
9390 )
9491
92+ def _make_gauge_callback (self , metric_name : str ):
93+ def callback (options : CallbackOptions ) -> Iterable [Observation ]:
94+ with self ._gauge_lock :
95+ value = self ._gauge_values .get (metric_name , 0 )
96+
97+ yield Observation (
98+ value ,
99+ {"environment" : self .environment },
100+ )
101+
102+ return callback
103+
95104 def set_gauge_value (self , metric_name , units , description , value ):
96105 logger .debug (
97106 "Metrics: set_gauge_value(metric_name=%s, units=%s, description=%s, value=%s)" ,
@@ -101,16 +110,14 @@ def set_gauge_value(self, metric_name, units, description, value):
101110 value ,
102111 )
103112
104- gauge = self ._gauges .get (metric_name )
105- if gauge is None :
106- gauge = self .meter .create_gauge (
107- name = metric_name ,
108- unit = units ,
109- description = description ,
110- )
111- self ._gauges [metric_name ] = gauge
112-
113- gauge .record (
114- value ,
115- {"environment" : self .environment },
116- )
113+ with self ._gauge_lock :
114+ self ._gauge_values [metric_name ] = value
115+
116+ if metric_name not in self ._registered_observable_gauges :
117+ self .meter .create_observable_gauge (
118+ name = metric_name ,
119+ callbacks = [self ._make_gauge_callback (metric_name )],
120+ unit = units ,
121+ description = description ,
122+ )
123+ self ._registered_observable_gauges .add (metric_name )
0 commit comments