packages feed

otel-effectful-1.0.0: src/Effectful/OpenTelemetry/Metrics/ObservableGauge.hs

{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Effectful.OpenTelemetry.Metrics.ObservableGauge (ObservableGauge, new) where

import Data.Maybe (maybeToList)
import Data.Scientific (Scientific)
import Data.Text (Text)
import Effectful
import Effectful.Dispatch.Static (unsafeEff_)
import Effectful.OpenTelemetry.Metrics.Effect (Metrics)
import Effectful.OpenTelemetry.Metrics.Effect qualified as Metrics
import Effectful.OpenTelemetry.Metrics.Gauge qualified as Gauge
import Effectful.OpenTelemetry.Metrics.Instrument (Instrument)
import Effectful.OpenTelemetry.Metrics.Instrument qualified as Instrument
import Effectful.OpenTelemetry.Metrics.Measurement (NumberDataPoint (..))
import Effectful.OpenTelemetry.Metrics.Metadata (Metadata (..))
import Effectful.OpenTelemetry.Timestamp (Timestamp)
import Effectful.OpenTelemetry.Timestamp qualified as Timestamp
import Prelude

-- | An asynchronous 'Instrument' which reports non-additive values when it is observed.
--
-- Example uses for 'ObservableGauge':
--
-- - the current room temperature
-- - the CPU fan speed
--
-- See <https://opentelemetry.io/docs/specs/otel/metrics/api/#asynchronous-gauge the OpenTelemetry spec>.
data ObservableGauge = ObservableGauge
    { name :: Text
    , startTime :: Timestamp
    , metadata :: Metadata
    , observe :: IO (Maybe Scientific)
    }

-- | Create a new 'ObservableGauge' with an observation callback.
new
    :: (Metrics :> es)
    => Text
    -> Metadata
    -> IO (Maybe Scientific)
    -> Eff es ObservableGauge
new name metadata observe =
    Metrics.register =<< unsafeEff_ do
        startTime <- Timestamp.now
        pure ObservableGauge{..}

instance Instrument ObservableGauge where
    name = name
    sample ObservableGauge{..} = do
        time <- Timestamp.now
        values <- maybeToList <$> observe
        pure
            [ (time, Gauge.measurement metadata name NumberDataPoint{attributes = metadata.attributes, ..})
            | value <- values
            ]