66use OpenTelemetry \API \Metrics \GaugeInterface ;
77use OpenTelemetry \API \Metrics \HistogramInterface ;
88use OpenTelemetry \API \Metrics \MeterInterface ;
9+ use OpenTelemetry \API \Metrics \ObserverInterface ;
910use OpenTelemetry \API \Metrics \UpDownCounterInterface ;
1011use OpenTelemetry \Contrib \Otlp \ContentTypes ;
1112use OpenTelemetry \Contrib \Otlp \MetricExporter ;
2526use Utopia \Telemetry \Counter ;
2627use Utopia \Telemetry \Gauge ;
2728use Utopia \Telemetry \Histogram ;
29+ use Utopia \Telemetry \ObservableGauge ;
2830use Utopia \Telemetry \UpDownCounter ;
2931
3032class OpenTelemetry implements Adapter
@@ -34,13 +36,14 @@ class OpenTelemetry implements Adapter
3436 private MeterInterface $ meter ;
3537
3638 /**
37- * @var array<class-string, array<string, Counter|UpDownCounter|Histogram|Gauge>>
39+ * @var array<class-string, array<string, Counter|UpDownCounter|Histogram|Gauge|ObservableGauge >>
3840 */
3941 private array $ meterStorage = [
4042 Counter::class => [],
4143 UpDownCounter::class => [],
4244 Histogram::class => [],
4345 Gauge::class => [],
46+ ObservableGauge::class => [],
4447 ];
4548
4649 /**
@@ -103,12 +106,12 @@ protected function createExporter(TransportInterface $transport): MetricExporter
103106 }
104107
105108 /**
106- * @template T of Counter|UpDownCounter|Histogram|Gauge
109+ * @template T of Counter|UpDownCounter|Histogram|Gauge|ObservableGauge
107110 * @param class-string<T> $type
108111 * @param callable(): T $creator
109112 * @return T
110113 */
111- private function createMeter (string $ type , string $ name , callable $ creator ): Counter |UpDownCounter |Histogram |Gauge
114+ private function createMeter (string $ type , string $ name , callable $ creator ): Counter |UpDownCounter |Histogram |Gauge | ObservableGauge
112115 {
113116 if (! isset ($ this ->meterStorage [$ type ][$ name ])) {
114117 $ this ->meterStorage [$ type ][$ name ] = $ creator ();
@@ -222,6 +225,39 @@ public function add(float|int $amount, iterable $attributes = []): void
222225 });
223226 }
224227
228+ /**
229+ * Create an ObservableGauge metric
230+ *
231+ * @param array<string, mixed> $advisory
232+ */
233+ public function createObservableGauge (string $ name , ?string $ unit = null , ?string $ description = null , array $ advisory = []): ObservableGauge
234+ {
235+ return $ this ->createMeter (ObservableGauge::class, $ name , function () use ($ name , $ unit , $ description , $ advisory ) {
236+ $ otelGauge = $ this ->meter ->createObservableGauge ($ name , $ unit , $ description , $ advisory );
237+
238+ return new class ($ otelGauge ) extends ObservableGauge {
239+ private ?\Closure $ callback = null ;
240+
241+ public function __construct (private \OpenTelemetry \API \Metrics \ObservableGaugeInterface $ gauge )
242+ {
243+ $ this ->gauge ->observe (function (ObserverInterface $ observer ): void {
244+ if ($ this ->callback !== null ) {
245+ ($ this ->callback )(function (float |int $ value , iterable $ attributes = []) use ($ observer ): void {
246+ /** @var iterable<non-empty-string, array<mixed>|bool|float|int|string|null> $attributes */
247+ $ observer ->observe ($ value , $ attributes );
248+ });
249+ }
250+ });
251+ }
252+
253+ public function observe (callable $ callback ): void
254+ {
255+ $ this ->callback = \Closure::fromCallable ($ callback );
256+ }
257+ };
258+ });
259+ }
260+
225261 /**
226262 * Collect and export metrics
227263 */
0 commit comments