packages feed

wai-middleware-prometheus 1.0.0 → 1.0.0.1

raw patch · 2 files changed

+56/−9 lines, 2 filesdep ~prometheus-client

Dependency ranges changed: prometheus-client

Files

src/Network/Wai/Middleware/Prometheus.hs view
@@ -8,8 +8,11 @@   , PrometheusSettings(..)   , Default.def   , instrumentHandlerValue+  , instrumentHandlerValueWithFilter+  , ignoreRawResponses   , instrumentApp   , instrumentIO+  , observeSeconds   , metricsApp   ) where @@ -21,6 +24,7 @@ import Data.Text.Encoding (decodeUtf8) import qualified Network.HTTP.Types as HTTP import qualified Network.Wai as Wai+import qualified Network.Wai.Internal as Wai (Response(ResponseRaw)) import qualified Prometheus as Prom import System.Clock (Clock(..), TimeSpec, diffTimeSpec, getTime, toNanoSecs) @@ -60,19 +64,55 @@ -- If you use this function you will likely want to override the default value -- of 'prometheusInstrumentApp' to be false so that your app does not get double -- instrumented.+--+-- WARNING: If you have 'ResponseRaw' values in your API, consider using+-- @instrumentHandlerValueWithFilter ignoreRawResponses@ instead. instrumentHandlerValue ::      (Wai.Request -> Text) -- ^ The function used to derive the "handler" value in Prometheus   -> Wai.Application -- ^ The app to instrument   -> Wai.Application -- ^ The instrumented app-instrumentHandlerValue f app req respond = do+instrumentHandlerValue = instrumentHandlerValueWithFilter Just++-- | A more flexible variant of 'instrumentHandlerValue'.  The filter can change some+-- responses, or drop others entirely.+instrumentHandlerValueWithFilter ::+     (Wai.Response -> Maybe Wai.Response) -- ^ Response filter+  -> (Wai.Request -> Text) -- ^ The function used to derive the "handler" value in Prometheus+  -> Wai.Application -- ^ The app to instrument+  -> Wai.Application -- ^ The instrumented app+instrumentHandlerValueWithFilter resFilter f app req respond = do   start <- getTime Monotonic   app req $ \res -> do-    end <- getTime Monotonic-    let method = Just $ decodeUtf8 (Wai.requestMethod req)-    let status = Just $ T.pack (show (HTTP.statusCode (Wai.responseStatus res)))-    observeSeconds (f req) method status start end+    case resFilter res of+      Nothing -> return ()+      Just res' -> do+        end <- getTime Monotonic+        let method = Just $ decodeUtf8 (Wai.requestMethod req)+        let status = Just $ T.pack (show (HTTP.statusCode (Wai.responseStatus res')))+        observeSeconds (f req) method status start end     respond res +-- | 'Wai.ResponseRaw' values have two parts: an action that can be executed to construct a+-- 'Wai.Response', and a pure "backup" 'Wai.Response' in case the computation fails.  Since+-- the pure selectors like 'Wai.responseStatus' are pure and it makes no sense for them to+-- call the action, they just go to the backup response and pull the value from that:+--+-- @+-- responseStatus (ResponseRaw ...+--   (ResponseBuilder (Status 500 "blargh") ... ...))+-- == Status {statusCode = 500, statusMessage = "blargh"}+-- @+--+-- This is often not what you want.  For example, if you have an end-point for establishing+-- websocket connections that has a backup response with status 5xx, every websocket+-- connection request, whether successful or not, will register as an internal server error.+--+-- This helper therefore filters out all raw requests so they won't create any metrics.  Use+-- together with 'instrumentHandlerValueWithFilter'.+ignoreRawResponses :: Wai.Response -> Maybe Wai.Response+ignoreRawResponses (Wai.ResponseRaw {}) = Nothing+ignoreRawResponses res = Just res+ -- | Instrument a WAI app with the default WAI metrics. -- -- If you use this function you will likely want to override the default value@@ -102,9 +142,16 @@     observeSeconds label Nothing Nothing start end     return result -observeSeconds :: Text -> Maybe Text -> Maybe Text -> TimeSpec -> TimeSpec -> IO ()+-- | Record an event to the middleware metric.+observeSeconds :: Text         -- ^ handler label+               -> Maybe Text   -- ^ method+               -> Maybe Text   -- ^ status+               -> TimeSpec     -- ^ start time+               -> TimeSpec     -- ^ end time+               -> IO () observeSeconds handler method status start end = do-    let latency = fromRational $ toRational (toNanoSecs (end `diffTimeSpec` start) % 1000000000)+    let latency :: Double+        latency = fromRational $ toRational (toNanoSecs (end `diffTimeSpec` start) % 1000000000)     Prom.withLabel requestLatency                    (handler, fromMaybe "" method, fromMaybe "" status)                    (flip Prom.observe latency)
wai-middleware-prometheus.cabal view
@@ -1,5 +1,5 @@ name:                wai-middleware-prometheus-version:             1.0.0+version:             1.0.0.1 synopsis:     WAI middlware for exposing http://prometheus.io metrics. description:@@ -29,7 +29,7 @@     , clock     , data-default     , http-types-    , prometheus-client  >=1.0.0 && <1.1+    , prometheus-client  >=1.0.0 && <1.2     , text               >=0.11     , wai                >=3.0   ghc-options: -Wall