packages feed

atelier-core-0.1.0.0: src/Atelier/Effects/Monitoring/Metrics/Server.hs

-- | Effect for running the Prometheus metrics HTTP server.
--
-- Wraps a Warp server that exposes the current metrics registry over HTTP, so
-- callers start it through the effect system rather than raw 'IO'.
module Atelier.Effects.Monitoring.Metrics.Server
    ( -- * Effect
      MetricsServer

      -- * Operations
    , runMetricsServer

      -- * Interpreters
    , runMetricsServerIO
    ) where

import Effectful (Effect, IOE)
import Effectful.Dispatch.Dynamic (interpret_)
import Effectful.TH (makeEffect)
import Network.HTTP.Types (status200)
import Network.Wai (Application, responseLBS)

import Network.Wai.Handler.Warp qualified as Warp
import Prometheus qualified as Prom


-- | Running the Prometheus metrics HTTP server.
data MetricsServer :: Effect where
    -- | Start an HTTP server that exposes Prometheus metrics at any path on the
    -- given port. Blocks until the server stops, which normally only happens on
    -- error; intended to be run in a background thread.
    RunMetricsServer :: Int -> MetricsServer m ()


makeEffect ''MetricsServer


-- | Interpret 'MetricsServer' by running a real Warp HTTP server.
runMetricsServerIO :: (IOE :> es) => Eff (MetricsServer : es) a -> Eff es a
runMetricsServerIO = interpret_ \case
    RunMetricsServer port -> liftIO $ Warp.run port metricsApp


metricsApp :: Application
metricsApp _req respond = do
    payload <- Prom.exportMetricsAsText
    respond
        $ responseLBS
            status200
            [("Content-Type", "text/plain; version=0.0.4; charset=utf-8")]
            payload