pro/server: add user_id of the collaborator in http_log

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7154
GitOrigin-RevId: 6f60a7c7be5b083e6adf6c3ab9991142f62434df
This commit is contained in:
Naveen Naidu 2022-12-15 13:18:18 +05:30 committed by hasura-bot
parent f2dd4a5eb7
commit 282e94b2de
8 changed files with 105 additions and 82 deletions

View File

@ -1034,9 +1034,9 @@ instance (MonadIO m) => HttpLog (PGMetadataStorageAppT m) where
emptyExtraHttpLogMetadata = ()
buildExtraHttpLogMetadata _ = ()
buildExtraHttpLogMetadata _ _ = ()
logHttpError logger loggingSettings userInfoM reqId waiReq req qErr headers =
logHttpError logger loggingSettings userInfoM reqId waiReq req qErr headers _ =
unLogger logger $
mkHttpLog $
mkHttpErrorLogContext userInfoM loggingSettings reqId waiReq req qErr Nothing Nothing headers
@ -1052,7 +1052,9 @@ instance (Monad m) => MonadExecuteQuery (PGMetadataStorageAppT m) where
instance (MonadIO m, MonadBaseControl IO m) => UserAuthentication (Tracing.TraceT (PGMetadataStorageAppT m)) where
resolveUserInfo logger manager headers authMode reqs =
runExceptT $ getUserInfoWithExpTime logger manager headers authMode reqs
runExceptT $ do
(a, b, c) <- getUserInfoWithExpTime logger manager headers authMode reqs
pure $ (a, b, c, ExtraUserInfo Nothing)
accessDeniedErrMsg :: Text
accessDeniedErrMsg =

View File

@ -727,7 +727,6 @@ runGQBatched ::
MonadQueryLog m,
MonadTrace m,
MonadExecuteQuery m,
HttpLog m,
MonadMetadataStorage (MetadataStorageT m),
EB.MonadQueryTags m,
HasResourceLimits m
@ -742,13 +741,13 @@ runGQBatched ::
E.GraphQLQueryType ->
-- | the batched request with unparsed GraphQL query
GQLBatchedReqs (GQLReq GQLQueryText) ->
m (HttpLogMetadata m, HttpResponse EncJSON)
m (HttpLogGraphQLInfo, HttpResponse EncJSON)
runGQBatched env logger reqId responseErrorsConfig userInfo ipAddress reqHdrs queryType query =
case query of
GQLSingleRequest req -> do
(gqlQueryOperationLog, httpResp) <- runGQ env logger reqId userInfo ipAddress reqHdrs queryType req
let httpLoggingMetadata = buildHttpLogMetadata @m (PQHSetSingleton (gqolParameterizedQueryHash gqlQueryOperationLog)) L.RequestModeSingle (Just (GQLSingleRequest (GQLQueryOperationSuccess gqlQueryOperationLog)))
pure (httpLoggingMetadata, snd <$> httpResp)
let httpLoggingGQInfo = (CommonHttpLogMetadata L.RequestModeSingle (Just (GQLSingleRequest (GQLQueryOperationSuccess gqlQueryOperationLog))), (PQHSetSingleton (gqolParameterizedQueryHash gqlQueryOperationLog)))
pure (httpLoggingGQInfo, snd <$> httpResp)
GQLBatchedReqs reqs -> do
-- It's unclear what we should do if we receive multiple
-- responses with distinct headers, so just do the simplest thing
@ -771,7 +770,7 @@ runGQBatched env logger reqId responseErrorsConfig userInfo ipAddress reqHdrs qu
)
responses
parameterizedQueryHashes = map gqolParameterizedQueryHash requestsOperationLogs
httpLoggingMetadata = buildHttpLogMetadata @m (PQHSetBatched parameterizedQueryHashes) L.RequestModeBatched (Just (GQLBatchedReqs batchOperationLogs))
pure (httpLoggingMetadata, removeHeaders (map ((fmap snd) . snd) responses))
httpLoggingGQInfo = (CommonHttpLogMetadata L.RequestModeBatched ((Just (GQLBatchedReqs batchOperationLogs))), PQHSetBatched parameterizedQueryHashes)
pure (httpLoggingGQInfo, removeHeaders (map ((fmap snd) . snd) responses))
where
try = flip catchError (pure . Left) . fmap Right

View File

@ -1125,7 +1125,7 @@ onConnInit logger manager wsConn authMode connParamsM onConnInitErrAction keepAl
logWSEvent logger wsConn $ EConnErr connErr
liftIO $ onConnInitErrAction wsConn connErr WS.ConnInitFailed
-- we're ignoring the auth headers as headers are irrelevant in websockets
Right (userInfo, expTimeM, _authHeaders) -> do
Right (userInfo, expTimeM, _authHeaders, _) -> do
let !csInit = CSInitialised $ WsClientState userInfo expTimeM paramHeaders ipAddress
liftIO $ do
$assertNFHere csInit -- so we don't write thunks to mutable vars

View File

@ -156,13 +156,13 @@ data APIResp
-- | API request handlers for different endpoints
data APIHandler m a where
-- | A simple GET request
AHGet :: !(Handler m (HttpLogMetadata m, APIResp)) -> APIHandler m void
AHGet :: !(Handler m (HttpLogGraphQLInfo, APIResp)) -> APIHandler m void
-- | A simple POST request that expects a request body from which an 'a' can be extracted
AHPost :: !(a -> Handler m (HttpLogMetadata m, APIResp)) -> APIHandler m a
AHPost :: !(a -> Handler m (HttpLogGraphQLInfo, APIResp)) -> APIHandler m a
-- | A general GraphQL request (query or mutation) for which the content of the query
-- is made available to the handler for authentication.
-- This is a more specific version of the 'AHPost' constructor.
AHGraphQLRequest :: !(GH.ReqsText -> Handler m (HttpLogMetadata m, APIResp)) -> APIHandler m GH.ReqsText
AHGraphQLRequest :: !(GH.ReqsText -> Handler m (HttpLogGraphQLInfo, APIResp)) -> APIHandler m GH.ReqsText
boolToText :: Bool -> Text
boolToText = bool "false" "true"
@ -171,13 +171,13 @@ isAdminSecretSet :: AuthMode -> Text
isAdminSecretSet AMNoAuth = boolToText False
isAdminSecretSet _ = boolToText True
mkGetHandler :: Handler m (HttpLogMetadata m, APIResp) -> APIHandler m ()
mkGetHandler :: Handler m (HttpLogGraphQLInfo, APIResp) -> APIHandler m ()
mkGetHandler = AHGet
mkPostHandler :: (a -> Handler m (HttpLogMetadata m, APIResp)) -> APIHandler m a
mkPostHandler :: (a -> Handler m (HttpLogGraphQLInfo, APIResp)) -> APIHandler m a
mkPostHandler = AHPost
mkGQLRequestHandler :: (GH.ReqsText -> Handler m (HttpLogMetadata m, APIResp)) -> APIHandler m GH.ReqsText
mkGQLRequestHandler :: (GH.ReqsText -> Handler m (HttpLogGraphQLInfo, APIResp)) -> APIHandler m GH.ReqsText
mkGQLRequestHandler = AHGraphQLRequest
mkAPIRespHandler :: (Functor m) => (a -> Handler m (HttpResponse EncJSON)) -> (a -> Handler m APIResp)
@ -266,7 +266,15 @@ mapActionT ::
mapActionT f tma = MTC.restoreT . pure =<< MTC.liftWith (\run -> f (run tma))
mkSpockAction ::
(MonadIO m, MonadBaseControl IO m, FromJSON a, UserAuthentication (Tracing.TraceT m), HttpLog m, Tracing.HasReporter m, HasResourceLimits m) =>
forall m a.
( MonadIO m,
MonadBaseControl IO m,
FromJSON a,
UserAuthentication (Tracing.TraceT m),
HttpLog m,
Tracing.HasReporter m,
HasResourceLimits m
) =>
ServerCtx ->
-- | `QErr` JSON encoder function
(Bool -> QErr -> Value) ->
@ -288,10 +296,10 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
handlerLimit <- lift askHTTPHandlerLimit
let runTraceT ::
forall m a.
(MonadIO m, Tracing.HasReporter m) =>
Tracing.TraceT m a ->
m a
forall m1 a1.
(MonadIO m1, Tracing.HasReporter m1) =>
Tracing.TraceT m1 a1 ->
m1 a1
runTraceT =
maybe
Tracing.runTraceT
@ -300,22 +308,23 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
(fromString (B8.unpack pathInfo))
runHandler ::
MonadBaseControl IO m =>
MonadBaseControl IO m2 =>
HandlerCtx ->
ReaderT HandlerCtx (MetadataStorageT m) a ->
m (Either QErr a)
ReaderT HandlerCtx (MetadataStorageT m2) a2 ->
m2 (Either QErr a2)
runHandler handlerCtx handler =
runMetadataStorageT $ flip runReaderT handlerCtx $ runResourceLimits handlerLimit $ handler
getInfo parsedRequest = do
authenticationResp <- lift (resolveUserInfo scLogger scManager headers scAuthMode parsedRequest)
authInfo <- onLeft authenticationResp (logErrorAndResp Nothing requestId req (reqBody, Nothing) False origHeaders . qErrModifier)
let (userInfo, _, authHeaders) = authInfo
authInfo <- onLeft authenticationResp (logErrorAndResp Nothing requestId req (reqBody, Nothing) False origHeaders (ExtraUserInfo Nothing) . qErrModifier)
let (userInfo, _, authHeaders, extraUserInfo) = authInfo
pure
( userInfo,
authHeaders,
HandlerCtx serverCtx userInfo headers requestId ipAddress,
shouldIncludeInternal (_uiRole userInfo) scResponseInternalErrorsConfig
shouldIncludeInternal (_uiRole userInfo) scResponseInternalErrorsConfig,
extraUserInfo
)
mapActionT runTraceT $ do
@ -323,31 +332,31 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
-- can correlate requests and traces
lift $ Tracing.attachMetadata [("request_id", unRequestId requestId)]
(serviceTime, (result, userInfo, authHeaders, includeInternal, queryJSON)) <- withElapsedTime $ case apiHandler of
(serviceTime, (result, userInfo, authHeaders, includeInternal, queryJSON, extraUserInfo)) <- withElapsedTime $ case apiHandler of
-- in the case of a simple get/post we don't have to send the webhook anything
AHGet handler -> do
(userInfo, authHeaders, handlerState, includeInternal) <- getInfo Nothing
(userInfo, authHeaders, handlerState, includeInternal, extraUserInfo) <- getInfo Nothing
res <- lift $ runHandler handlerState handler
pure (res, userInfo, authHeaders, includeInternal, Nothing)
pure (res, userInfo, authHeaders, includeInternal, Nothing, extraUserInfo)
AHPost handler -> do
(userInfo, authHeaders, handlerState, includeInternal) <- getInfo Nothing
(userInfo, authHeaders, handlerState, includeInternal, extraUserInfo) <- getInfo Nothing
(queryJSON, parsedReq) <-
runExcept (parseBody reqBody) `onLeft` \e ->
logErrorAndResp (Just userInfo) requestId req (reqBody, Nothing) includeInternal origHeaders $ qErrModifier e
runExcept (parseBody reqBody) `onLeft` \e -> do
logErrorAndResp (Just userInfo) requestId req (reqBody, Nothing) includeInternal origHeaders extraUserInfo (qErrModifier e)
res <- lift $ runHandler handlerState $ handler parsedReq
pure (res, userInfo, authHeaders, includeInternal, Just queryJSON)
pure (res, userInfo, authHeaders, includeInternal, Just queryJSON, extraUserInfo)
-- in this case we parse the request _first_ and then send the request to the webhook for auth
AHGraphQLRequest handler -> do
(queryJSON, parsedReq) <-
runExcept (parseBody reqBody) `onLeft` \e -> do
-- if the request fails to parse, call the webhook without a request body
-- TODO should we signal this to the webhook somehow?
(userInfo, _, _, _) <- getInfo Nothing
logErrorAndResp (Just userInfo) requestId req (reqBody, Nothing) False origHeaders $ qErrModifier e
(userInfo, authHeaders, handlerState, includeInternal) <- getInfo (Just parsedReq)
(userInfo, _, _, _, extraUserInfo) <- getInfo Nothing
logErrorAndResp (Just userInfo) requestId req (reqBody, Nothing) False origHeaders extraUserInfo (qErrModifier e)
(userInfo, authHeaders, handlerState, includeInternal, extraUserInfo) <- getInfo (Just parsedReq)
res <- lift $ runHandler handlerState $ handler parsedReq
pure (res, userInfo, authHeaders, includeInternal, Just queryJSON)
pure (res, userInfo, authHeaders, includeInternal, Just queryJSON, extraUserInfo)
-- apply the error modifier
let modResult = fmapL qErrModifier result
@ -355,22 +364,26 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
-- log and return result
case modResult of
Left err ->
logErrorAndResp (Just userInfo) requestId req (reqBody, queryJSON) includeInternal headers err
Right (httpLoggingMetadata, res) ->
logSuccessAndResp (Just userInfo) requestId req (reqBody, queryJSON) res (Just (ioWaitTime, serviceTime)) origHeaders authHeaders httpLoggingMetadata
logErrorAndResp (Just userInfo) requestId req (reqBody, queryJSON) includeInternal headers extraUserInfo err
Right (httpLogGraphQLInfo, res) -> do
let httpLogMetadata = buildHttpLogMetadata @m httpLogGraphQLInfo extraUserInfo
logSuccessAndResp (Just userInfo) requestId req (reqBody, queryJSON) res (Just (ioWaitTime, serviceTime)) origHeaders authHeaders httpLogMetadata
where
logErrorAndResp ::
(MonadIO m, HttpLog m) =>
forall m3 a3 ctx.
(MonadIO m3, HttpLog m3) =>
Maybe UserInfo ->
RequestId ->
Wai.Request ->
(BL.ByteString, Maybe Value) ->
Bool ->
[HTTP.Header] ->
ExtraUserInfo ->
QErr ->
Spock.ActionCtxT ctx m a
logErrorAndResp userInfo reqId waiReq req includeInternal headers qErr = do
lift $ logHttpError scLogger scLoggingSettings userInfo reqId waiReq req qErr headers
Spock.ActionCtxT ctx m3 a3
logErrorAndResp userInfo reqId waiReq req includeInternal headers extraUserInfo qErr = do
let httpLogMetadata = buildHttpLogMetadata @m3 emptyHttpLogGraphQLInfo extraUserInfo
lift $ logHttpError scLogger scLoggingSettings userInfo reqId waiReq req qErr headers httpLogMetadata
Spock.setStatus $ qeStatus qErr
Spock.json $ qErrEncoder includeInternal qErr
@ -551,14 +564,13 @@ v1Alpha1GQHandler ::
GH.MonadExecuteQuery m,
MonadError QErr m,
MonadReader HandlerCtx m,
HttpLog m,
MonadMetadataStorage (MetadataStorageT m),
EB.MonadQueryTags m,
HasResourceLimits m
) =>
E.GraphQLQueryType ->
GH.GQLBatchedReqs (GH.GQLReq GH.GQLQueryText) ->
m (HttpLogMetadata m, HttpResponse EncJSON)
m (HttpLogGraphQLInfo, HttpResponse EncJSON)
v1Alpha1GQHandler queryType query = do
userInfo <- asks hcUser
reqHeaders <- asks hcReqHeaders
@ -596,7 +608,6 @@ v1GQHandler ::
MonadQueryLog m,
Tracing.MonadTrace m,
GH.MonadExecuteQuery m,
HttpLog m,
MonadError QErr m,
MonadReader HandlerCtx m,
MonadMetadataStorage (MetadataStorageT m),
@ -604,7 +615,7 @@ v1GQHandler ::
HasResourceLimits m
) =>
GH.GQLBatchedReqs (GH.GQLReq GH.GQLQueryText) ->
m (HttpLogMetadata m, HttpResponse EncJSON)
m (HttpLogGraphQLInfo, HttpResponse EncJSON)
v1GQHandler = v1Alpha1GQHandler E.QueryHasura
v1GQRelayHandler ::
@ -613,7 +624,6 @@ v1GQRelayHandler ::
E.MonadGQLExecutionCheck m,
MonadQueryLog m,
Tracing.MonadTrace m,
HttpLog m,
GH.MonadExecuteQuery m,
MonadError QErr m,
MonadReader HandlerCtx m,
@ -622,7 +632,7 @@ v1GQRelayHandler ::
HasResourceLimits m
) =>
GH.GQLBatchedReqs (GH.GQLReq GH.GQLQueryText) ->
m (HttpLogMetadata m, HttpResponse EncJSON)
m (HttpLogGraphQLInfo, HttpResponse EncJSON)
v1GQRelayHandler = v1Alpha1GQHandler E.QueryRelay
gqlExplainHandler ::
@ -730,7 +740,7 @@ configApiGetHandler serverCtx@ServerCtx {..} consoleAssetsDir =
scExperimentalFeatures
scEnabledAPIs
scDefaultNamingConvention
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue res) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue res) [])
data HasuraApp = HasuraApp
{ _hapApplication :: !Wai.Application,
@ -990,12 +1000,11 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
MonadQueryLog n,
GH.MonadExecuteQuery n,
MonadMetadataStorage (MetadataStorageT n),
HttpLog n,
EB.MonadQueryTags n,
HasResourceLimits n
) =>
RestRequest Spock.SpockMethod ->
Handler (Tracing.TraceT n) (HttpLogMetadata n, APIResp)
Handler (Tracing.TraceT n) (HttpLogGraphQLInfo, APIResp)
customEndpointHandler restReq = do
scRef <- asks (scCacheRef . hcServerCtx)
endpoints <- liftIO $ scEndpoints <$> getSchemaCache scRef
@ -1043,23 +1052,23 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
Spock.post "v1/query" $
spockAction encodeQErr id $ do
mkPostHandler $ fmap (emptyHttpLogMetadata @m,) <$> mkAPIRespHandler v1QueryHandler
mkPostHandler $ fmap (emptyHttpLogGraphQLInfo,) <$> mkAPIRespHandler v1QueryHandler
Spock.post "v1/metadata" $
spockAction encodeQErr id $
mkPostHandler $
fmap (emptyHttpLogMetadata @m,) <$> mkAPIRespHandler v1MetadataHandler
fmap (emptyHttpLogGraphQLInfo,) <$> mkAPIRespHandler v1MetadataHandler
Spock.post "v2/query" $
spockAction encodeQErr id $
mkPostHandler $
fmap (emptyHttpLogMetadata @m,) <$> mkAPIRespHandler v2QueryHandler
fmap (emptyHttpLogGraphQLInfo,) <$> mkAPIRespHandler v2QueryHandler
when enablePGDump $
Spock.post "v1alpha1/pg_dump" $
spockAction encodeQErr id $
mkPostHandler $
fmap (emptyHttpLogMetadata @m,) <$> v1Alpha1PGDumpHandler
fmap (emptyHttpLogGraphQLInfo,) <$> v1Alpha1PGDumpHandler
when enableConfig $ runConfigApiHandler serverCtx consoleAssetsDir
@ -1099,38 +1108,38 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
mkGetHandler $ do
onlyAdmin
respJ <- liftIO $ EKG.sampleAll $ scEkgStore serverCtx
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue $ EKG.sampleToJson respJ) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue $ EKG.sampleToJson respJ) [])
-- This deprecated endpoint used to show the query plan cache pre-PDV.
-- Eventually this endpoint can be removed.
Spock.get "dev/plan_cache" $
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue J.Null) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue J.Null) [])
Spock.get "dev/subscriptions" $
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
respJ <- liftIO $ ES.dumpSubscriptionsState False $ scSubscriptionState serverCtx
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue respJ) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue respJ) [])
Spock.get "dev/subscriptions/extended" $
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
respJ <- liftIO $ ES.dumpSubscriptionsState True $ scSubscriptionState serverCtx
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue respJ) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue respJ) [])
Spock.get "dev/dataconnector/schema" $
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue openApiSchema) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue openApiSchema) [])
Spock.get "api/swagger/json" $
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
sc <- liftIO $ getSchemaCache $ scCacheRef serverCtx
json <- buildOpenAPI sc
return (emptyHttpLogMetadata @m, JSONResp $ HttpResponse (encJFromJValue json) [])
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue json) [])
forM_ [Spock.GET, Spock.POST] $ \m -> Spock.hookAny m $ \_ -> do
req <- Spock.request
@ -1155,7 +1164,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
let headers = Wai.requestHeaders req
(reqId, _newHeaders) <- getRequestId headers
lift $
logHttpError logger (scLoggingSettings serverCtx) Nothing reqId req (reqBody, Nothing) err headers
logHttpError logger (scLoggingSettings serverCtx) Nothing reqId req (reqBody, Nothing) err headers (emptyHttpLogMetadata @m)
spockAction ::
forall a n.
@ -1171,7 +1180,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
gqlExplainAction = do
spockAction encodeQErr id $
mkPostHandler $
fmap (emptyHttpLogMetadata @m,) <$> mkAPIRespHandler gqlExplainHandler
fmap (emptyHttpLogGraphQLInfo,) <$> mkAPIRespHandler gqlExplainHandler
enableGraphQL = isGraphQLEnabled serverCtx
enableMetadata = isMetadataEnabled serverCtx
enablePGDump = isPGDumpEnabled serverCtx
@ -1195,6 +1204,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
either (raiseGenericApiError logger (scLoggingSettings serverCtx) headers . internalError . T.pack) Spock.html consoleHtml
raiseGenericApiError ::
forall m.
(MonadIO m, HttpLog m) =>
L.Logger L.Hasura ->
LoggingSettings ->
@ -1205,7 +1215,7 @@ raiseGenericApiError logger loggingSetting headers qErr = do
req <- Spock.request
reqBody <- liftIO $ Wai.strictRequestBody req
(reqId, _newHeaders) <- getRequestId $ Wai.requestHeaders req
lift $ logHttpError logger loggingSetting Nothing reqId req (reqBody, Nothing) qErr headers
lift $ logHttpError logger loggingSetting Nothing reqId req (reqBody, Nothing) qErr headers (emptyHttpLogMetadata @m)
setHeader jsonHeader
Spock.setStatus $ qeStatus qErr
Spock.lazyBytes $ encode qErr

View File

@ -60,7 +60,7 @@ class (Monad m) => UserAuthentication m where
[HTTP.Header] ->
AuthMode ->
Maybe ReqsText ->
m (Either QErr (UserInfo, Maybe UTCTime, [HTTP.Header]))
m (Either QErr (UserInfo, Maybe UTCTime, [HTTP.Header], ExtraUserInfo))
-- | The hashed admin password. 'hashAdminSecret' is our public interface for
-- constructing the secret.

View File

@ -30,6 +30,8 @@ module Hasura.Server.Logging
LoggingSettings (..),
SchemaSyncThreadType (..),
SchemaSyncLog (..),
HttpLogGraphQLInfo,
emptyHttpLogGraphQLInfo,
)
where
@ -204,6 +206,13 @@ data CommonHttpLogMetadata = CommonHttpLogMetadata
}
deriving (Eq)
-- The information from the GraphQL layer that needs to be included in the http-log.
-- This info is used to construct 'HttpLogMetadata m'
type HttpLogGraphQLInfo = (CommonHttpLogMetadata, ParameterizedQueryHashList)
emptyHttpLogGraphQLInfo :: HttpLogGraphQLInfo
emptyHttpLogGraphQLInfo = (CommonHttpLogMetadata RequestModeNonBatchable Nothing, PQHSetEmpty)
-- | The http-log metadata attached to HTTP requests running in the monad 'm', split into a
-- common portion that is present regardless of 'm', and a monad-specific one defined in the
-- 'HttpLog' instance.
@ -215,12 +224,11 @@ type HttpLogMetadata m = (CommonHttpLogMetadata, ExtraHttpLogMetadata m)
buildHttpLogMetadata ::
forall m.
HttpLog m =>
ParameterizedQueryHashList ->
RequestMode ->
Maybe (GH.GQLBatchedReqs GQLBatchQueryOperationLog) ->
HttpLogGraphQLInfo ->
ExtraUserInfo ->
HttpLogMetadata m
buildHttpLogMetadata paramQueryHashList requestMode batchQueryOperationLog =
(CommonHttpLogMetadata requestMode batchQueryOperationLog, buildExtraHttpLogMetadata @m paramQueryHashList)
buildHttpLogMetadata (commonHttpLogMetadata, paramQueryHashList) extraUserInfo =
(commonHttpLogMetadata, buildExtraHttpLogMetadata @m paramQueryHashList extraUserInfo)
-- | synonym for clarity, writing `emptyHttpLogMetadata @m` instead of `def @(HttpLogMetadata m)`
emptyHttpLogMetadata :: forall m. HttpLog m => HttpLogMetadata m
@ -276,7 +284,7 @@ class Monad m => HttpLog m where
emptyExtraHttpLogMetadata :: ExtraHttpLogMetadata m
buildExtraHttpLogMetadata :: ParameterizedQueryHashList -> ExtraHttpLogMetadata m
buildExtraHttpLogMetadata :: ParameterizedQueryHashList -> ExtraUserInfo -> ExtraHttpLogMetadata m
logHttpError ::
-- | the logger
@ -295,6 +303,7 @@ class Monad m => HttpLog m where
QErr ->
-- | list of request headers
[HTTP.Header] ->
HttpLogMetadata m ->
m ()
logHttpSuccess ::
@ -330,7 +339,7 @@ instance HttpLog m => HttpLog (TraceT m) where
buildExtraHttpLogMetadata a = buildExtraHttpLogMetadata @m a
emptyExtraHttpLogMetadata = emptyExtraHttpLogMetadata @m
logHttpError a b c d e f g h = lift $ logHttpError a b c d e f g h
logHttpError a b c d e f g h i = lift $ logHttpError a b c d e f g h i
logHttpSuccess a b c d e f g h i j k l = lift $ logHttpSuccess a b c d e f g h i j k l
@ -340,7 +349,7 @@ instance HttpLog m => HttpLog (ReaderT r m) where
buildExtraHttpLogMetadata a = buildExtraHttpLogMetadata @m a
emptyExtraHttpLogMetadata = emptyExtraHttpLogMetadata @m
logHttpError a b c d e f g h = lift $ logHttpError a b c d e f g h
logHttpError a b c d e f g h i = lift $ logHttpError a b c d e f g h i
logHttpSuccess a b c d e f g h i j k l = lift $ logHttpSuccess a b c d e f g h i j k l
@ -350,7 +359,7 @@ instance HttpLog m => HttpLog (MetadataStorageT m) where
buildExtraHttpLogMetadata a = buildExtraHttpLogMetadata @m a
emptyExtraHttpLogMetadata = emptyExtraHttpLogMetadata @m
logHttpError a b c d e f g h = lift $ logHttpError a b c d e f g h
logHttpError a b c d e f g h i = lift $ logHttpError a b c d e f g h i
logHttpSuccess a b c d e f g h i j k l = lift $ logHttpSuccess a b c d e f g h i j k l

View File

@ -99,7 +99,6 @@ runCustomEndpoint ::
MonadQueryLog m,
GH.MonadExecuteQuery m,
MonadMetadataStorage (MetadataStorageT m),
HttpLog m,
EB.MonadQueryTags m,
HasResourceLimits m
) =>
@ -111,7 +110,7 @@ runCustomEndpoint ::
Wai.IpAddress ->
RestRequest EndpointMethod ->
EndpointTrie GQLQueryWithText ->
m (HttpLogMetadata m, HttpResponse EncJSON)
m (HttpLogGraphQLInfo, HttpResponse EncJSON)
runCustomEndpoint env execCtx requestId userInfo reqHeaders ipAddress RestRequest {..} endpoints = do
-- First match the path to an endpoint.
case matchPath reqMethod (T.split (== '/') reqPath) endpoints of
@ -143,9 +142,8 @@ runCustomEndpoint env execCtx requestId userInfo reqHeaders ipAddress RestReques
-- through to the /v1/graphql endpoint.
(httpLoggingMetadata, handlerResp) <- flip runReaderT execCtx $ do
(gqlOperationLog, resp) <- GH.runGQ env (E._ecxLogger execCtx) requestId userInfo ipAddress reqHeaders E.QueryHasura (mkPassthroughRequest queryx resolvedVariables)
let httpLogMetadata =
buildHttpLogMetadata @m (PQHSetSingleton (gqolParameterizedQueryHash gqlOperationLog)) RequestModeNonBatchable Nothing
return (httpLogMetadata, fst <$> resp)
let httpLoggingGQInfo = (CommonHttpLogMetadata RequestModeNonBatchable Nothing, (PQHSetSingleton (gqolParameterizedQueryHash gqlOperationLog)))
return (httpLoggingGQInfo, fst <$> resp)
case sequence handlerResp of
Just resp -> pure (httpLoggingMetadata, fmap encodeHTTPResp resp)
-- a Nothing value here indicates a failure to parse the cached request from redis.

View File

@ -25,6 +25,7 @@ module Hasura.Session
mkUserInfo,
adminUserInfo,
BackendOnlyFieldAccess (..),
ExtraUserInfo (..),
)
where
@ -202,6 +203,10 @@ instance (UserInfoM m) => UserInfoM (StateT s m) where
instance (UserInfoM m) => UserInfoM (TraceT m) where
askUserInfo = lift askUserInfo
-- | extra information used to identify a Hasura User
data ExtraUserInfo = ExtraUserInfo {_euiUserId :: Maybe Text}
deriving (Show, Eq, Generic)
askCurRole :: (UserInfoM m) => m RoleName
askCurRole = _uiRole <$> askUserInfo