servant-prometheus 1.2.0 → 1.3.0
raw patch · 4 files changed
+66/−18 lines, 4 filesdep ~aesondep ~basedep ~containersnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, base, containers, ghc-prim, hashable, http-types, servant, servant-client, servant-server, text, warp
API changes (from Hackage documentation)
- Prometheus.Servant.Internal: instance (GHC.TypeLits.KnownSymbol capture, Prometheus.Servant.Internal.HasEndpoint sub) => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Capture.Capture' mods capture a Servant.API.Sub.:> sub)
- Prometheus.Servant.Internal: instance (GHC.TypeLits.KnownSymbol path, Prometheus.Servant.Internal.HasEndpoint sub) => Prometheus.Servant.Internal.HasEndpoint (path Servant.API.Sub.:> sub)
- Prometheus.Servant.Internal: instance GHC.Generics.Generic Prometheus.Servant.Internal.Endpoint
- Prometheus.Servant.Internal: instance GHC.Show.Show Prometheus.Servant.Internal.Endpoint
- Prometheus.Servant.Internal: instance forall k1 (method :: k1) (status :: GHC.TypeNats.Nat) (cts :: [*]) a. Servant.API.Verbs.ReflectMethod method => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Verbs.Verb method status cts a)
- Prometheus.Servant.Internal: instance forall k1 (method :: k1) (status :: GHC.TypeNats.Nat) framing ct a. Servant.API.Verbs.ReflectMethod method => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Stream.Stream method status framing ct a)
+ Prometheus.Servant.Internal: instance (GHC.Internal.TypeLits.KnownSymbol capture, Prometheus.Servant.Internal.HasEndpoint sub) => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Capture.Capture' mods capture a Servant.API.Sub.:> sub)
+ Prometheus.Servant.Internal: instance (GHC.Internal.TypeLits.KnownSymbol path, Prometheus.Servant.Internal.HasEndpoint sub) => Prometheus.Servant.Internal.HasEndpoint (path Servant.API.Sub.:> sub)
+ Prometheus.Servant.Internal: instance GHC.Internal.Generics.Generic Prometheus.Servant.Internal.Endpoint
+ Prometheus.Servant.Internal: instance GHC.Internal.Show.Show Prometheus.Servant.Internal.Endpoint
+ Prometheus.Servant.Internal: instance Prometheus.Servant.Internal.HasEndpoint Servant.API.Raw.RawM
+ Prometheus.Servant.Internal: instance forall k sub (a :: k). Prometheus.Servant.Internal.HasEndpoint sub => Prometheus.Servant.Internal.HasEndpoint (Servant.API.WithResource.WithResource a Servant.API.Sub.:> sub)
+ Prometheus.Servant.Internal: instance forall k1 (method :: k1) (status :: GHC.Internal.TypeNats.Nat) (cts :: [*]) a. Servant.API.Verbs.ReflectMethod method => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Verbs.Verb method status cts a)
+ Prometheus.Servant.Internal: instance forall k1 (method :: k1) (status :: GHC.Internal.TypeNats.Nat) framing ct a. Servant.API.Verbs.ReflectMethod method => Prometheus.Servant.Internal.HasEndpoint (Servant.API.Stream.Stream method status framing ct a)
- Prometheus.Servant: prometheusMiddleware :: (Label mLatencyLabel, Label mActiveLabel, HasEndpoint api) => Metrics mLatencyLabel mActiveLabel -> Proxy api -> Middleware
+ Prometheus.Servant: prometheusMiddleware :: forall {k} mLatencyLabel mActiveLabel (api :: k). (Label mLatencyLabel, Label mActiveLabel, HasEndpoint api) => Metrics mLatencyLabel mActiveLabel -> Proxy api -> Middleware
- Prometheus.Servant.Internal: class HasEndpoint api
+ Prometheus.Servant.Internal: class HasEndpoint (api :: k)
Files
- CHANGELOG.md +11/−0
- lib/Prometheus/Servant/Internal.hs +20/−1
- servant-prometheus.cabal +18/−14
- test/Prometheus/ServantSpec.hs +17/−3
CHANGELOG.md view
@@ -1,6 +1,17 @@ Unreleased ========== +1.3.0+=======++- Add an `HasEndpoint` instance for `RawM`+- Add an `HasEndpoint` instance for `WithResource`+- Fix `HasEndpoint` instance for `CaptureAll`+ - Previously paths would never be matched since the instance+ did not consume the rest of the path like `CaptureAll` does.+ The rest of the path is now captured and replaced with a `*`+ place holder and this is also the case for enumerating the endpoint.+- Support GHC up to and including 9.12 1.2.0 =======
lib/Prometheus/Servant/Internal.hs view
@@ -225,11 +225,30 @@ enumerateEndpoints _ = [Endpoint [] "RAW"] instance HasEndpoint (sub :: Type) => HasEndpoint (CaptureAll (h :: Symbol) a :> sub) where+ getEndpoint _ req =+ case pathInfo req of+ [] -> Nothing+ _ -> do+ Endpoint{..} <- getEndpoint (Proxy :: Proxy sub) req{pathInfo = []}+ pure $ Endpoint ("*" : ePathSegments) eMethod++ enumerateEndpoints _ = do+ let qualify Endpoint{..} = Endpoint ("*" : ePathSegments) eMethod+ map qualify $ enumerateEndpoints (Proxy :: Proxy sub)++instance HasEndpoint (sub :: Type) => HasEndpoint (BasicAuth (realm :: Symbol) a :> sub) where getEndpoint _ = getEndpoint (Proxy :: Proxy sub) enumerateEndpoints _ = enumerateEndpoints (Proxy :: Proxy sub) -instance HasEndpoint (sub :: Type) => HasEndpoint (BasicAuth (realm :: Symbol) a :> sub) where+#if MIN_VERSION_servant(0,20,0)+instance HasEndpoint (sub :: Type) => HasEndpoint (WithResource a :> sub) where getEndpoint _ = getEndpoint (Proxy :: Proxy sub) enumerateEndpoints _ = enumerateEndpoints (Proxy :: Proxy sub)++instance HasEndpoint RawM where+ getEndpoint _ _ = Just (Endpoint [] "RAW")++ enumerateEndpoints _ = [Endpoint [] "RAW"]+#endif
servant-prometheus.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: servant-prometheus-version: 1.2.0+version: 1.3.0 synopsis: Helpers for using prometheus with servant description: Please see the README on GitHub at <https://github.com/worm2fed/servant-prometheus#readme> category: Servant, Web, System@@ -18,8 +18,11 @@ build-type: Simple tested-with: GHC == 9.2.8- , GHC == 9.4.7 , GHC == 9.4.8+ , GHC == 9.6.7+ , GHC == 9.8.2+ , GHC == 9.10.1+ , GHC == 9.12.1 extra-source-files: README.md LICENSE@@ -49,14 +52,14 @@ UndecidableInstances ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-inferred-safe-imports -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-kind-signatures -Wno-implicit-prelude build-depends:- base >=4.10 && <4.18+ base >=4.10 && <4.22 , clock >=0.8.3 && <0.9- , ghc-prim >=0.8.0 && <0.10- , hashable >=1.4.2 && <1.5+ , ghc-prim >=0.8.0 && <0.14+ , hashable >=1.4.2 && <1.6 , http-types >=0.12.3 && <0.13 , prometheus-client >=1.1.0 && <1.2- , servant >=0.14 && <0.20- , text >=1.2.5 && <2.1+ , servant >=0.14 && <0.21+ , text >=1.2.5 && <2.2 , wai >=3.2.3 && <3.3 default-language: GHC2021 @@ -81,20 +84,21 @@ build-tool-depends: hspec-discover:hspec-discover build-depends:- aeson >=2.0 && <2.2- , base >=4.10 && <4.18- , containers >=0.6.5 && <0.7+ aeson >=2.0 && <2.3+ , base >=4.10 && <4.22+ , containers >=0.6.5 && <0.9 , hspec ==2.* , hspec-expectations-pretty-diff >=0.7.2.2 && <0.8 , http-client >=0.7.13 && <0.8+ , http-types >=0.12.4 && <0.13 , prometheus-client , servant- , servant-client >=0.14 && <0.20+ , servant-client >=0.14 && <0.21 , servant-prometheus- , servant-server >=0.14 && <0.20+ , servant-server >=0.14 && <0.21 , text , wai- , warp >=3.2.4 && <3.4+ , warp >=3.2.4 && <3.5 default-language: GHC2021 benchmark bench@@ -115,7 +119,7 @@ UndecidableInstances ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-inferred-safe-imports -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-kind-signatures -Wno-implicit-prelude -threaded "-with-rtsopts=-N -A64m -AL256m" build-depends:- base >=4.10 && <4.18+ base >=4.10 && <4.22 , process >=1.6.16 && <1.7 , servant-prometheus , servant-server
test/Prometheus/ServantSpec.hs view
@@ -6,11 +6,15 @@ import Data.Text qualified as T import GHC.Generics (Generic) import Network.HTTP.Client (defaultManagerSettings, newManager)+import Network.HTTP.Types.Method (methodGet)+import Network.HTTP.Types.Status (ok200) import Network.Wai (Application)+import Network.Wai qualified as Wai import Network.Wai.Handler.Warp (Port, withApplication) import Prometheus qualified as P import Servant ( Capture+ , CaptureAll , Delete , Get , JSON@@ -18,12 +22,14 @@ , Post , Proxy (..) , QueryParam+ , Raw , ReqBody , Server , serve , (:<|>) (..) , (:>) )+import Servant qualified import Servant.Client ( BaseUrl (..) , ClientError@@ -44,7 +50,7 @@ spec :: Spec spec = describe "servant-prometheus" $ do- let getEp :<|> postEp :<|> deleteEp = client testApi+ let getEp :<|> postEp :<|> deleteEp :<|> proxyEp = client testApi it "collects number of request" $ withApp $ \port -> do@@ -54,6 +60,7 @@ _ <- runFn $ getEp "name" Nothing _ <- runFn $ postEp (Greet "hi") _ <- runFn $ deleteEp "blah"+ _ <- runFn $ proxyEp ["some", "proxy", "route"] methodGet let Metrics{..} = defaultMetrics latencies <- P.getVectorWith mLatency P.getHistogram@@ -61,9 +68,10 @@ `shouldBe` [ ("/greet", "POST", "200") , ("/greet/:greetid", "DELETE", "200") , ("/hello/:name", "GET", "200")+ , ("/proxy/*", "RAW", "200") ] map (sum . map snd . Map.toList . snd) latencies- `shouldBe` [1, 1, 1]+ `shouldBe` [1, 1, 1, 1] it "is comprehensive" $ do let !_typeLevelTest = prometheusMiddleware defaultMetrics comprehensiveAPI@@ -74,6 +82,7 @@ `shouldBe` [ Endpoint ["hello", ":name"] "GET" , Endpoint ["greet"] "POST" , Endpoint ["greet", ":greetid"] "DELETE"+ , Endpoint ["proxy", "*"] "RAW" ] -- * Example@@ -94,6 +103,8 @@ :<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] Greet -- DELETE /greet/:greetid :<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent+ -- GET /proxy/some/proxy/route+ :<|> "proxy" :> CaptureAll "proxyRoute" Text :> Raw testApi :: Proxy TestApi testApi = Proxy@@ -105,7 +116,7 @@ -- -- Each handler runs in the 'EitherT (Int, String) IO' monad. server :: Server TestApi-server = helloH :<|> postGreetH :<|> deleteGreetH+server = helloH :<|> postGreetH :<|> deleteGreetH :<|> proxyH where helloH name Nothing = helloH name (Just False) helloH name (Just False) = pure . Greet $ "Hello, " <> name@@ -114,6 +125,9 @@ postGreetH = pure deleteGreetH _ = pure NoContent++ proxyH :: [Text] -> Servant.Tagged Servant.Handler Wai.Application+ proxyH _ = Servant.Tagged $ \_ responder -> responder $ Wai.responseLBS ok200 [] "success" -- | Turn the server into a WAI app. 'serve' is provided by servant, -- more precisely by the Servant.Server module.