@@ -45,24 +45,27 @@ import qualified PostgREST.Unix as Unix (installSignalHandlers)
4545
4646import PostgREST.ApiRequest (Action (.. ), ApiRequest (.. ),
4747 Mutation (.. ), Target (.. ))
48- import PostgREST.AppState (AppState )
48+ import PostgREST.AppState (AppState , getOTelTracer )
4949import PostgREST.Auth (AuthResult (.. ))
5050import PostgREST.Config (AppConfig (.. ))
5151import PostgREST.Config.PgVersion (PgVersion (.. ))
52- import PostgREST.Error (Error )
52+ import PostgREST.Error (Error ( .. ) )
5353import PostgREST.Query (DbHandler )
5454import PostgREST.Response.Performance (ServerTiming (.. ),
5555 serverTimingHeader )
5656import PostgREST.SchemaCache (SchemaCache (.. ))
5757import PostgREST.SchemaCache.Routine (Routine (.. ))
5858import PostgREST.Version (docsVersion , prettyVersion )
5959
60- import qualified Data.ByteString.Char8 as BS
61- import qualified Data.List as L
62- import qualified Network.HTTP.Types as HTTP
63- import qualified Network.Socket as NS
64- import Protolude hiding (Handler )
65- import System.TimeIt (timeItT )
60+ import qualified Data.ByteString.Char8 as BS
61+ import qualified Data.List as L
62+ import qualified Network.HTTP.Types as HTTP
63+ import qualified Network.Socket as NS
64+ import OpenTelemetry.Instrumentation.Wai (newOpenTelemetryWaiMiddleware )
65+ import OpenTelemetry.Trace (defaultSpanArguments )
66+ import OpenTelemetry.Utils.Exceptions (inSpanM )
67+ import Protolude hiding (Handler )
68+ import System.TimeIt (timeItT )
6669
6770type Handler = ExceptT Error
6871
@@ -87,7 +90,9 @@ run appState = do
8790 pure $ " port " <> show port
8891 AppState. logWithZTime appState $ " Listening on " <> what
8992
90- Warp. runSettingsSocket (serverSettings conf) (AppState. getSocketREST appState) app
93+ oTelMWare <- newOpenTelemetryWaiMiddleware
94+
95+ Warp. runSettingsSocket (serverSettings conf) (AppState. getSocketREST appState) (oTelMWare app)
9196
9297serverSettings :: AppConfig -> Warp. Settings
9398serverSettings AppConfig {.. } =
@@ -105,27 +110,28 @@ postgrest conf appState connWorker =
105110 Logger. middleware (configLogLevel conf) $
106111 -- fromJust can be used, because the auth middleware will **always** add
107112 -- some AuthResult to the vault.
108- \ req respond -> case fromJust $ Auth. getResult req of
109- Left err -> respond $ Error. errorResponseFor err
110- Right authResult -> do
111- appConf <- AppState. getConfig appState -- the config must be read again because it can reload
112- maybeSchemaCache <- AppState. getSchemaCache appState
113- pgVer <- AppState. getPgVersion appState
114-
115- let
116- eitherResponse :: IO (Either Error Wai. Response )
117- eitherResponse =
118- runExceptT $ postgrestResponse appState appConf maybeSchemaCache pgVer authResult req
119-
120- response <- either Error. errorResponseFor identity <$> eitherResponse
121- -- Launch the connWorker when the connection is down. The postgrest
122- -- function can respond successfully (with a stale schema cache) before
123- -- the connWorker is done.
124- when (isServiceUnavailable response) connWorker
125- resp <- do
126- delay <- AppState. getRetryNextIn appState
127- return $ addRetryHint delay response
128- respond resp
113+ \ req respond -> inSpanM (getOTelTracer appState) " respond" defaultSpanArguments $
114+ case fromJust $ Auth. getResult req of
115+ Left err -> respond $ Error. errorResponseFor err
116+ Right authResult -> do
117+ appConf <- AppState. getConfig appState -- the config must be read again because it can reload
118+ maybeSchemaCache <- AppState. getSchemaCache appState
119+ pgVer <- AppState. getPgVersion appState
120+
121+ let
122+ eitherResponse :: IO (Either Error Wai. Response )
123+ eitherResponse = inSpanM (getOTelTracer appState) " eitherResponse" defaultSpanArguments $
124+ runExceptT $ postgrestResponse appState appConf maybeSchemaCache pgVer authResult req
125+
126+ response <- either Error. errorResponseFor identity <$> eitherResponse
127+ -- Launch the connWorker when the connection is down. The postgrest
128+ -- function can respond successfully (with a stale schema cache) before
129+ -- the connWorker is done.
130+ when (isServiceUnavailable response) connWorker
131+ resp <- do
132+ delay <- AppState. getRetryNextIn appState
133+ return $ addRetryHint delay response
134+ respond resp
129135
130136postgrestResponse
131137 :: AppState. AppState
@@ -169,54 +175,54 @@ handleRequest :: AuthResult -> AppConfig -> AppState.AppState -> Bool -> Bool ->
169175handleRequest AuthResult {.. } conf appState authenticated prepared pgVer apiReq@ ApiRequest {.. } sCache jwtTime parseTime =
170176 case (iAction, iTarget) of
171177 (ActionRead headersOnly, TargetIdent identifier) -> do
172- (planTime', wrPlan) <- withTiming $ liftEither $ Plan. wrappedReadPlan identifier conf sCache apiReq
173- (txTime', resultSet) <- withTiming $ runQuery roleIsoLvl mempty (Plan. wrTxMode wrPlan) $ Query. readQuery wrPlan conf apiReq
174- (respTime', pgrst) <- withTiming $ liftEither $ Response. readResponse wrPlan headersOnly identifier apiReq resultSet
178+ (planTime', wrPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. wrappedReadPlan identifier conf sCache apiReq
179+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. wrTxMode wrPlan) $ Query. readQuery wrPlan conf apiReq
180+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. readResponse wrPlan headersOnly identifier apiReq resultSet
175181 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
176182
177183 (ActionMutate MutationCreate , TargetIdent identifier) -> do
178- (planTime', mrPlan) <- withTiming $ liftEither $ Plan. mutateReadPlan MutationCreate apiReq identifier conf sCache
179- (txTime', resultSet) <- withTiming $ runQuery roleIsoLvl mempty (Plan. mrTxMode mrPlan) $ Query. createQuery mrPlan apiReq conf
180- (respTime', pgrst) <- withTiming $ liftEither $ Response. createResponse identifier mrPlan apiReq resultSet
184+ (planTime', mrPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. mutateReadPlan MutationCreate apiReq identifier conf sCache
185+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. mrTxMode mrPlan) $ Query. createQuery mrPlan apiReq conf
186+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. createResponse identifier mrPlan apiReq resultSet
181187 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
182188
183189 (ActionMutate MutationUpdate , TargetIdent identifier) -> do
184- (planTime', mrPlan) <- withTiming $ liftEither $ Plan. mutateReadPlan MutationUpdate apiReq identifier conf sCache
185- (txTime', resultSet) <- withTiming $ runQuery roleIsoLvl mempty (Plan. mrTxMode mrPlan) $ Query. updateQuery mrPlan apiReq conf
186- (respTime', pgrst) <- withTiming $ liftEither $ Response. updateResponse mrPlan apiReq resultSet
190+ (planTime', mrPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. mutateReadPlan MutationUpdate apiReq identifier conf sCache
191+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. mrTxMode mrPlan) $ Query. updateQuery mrPlan apiReq conf
192+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. updateResponse mrPlan apiReq resultSet
187193 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
188194
189195 (ActionMutate MutationSingleUpsert , TargetIdent identifier) -> do
190- (planTime', mrPlan) <- withTiming $ liftEither $ Plan. mutateReadPlan MutationSingleUpsert apiReq identifier conf sCache
191- (txTime', resultSet) <- withTiming $ runQuery roleIsoLvl mempty (Plan. mrTxMode mrPlan) $ Query. singleUpsertQuery mrPlan apiReq conf
192- (respTime', pgrst) <- withTiming $ liftEither $ Response. singleUpsertResponse mrPlan apiReq resultSet
196+ (planTime', mrPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. mutateReadPlan MutationSingleUpsert apiReq identifier conf sCache
197+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. mrTxMode mrPlan) $ Query. singleUpsertQuery mrPlan apiReq conf
198+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. singleUpsertResponse mrPlan apiReq resultSet
193199 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
194200
195201 (ActionMutate MutationDelete , TargetIdent identifier) -> do
196- (planTime', mrPlan) <- withTiming $ liftEither $ Plan. mutateReadPlan MutationDelete apiReq identifier conf sCache
197- (txTime', resultSet) <- withTiming $ runQuery roleIsoLvl mempty (Plan. mrTxMode mrPlan) $ Query. deleteQuery mrPlan apiReq conf
198- (respTime', pgrst) <- withTiming $ liftEither $ Response. deleteResponse mrPlan apiReq resultSet
202+ (planTime', mrPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. mutateReadPlan MutationDelete apiReq identifier conf sCache
203+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. mrTxMode mrPlan) $ Query. deleteQuery mrPlan apiReq conf
204+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. deleteResponse mrPlan apiReq resultSet
199205 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
200206
201207 (ActionInvoke invMethod, TargetProc identifier _) -> do
202- (planTime', cPlan) <- withTiming $ liftEither $ Plan. callReadPlan identifier conf sCache apiReq invMethod
203- (txTime', resultSet) <- withTiming $ runQuery (fromMaybe roleIsoLvl $ pdIsoLvl (Plan. crProc cPlan)) (pdFuncSettings $ Plan. crProc cPlan) (Plan. crTxMode cPlan) $ Query. invokeQuery (Plan. crProc cPlan) cPlan apiReq conf pgVer
204- (respTime', pgrst) <- withTiming $ liftEither $ Response. invokeResponse cPlan invMethod (Plan. crProc cPlan) apiReq resultSet
208+ (planTime', cPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. callReadPlan identifier conf sCache apiReq invMethod
209+ (txTime', resultSet) <- withOTel " query " $ withTiming $ runQuery (fromMaybe roleIsoLvl $ pdIsoLvl (Plan. crProc cPlan)) (pdFuncSettings $ Plan. crProc cPlan) (Plan. crTxMode cPlan) $ Query. invokeQuery (Plan. crProc cPlan) cPlan apiReq conf pgVer
210+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. invokeResponse cPlan invMethod (Plan. crProc cPlan) apiReq resultSet
205211 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
206212
207213 (ActionInspect headersOnly, TargetDefaultSpec tSchema) -> do
208- (planTime', iPlan) <- withTiming $ liftEither $ Plan. inspectPlan apiReq
209- (txTime', oaiResult) <- withTiming $ runQuery roleIsoLvl mempty (Plan. ipTxmode iPlan) $ Query. openApiQuery sCache pgVer conf tSchema
210- (respTime', pgrst) <- withTiming $ liftEither $ Response. openApiResponse (T. decodeUtf8 prettyVersion, docsVersion) headersOnly oaiResult conf sCache iSchema iNegotiatedByProfile
214+ (planTime', iPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. inspectPlan apiReq
215+ (txTime', oaiResult) <- withOTel " query " $ withTiming $ runQuery roleIsoLvl [] (Plan. ipTxmode iPlan) $ Query. openApiQuery sCache pgVer conf tSchema
216+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. openApiResponse (T. decodeUtf8 prettyVersion, docsVersion) headersOnly oaiResult conf sCache iSchema iNegotiatedByProfile
211217 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' txTime' respTime') pgrst
212218
213219 (ActionInfo , TargetIdent identifier) -> do
214- (respTime', pgrst) <- withTiming $ liftEither $ Response. infoIdentResponse identifier sCache
220+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. infoIdentResponse identifier sCache
215221 return $ pgrstResponse (ServerTiming jwtTime parseTime Nothing Nothing respTime') pgrst
216222
217223 (ActionInfo , TargetProc identifier _) -> do
218- (planTime', cPlan) <- withTiming $ liftEither $ Plan. callReadPlan identifier conf sCache apiReq ApiRequest. InvHead
219- (respTime', pgrst) <- withTiming $ liftEither $ Response. infoProcResponse (Plan. crProc cPlan)
224+ (planTime', cPlan) <- withOTel " plan " $ withTiming $ liftEither $ Plan. callReadPlan identifier conf sCache apiReq ApiRequest. InvHead
225+ (respTime', pgrst) <- withOTel " response " $ withTiming $ liftEither $ Response. infoProcResponse (Plan. crProc cPlan)
220226 return $ pgrstResponse (ServerTiming jwtTime parseTime planTime' Nothing respTime') pgrst
221227
222228 (ActionInfo , TargetDefaultSpec _) -> do
@@ -241,6 +247,8 @@ handleRequest AuthResult{..} conf appState authenticated prepared pgVer apiReq@A
241247
242248 withTiming = calcTiming $ configServerTimingEnabled conf
243249
250+ withOTel label = inSpanM (getOTelTracer appState) label defaultSpanArguments
251+
244252calcTiming :: Bool -> Handler IO a -> Handler IO (Maybe Double , a )
245253calcTiming timingEnabled f = if timingEnabled
246254 then do
0 commit comments