feature(server): make execution statistics available through logging

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8286
Co-authored-by: Daniel Harvey <4729125+danieljharvey@users.noreply.github.com>
GitOrigin-RevId: 72de592c08778649693d8ff0a0555b16fb28c4bd
This commit is contained in:
Tom Harding 2023-03-14 11:32:20 +00:00 committed by hasura-bot
parent 6ac06561e6
commit 2124fa0f08
21 changed files with 216 additions and 118 deletions

View File

@ -89,7 +89,7 @@ runSQL_ f (BigQueryRunSQL query source) = do
Right recordSet ->
pure
( encJFromJValue
(RunSQLRes "TuplesOk" (f recordSet))
(RunSQLRes "TuplesOk" (f (snd recordSet)))
)
recordSetAsHeaderAndRows :: Execute.RecordSet -> J.Value

View File

@ -15,6 +15,7 @@ module Hasura.Backends.BigQuery.Execute
Execute,
ExecuteProblem (..),
FieldNameText (..),
Job (..),
OutputValue (..),
RecordSet (..),
ShowDetails (..),
@ -246,23 +247,23 @@ bigQueryProjectUrl projectId =
runExecute ::
MonadIO m =>
BigQuerySourceConfig ->
Execute RecordSet ->
m (Either ExecuteProblem RecordSet)
Execute (BigQuery.Job, RecordSet) ->
m (Either ExecuteProblem (BigQuery.Job, RecordSet))
runExecute sourceConfig m =
liftIO
( runExceptT
( runReaderT
(unExecute (m >>= getFinalRecordSet))
(unExecute (m >>= traverse getFinalRecordSet))
(ExecuteReader {sourceConfig})
)
)
executeSelect :: Select -> Execute RecordSet
executeSelect :: Select -> Execute (BigQuery.Job, RecordSet)
executeSelect select = do
conn <- asks (_scConnection . sourceConfig)
recordSet <-
(job, recordSet) <-
streamBigQuery conn (selectToBigQuery select) >>= liftEither
pure recordSet {wantedFields = selectFinalWantedFields select}
pure (job, recordSet {wantedFields = selectFinalWantedFields select})
-- | This is needed to strip out unneeded fields (join keys) in the
-- final query. This is a relic of the data loader approach. A later
@ -384,7 +385,7 @@ valueToBigQueryJson = go
-- response. Until that test has been done, we should consider this a
-- preliminary implementation.
streamBigQuery ::
(MonadIO m) => BigQueryConnection -> BigQuery -> m (Either ExecuteProblem RecordSet)
(MonadIO m) => BigQueryConnection -> BigQuery -> m (Either ExecuteProblem (BigQuery.Job, RecordSet))
streamBigQuery conn bigquery = do
jobResult <- runExceptT $ createQueryJob conn bigquery
case jobResult of
@ -407,7 +408,7 @@ streamBigQuery conn bigquery = do
Just recordSet@RecordSet {rows} ->
(recordSet {rows = rows <> rows'})
case mpageToken' of
Nothing -> pure (Right extendedRecordSet)
Nothing -> pure (Right (job, extendedRecordSet))
Just pageToken' ->
loop (pure pageToken') (pure extendedRecordSet)
Right JobIncomplete {} -> do
@ -488,7 +489,7 @@ data Fetch = Fetch
getJobResults ::
(MonadIO m) =>
BigQueryConnection ->
Job ->
BigQuery.Job ->
Fetch ->
m (Either ExecuteProblem JobResultsResponse)
getJobResults conn Job {jobId, location} Fetch {pageToken} = runExceptT $ do
@ -531,33 +532,6 @@ getJobResults conn Job {jobId, location} Fetch {pageToken} = runExceptT $ do
--------------------------------------------------------------------------------
-- Creating jobs
data Job = Job
{ state :: Text,
jobId :: Text,
location :: Text
}
deriving (Show)
instance Aeson.FromJSON Job where
parseJSON =
Aeson.withObject
"Job"
( \o -> do
kind <- o .: "kind"
if kind == ("bigquery#job" :: Text)
then do
state <- do
status <- o .: "status"
status .: "state"
(jobId, location) <- do
ref <- o .: "jobReference"
-- 'location' is needed in addition to 'jobId' to query a job's
-- status
(,) <$> ref .: "jobId" <*> ref .: "location"
pure Job {state, jobId, location}
else fail ("Invalid kind: " <> show kind)
)
-- | Make a Request return `JSON`
jsonRequestHeader :: Request -> Request
jsonRequestHeader =

View File

@ -84,7 +84,7 @@ bqDBQueryPlan userInfo _env sourceName sourceConfig qrf _ _ = do
(DataLoader.executeSelect select)
case result of
Left err -> throw500WithDetail (DataLoader.executeProblemMessage DataLoader.HideDetails err) $ Aeson.toJSON err
Right recordSet -> pure $! recordSetToEncJSON (BigQuery.selectCardinality select) recordSet
Right (job, recordSet) -> pure ActionResult {arStatistics = Just BigQuery.ExecutionStatistics {_esJob = job}, arResult = recordSetToEncJSON (BigQuery.selectCardinality select) recordSet}
pure $ DBStepInfo @'BigQuery sourceName sourceConfig (Just (selectSQLTextForExplain select)) action ()
-- | Convert the dataloader's 'RecordSet' type to JSON.
@ -161,11 +161,12 @@ bqDBQueryExplain fieldName userInfo sourceName sourceConfig qrf _ _ = do
Nothing
( OnBaseMonad $
pure $
encJFromJValue $
ExplainPlan
fieldName
(Just $ textSQL)
(Just $ T.lines $ textSQL)
withNoStatistics $
encJFromJValue $
ExplainPlan
fieldName
(Just $ textSQL)
(Just $ T.lines $ textSQL)
)
()

View File

@ -9,10 +9,11 @@ import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.GraphQL.Execute.Backend
import Hasura.GraphQL.Logging
( GeneratedQuery (..),
( ExecutionStats (..),
GeneratedQuery (..),
MonadQueryLog (..),
QueryLog (..),
QueryLogKind (QueryLogKindDatabase),
QueryLogKind (QueryLogKindDatabase, QueryLogKindDatabaseResponse),
)
import Hasura.GraphQL.Namespace (RootFieldAlias)
import Hasura.GraphQL.Transport.Backend
@ -20,6 +21,7 @@ import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.SQL.AnyBackend (AnyBackend)
import Hasura.SQL.Backend
import Hasura.Server.Types (RequestId)
import Hasura.Session
@ -45,7 +47,7 @@ runQuery ::
UserInfo ->
L.Logger L.Hasura ->
SourceConfig 'BigQuery ->
OnBaseMonad IdentityT EncJSON ->
OnBaseMonad IdentityT (Maybe (AnyBackend ExecutionStats), EncJSON) ->
Maybe Text ->
ResolvedConnectionTemplate 'BigQuery ->
-- | Also return the time spent in the PG query; for telemetry.
@ -53,8 +55,12 @@ runQuery ::
runQuery reqId query fieldName _userInfo logger _sourceConfig tx genSql _ = do
-- log the generated SQL and the graphql query
-- FIXME: fix logging by making logQueryLog expect something backend agnostic!
logQueryLog logger $ mkQueryLog query fieldName genSql reqId
withElapsedTime $ run tx
logQueryLog logger $ mkQueryLog (QueryLogKindDatabase Nothing) query fieldName genSql reqId Nothing
(diffTime, (stats, result)) <- withElapsedTime $ run tx
logQueryLog logger $ mkQueryLog (QueryLogKindDatabaseResponse Nothing) query fieldName Nothing reqId stats
pure (diffTime, result)
runQueryExplain ::
( MonadIO m,
@ -64,7 +70,7 @@ runQueryExplain ::
) =>
DBStepInfo 'BigQuery ->
m EncJSON
runQueryExplain (DBStepInfo _ _ _ action _) = run action
runQueryExplain (DBStepInfo _ _ _ action _) = fmap arResult (run action)
runMutation ::
( MonadError QErr m
@ -95,14 +101,15 @@ run ::
m a
run = runIdentityT . runOnBaseMonad
-- @QueryLogKindDatabase Nothing@ means that the backend doesn't support connection templates
mkQueryLog ::
QueryLogKind ->
GQLReqUnparsed ->
RootFieldAlias ->
Maybe Text ->
RequestId ->
Maybe (AnyBackend ExecutionStats) ->
QueryLog
mkQueryLog gqlQuery fieldName preparedSql requestId =
-- @QueryLogKindDatabase Nothing@ means that the backend doesn't support connection templates
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase Nothing)
mkQueryLog _qlKind _qlQuery fieldName preparedSql _qlRequestId _qlStatistics = QueryLog {..}
where
generatedQuery = preparedSql <&> \qs -> GeneratedQuery qs J.Null
_qlGeneratedSql = preparedSql <&> \query -> (fieldName, GeneratedQuery query J.Null)

View File

@ -37,6 +37,7 @@ instance Backend 'BigQuery where
type FunctionArgumentExp 'BigQuery = BigQuery.ArgumentExp
type ComputedFieldImplicitArguments 'BigQuery = BigQuery.ComputedFieldImplicitArguments
type ComputedFieldReturn 'BigQuery = BigQuery.ComputedFieldReturn
type ExecutionStatistics 'BigQuery = BigQuery.ExecutionStatistics
type XStreamingSubscription 'BigQuery = XDisable
type XComputedField 'BigQuery = XEnable

View File

@ -15,6 +15,7 @@ module Hasura.Backends.BigQuery.Types
Datetime (..),
Decimal (..),
EntityAlias (..),
ExecutionStatistics (..),
Expression (..),
FieldName (..),
FieldOrigin (..),
@ -23,6 +24,7 @@ module Hasura.Backends.BigQuery.Types
SelectFromFunction (..),
Geography (Geography),
Int64 (Int64),
Job (..),
Join (..),
JoinProvenance (ArrayAggregateJoinProvenance, ArrayJoinProvenance, ObjectJoinProvenance, OrderByJoinProvenance),
JoinSource (..),
@ -94,11 +96,11 @@ import Hasura.Base.Error
import Hasura.Base.ErrorValue qualified as ErrorValue
import Hasura.Base.ToErrorValue
import Hasura.Metadata.DTO.Placeholder (placeholderCodecViaJSON)
import Hasura.Prelude
import Hasura.Prelude hiding (state)
import Hasura.RQL.IR.BoolExp
import Hasura.RQL.Types.Function (FunctionArgName)
import Language.GraphQL.Draft.Syntax qualified as G
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Syntax hiding (location)
import Text.ParserCombinators.ReadP (eof, readP_to_S)
data Select = Select
@ -1115,3 +1117,46 @@ projectionAlias =
EntityProjection a -> pure (aliasedAlias a)
ArrayEntityProjection _ a -> pure (aliasedAlias a)
WindowProjection a -> pure (aliasedAlias a)
data Job = Job
{ state :: Text,
jobId :: Text,
location :: Text
}
deriving (Show)
instance FromJSON Job where
parseJSON =
J.withObject
"Job"
( \o -> do
kind <- o J..: "kind"
if kind == ("bigquery#job" :: Text)
then do
state <- do
status <- o J..: "status"
status J..: "state"
(jobId, location) <- do
ref <- o J..: "jobReference"
-- 'location' is needed in addition to 'jobId' to query a job's
-- status
(,) <$> ref J..: "jobId" <*> ref J..: "location"
pure Job {state, jobId, location}
else fail ("Invalid kind: " <> show kind)
)
instance ToJSON Job where
toJSON Job {..} =
J.object
[ "id" J..= jobId,
"location" J..= location,
"state" J..= state
]
data ExecutionStatistics = ExecutionStatistics
{ _esJob :: Job
}
deriving stock (Generic)
instance ToJSON ExecutionStatistics where
toJSON = J.genericToJSON hasuraJSON

View File

@ -24,7 +24,7 @@ import Hasura.Backends.DataConnector.Plan.QueryPlan qualified as Plan
import Hasura.Backends.DataConnector.Plan.RemoteRelationshipPlan qualified as Plan
import Hasura.Base.Error (Code (..), QErr, throw400, throw400WithDetail)
import Hasura.EncJSON (EncJSON, encJFromBuilder, encJFromJValue)
import Hasura.GraphQL.Execute.Backend (BackendExecute (..), DBStepInfo (..), ExplainPlan (..), OnBaseMonad (..))
import Hasura.GraphQL.Execute.Backend (BackendExecute (..), DBStepInfo (..), ExplainPlan (..), OnBaseMonad (..), withNoStatistics)
import Hasura.GraphQL.Namespace qualified as GQL
import Hasura.Prelude
import Hasura.RQL.Types.Common qualified as RQL
@ -63,7 +63,7 @@ instance BackendExecute 'DataConnector where
{ dbsiSourceName = sourceName,
dbsiSourceConfig = transformedSourceConfig,
dbsiPreparedQuery = Just $ QueryRequest _pRequest,
dbsiAction = OnBaseMonad $ buildQueryAction sourceName transformedSourceConfig queryPlan,
dbsiAction = OnBaseMonad $ fmap withNoStatistics (buildQueryAction sourceName transformedSourceConfig queryPlan),
dbsiResolvedConnectionTemplate = ()
}
@ -76,7 +76,7 @@ instance BackendExecute 'DataConnector where
{ dbsiSourceName = sourceName,
dbsiSourceConfig = transformedSourceConfig,
dbsiPreparedQuery = Just $ QueryRequest _pRequest,
dbsiAction = OnBaseMonad $ buildExplainAction fieldName sourceName transformedSourceConfig queryPlan,
dbsiAction = OnBaseMonad $ fmap withNoStatistics (buildExplainAction fieldName sourceName transformedSourceConfig queryPlan),
dbsiResolvedConnectionTemplate = ()
}
@ -88,7 +88,7 @@ instance BackendExecute 'DataConnector where
{ dbsiSourceName = sourceName,
dbsiSourceConfig = transformedSourceConfig,
dbsiPreparedQuery = Just $ MutationRequest _pRequest,
dbsiAction = OnBaseMonad $ buildMutationAction sourceName transformedSourceConfig mutationPlan,
dbsiAction = OnBaseMonad $ fmap withNoStatistics (buildMutationAction sourceName transformedSourceConfig mutationPlan),
dbsiResolvedConnectionTemplate = ()
}
@ -106,7 +106,7 @@ instance BackendExecute 'DataConnector where
{ dbsiSourceName = sourceName,
dbsiSourceConfig = transformedSourceConfig,
dbsiPreparedQuery = Just $ QueryRequest _pRequest,
dbsiAction = OnBaseMonad $ buildQueryAction sourceName transformedSourceConfig remoteRelationshipPlan,
dbsiAction = OnBaseMonad $ fmap withNoStatistics (buildQueryAction sourceName transformedSourceConfig remoteRelationshipPlan),
dbsiResolvedConnectionTemplate = ()
}

View File

@ -13,7 +13,7 @@ import Hasura.Backends.DataConnector.Adapter.Types (SourceConfig (..))
import Hasura.Backends.DataConnector.Agent.Client (AgentClientContext (..), AgentClientT, runAgentClientT)
import Hasura.Base.Error (QErr)
import Hasura.EncJSON (EncJSON)
import Hasura.GraphQL.Execute.Backend (DBStepInfo (..), OnBaseMonad (..))
import Hasura.GraphQL.Execute.Backend (DBStepInfo (..), OnBaseMonad (..), arResult)
import Hasura.GraphQL.Logging qualified as HGL
import Hasura.GraphQL.Namespace (RootFieldAlias)
import Hasura.GraphQL.Transport.Backend (BackendTransport (..))
@ -21,6 +21,7 @@ import Hasura.GraphQL.Transport.HTTP.Protocol (GQLReqUnparsed)
import Hasura.Logging (Hasura, Logger, nullLogger)
import Hasura.Prelude
import Hasura.RQL.Types.Backend (ResolvedConnectionTemplate)
import Hasura.SQL.AnyBackend (AnyBackend)
import Hasura.SQL.Backend (BackendType (DataConnector))
import Hasura.Server.Types (RequestId)
import Hasura.Session (UserInfo)
@ -50,7 +51,7 @@ runDBQuery' ::
UserInfo ->
Logger Hasura ->
SourceConfig ->
OnBaseMonad AgentClientT a ->
OnBaseMonad AgentClientT (Maybe (AnyBackend HGL.ExecutionStats), a) ->
Maybe DataConnectorPreparedQuery ->
ResolvedConnectionTemplate 'DataConnector ->
m (DiffTime, a)
@ -59,6 +60,7 @@ runDBQuery' requestId query fieldName _userInfo logger SourceConfig {..} action
withElapsedTime
. Tracing.newSpan ("Data Connector backend query for root field " <>> fieldName)
. flip runAgentClientT (AgentClientContext logger _scEndpoint _scManager _scTimeoutMicroseconds)
. fmap snd
. runOnBaseMonad
$ action
@ -75,6 +77,7 @@ mkQueryLog gqlQuery fieldName maybeQuery requestId =
requestId
-- @QueryLogKindDatabase Nothing@ means that the backend doesn't support connection templates
(HGL.QueryLogKindDatabase Nothing)
Nothing
runDBQueryExplain' ::
( MonadIO m,
@ -86,7 +89,7 @@ runDBQueryExplain' ::
m EncJSON
runDBQueryExplain' (DBStepInfo _ SourceConfig {..} _ action _) =
flip runAgentClientT (AgentClientContext nullLogger _scEndpoint _scManager _scTimeoutMicroseconds) $
runOnBaseMonad action
fmap arResult (runOnBaseMonad action)
runDBMutation' ::
( MonadIO m,

View File

@ -107,7 +107,7 @@ msDBQueryPlan userInfo _env sourceName sourceConfig qrf _ _ = do
where
runSelectQuery queryPrinter = OnBaseMonad do
let queryTx = encJFromText <$> Tx.singleRowQueryE defaultMSSQLTxErrorHandler (toQueryFlat queryPrinter)
mssqlRunReadOnly (_mscExecCtx sourceConfig) queryTx
mssqlRunReadOnly (_mscExecCtx sourceConfig) (fmap withNoStatistics queryTx)
runShowplan ::
MonadIO m =>
@ -141,13 +141,13 @@ msDBQueryExplain fieldName userInfo sourceName sourceConfig qrf _ _ = do
(_mscExecCtx sourceConfig)
do
showplan <- runShowplan query
pure
( encJFromJValue $
pure $
withNoStatistics $
encJFromJValue $
ExplainPlan
fieldName
(Just queryString)
(Just showplan)
)
pure $
AB.mkAnyBackend $
DBStepInfo @'MSSQL sourceName sourceConfig Nothing odbcQuery ()
@ -260,7 +260,7 @@ msDBMutationPlan userInfo _environment stringifyNum sourceName sourceConfig mrf
MDBUpdate annUpdate -> executeUpdate userInfo stringifyNum sourceConfig annUpdate
MDBFunction {} -> throw400 NotSupported "function mutations are not supported in MSSQL"
where
go v = DBStepInfo @'MSSQL sourceName sourceConfig Nothing v ()
go v = DBStepInfo @'MSSQL sourceName sourceConfig Nothing (fmap withNoStatistics v) ()
-- * Subscription
@ -459,4 +459,4 @@ msDBRemoteRelationshipPlan _env userInfo sourceName sourceConfig lhs lhsSchema a
where
runSelectQuery queryPrinter = OnBaseMonad do
let queryTx = encJFromText <$> Tx.singleRowQueryE defaultMSSQLTxErrorHandler (toQueryFlat queryPrinter)
mssqlRunReadOnly (_mscExecCtx sourceConfig) queryTx
mssqlRunReadOnly (_mscExecCtx sourceConfig) (fmap withNoStatistics queryTx)

View File

@ -32,6 +32,7 @@ import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.SQL.AnyBackend (AnyBackend)
import Hasura.SQL.Backend
import Hasura.Server.Types (RequestId)
import Hasura.Session
@ -66,7 +67,7 @@ runQuery ::
UserInfo ->
L.Logger L.Hasura ->
SourceConfig 'MSSQL ->
OnBaseMonad (ExceptT QErr) EncJSON ->
OnBaseMonad (ExceptT QErr) (Maybe (AnyBackend ExecutionStats), EncJSON) ->
Maybe (PreparedQuery 'MSSQL) ->
ResolvedConnectionTemplate 'MSSQL ->
-- | Also return the time spent in the PG query; for telemetry.
@ -75,7 +76,7 @@ runQuery reqId query fieldName _userInfo logger _sourceConfig tx genSql _ = do
logQueryLog logger $ mkQueryLog query fieldName genSql reqId
withElapsedTime $
newSpan ("MSSQL Query for root field " <>> fieldName) $
run tx
fmap snd (run tx)
runQueryExplain ::
( MonadIO m,
@ -85,7 +86,7 @@ runQueryExplain ::
) =>
DBStepInfo 'MSSQL ->
m EncJSON
runQueryExplain (DBStepInfo _ _ _ action _) = run action
runQueryExplain (DBStepInfo _ _ _ action _) = fmap arResult (run action)
runMutation ::
( MonadIO m,
@ -157,7 +158,7 @@ mkQueryLog ::
QueryLog
mkQueryLog gqlQuery fieldName preparedSql requestId =
-- @QueryLogKindDatabase Nothing@ means that the backend doesn't support connection templates
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase Nothing)
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase Nothing) Nothing
where
generatedQuery =
preparedSql <&> \queryString ->

View File

@ -73,7 +73,7 @@ mysqlDBQueryPlan userInfo _env sourceName sourceConfig qrf _ _ = do
(DataLoader.execute actionsForest)
either
(throw500WithDetail "MySQL DataLoader Error" . toJSON . show)
(pure . encJFromRecordSet)
(pure . withNoStatistics . encJFromRecordSet)
result
)
()
@ -105,7 +105,7 @@ mysqlDBQueryExplain fieldName userInfo sourceName sourceConfig qrf _ _ = do
fields <- fetchFields result
rows <- fetchAllRows result
let texts = concat $ parseTextRows fields rows
pure $ encJFromJValue $ ExplainPlan fieldName (Just sqlQueryText) (Just texts)
pure $ withNoStatistics $ encJFromJValue $ ExplainPlan fieldName (Just sqlQueryText) (Just texts)
pure $
AB.mkAnyBackend $
DBStepInfo @'MySQL sourceName sourceConfig Nothing explainResult ()

View File

@ -16,6 +16,7 @@ import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.SQL.AnyBackend (AnyBackend)
import Hasura.SQL.Backend
import Hasura.Server.Types (RequestId)
import Hasura.Session
@ -41,7 +42,7 @@ runQuery ::
UserInfo ->
L.Logger L.Hasura ->
SourceConfig 'MySQL ->
OnBaseMonad IdentityT EncJSON ->
OnBaseMonad IdentityT (Maybe (AnyBackend ExecutionStats), EncJSON) ->
Maybe (PreparedQuery 'MySQL) ->
ResolvedConnectionTemplate 'MySQL ->
-- | Also return the time spent in the PG query; for telemetry.
@ -50,7 +51,7 @@ runQuery reqId query fieldName _userInfo logger _sourceConfig tx genSql _ = do
logQueryLog logger $ mkQueryLog query fieldName genSql reqId
withElapsedTime $
newSpan ("MySQL Query for root field " <>> fieldName) $
run tx
fmap snd (run tx)
runQueryExplain ::
( MonadIO m,
@ -60,7 +61,7 @@ runQueryExplain ::
) =>
DBStepInfo 'MySQL ->
m EncJSON
runQueryExplain (DBStepInfo _ _ _ action _) = run action
runQueryExplain (DBStepInfo _ _ _ action _) = fmap arResult (run action)
run :: (MonadIO m, MonadBaseControl IO m, MonadError QErr m, MonadTrace m) => OnBaseMonad IdentityT a -> m a
run = runIdentityT . runOnBaseMonad
@ -73,7 +74,7 @@ mkQueryLog ::
QueryLog
mkQueryLog gqlQuery fieldName preparedSql requestId =
-- @QueryLogKindDatabase Nothing@ means that the backend doesn't support connection templates
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase Nothing)
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase Nothing) Nothing
where
generatedQuery =
preparedSql <&> \queryString ->

View File

@ -50,6 +50,7 @@ import Hasura.GraphQL.Execute.Backend
ExplainPlan (..),
OnBaseMonad (..),
convertRemoteSourceRelationship,
withNoStatistics,
)
import Hasura.GraphQL.Execute.Subscription.Plan
( CohortId,
@ -149,7 +150,8 @@ pgDBQueryPlan userInfo _env sourceName sourceConfig qrf reqHeaders operationName
QueryOperationType G.OperationTypeQuery
let preparedSQLWithQueryTags = appendPreparedSQLWithQueryTags (irToRootFieldPlan planVals preparedQuery) queryTagsComment
let (action, preparedSQL) = mkCurPlanTx userInfo preparedSQLWithQueryTags
pure $ DBStepInfo @('Postgres pgKind) sourceName sourceConfig preparedSQL action resolvedConnectionTemplate
pure $ DBStepInfo @('Postgres pgKind) sourceName sourceConfig preparedSQL (fmap withNoStatistics action) resolvedConnectionTemplate
pgDBQueryExplain ::
forall pgKind m.
@ -174,7 +176,7 @@ pgDBQueryExplain fieldName userInfo sourceName sourceConfig rootSelection reqHea
withExplain = "EXPLAIN " <> textSQL
let action = OnBaseMonad do
PG.withQE dmlTxErrorHandler (PG.fromText withExplain) () True <&> \planList ->
encJFromJValue $ ExplainPlan fieldName (Just textSQL) (Just $ map runIdentity planList)
withNoStatistics $ encJFromJValue $ ExplainPlan fieldName (Just textSQL) (Just $ map runIdentity planList)
resolvedConnectionTemplate <-
applyConnectionTemplateResolverNonAdmin (_pscConnectionTemplateResolver sourceConfig) userInfo reqHeaders $
Just $
@ -326,7 +328,14 @@ pgDBMutationPlan userInfo _environment stringifyNum sourceName sourceConfig mrf
MDBDelete s -> convertDelete userInfo s stringifyNum
MDBFunction returnsSet s -> convertFunction userInfo returnsSet s
where
go resolvedConnectionTemplate v = DBStepInfo @('Postgres pgKind) sourceName sourceConfig Nothing v resolvedConnectionTemplate
go resolvedConnectionTemplate v =
DBStepInfo
{ dbsiSourceName = sourceName,
dbsiSourceConfig = sourceConfig,
dbsiPreparedQuery = Nothing,
dbsiAction = fmap withNoStatistics v,
dbsiResolvedConnectionTemplate = resolvedConnectionTemplate
}
-- subscription

View File

@ -70,7 +70,7 @@ runPGQuery ::
UserInfo ->
L.Logger L.Hasura ->
SourceConfig ('Postgres pgKind) ->
OnBaseMonad (PG.TxET QErr) EncJSON ->
OnBaseMonad (PG.TxET QErr) (Maybe (AB.AnyBackend ExecutionStats), EncJSON) ->
Maybe EQ.PreparedSql ->
ResolvedConnectionTemplate ('Postgres pgKind) ->
-- | Also return the time spent in the PG query; for telemetry.
@ -81,7 +81,7 @@ runPGQuery reqId query fieldName _userInfo logger sourceConfig tx genSql resolve
withElapsedTime $
newSpan ("Postgres Query for root field " <>> fieldName) $
runQueryTx (_pscExecCtx sourceConfig) (GraphQLQuery resolvedConnectionTemplate) $
runOnBaseMonad tx
fmap snd (runOnBaseMonad tx)
runPGMutation ::
( MonadIO m,
@ -145,7 +145,7 @@ runPGQueryExplain ::
m EncJSON
runPGQueryExplain (DBStepInfo _ sourceConfig _ action resolvedConnectionTemplate) =
runQueryTx (_pscExecCtx sourceConfig) (GraphQLQuery resolvedConnectionTemplate) $
runOnBaseMonad action
fmap arResult (runOnBaseMonad action)
mkQueryLog ::
GQLReqUnparsed ->
@ -155,7 +155,7 @@ mkQueryLog ::
Maybe (ResolvedConnectionTemplate ('Postgres pgKind)) ->
QueryLog
mkQueryLog gqlQuery fieldName preparedSql requestId resolvedConnectionTemplate =
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase (mkBackendResolvedConnectionTemplate <$> resolvedConnectionTemplate))
QueryLog gqlQuery ((fieldName,) <$> generatedQuery) requestId (QueryLogKindDatabase (mkBackendResolvedConnectionTemplate <$> resolvedConnectionTemplate)) Nothing
where
mkBackendResolvedConnectionTemplate ::
ResolvedConnectionTemplate ('Postgres pgKind) ->
@ -190,5 +190,6 @@ runPGMutationTransaction reqId query userInfo logger sourceConfig resolvedConnec
runTxWithCtxAndUserInfo userInfo (_pscExecCtx sourceConfig) (Tx PG.ReadWrite Nothing) (GraphQLQuery resolvedConnectionTemplate) $
flip OMap.traverseWithKey mutations \fieldName dbsi ->
newSpan ("Postgres Mutation for root field " <>> fieldName) $
runOnBaseMonad $
dbsiAction dbsi
fmap arResult $
runOnBaseMonad $
dbsiAction dbsi

View File

@ -1,6 +1,8 @@
module Hasura.GraphQL.Execute.Backend
( BackendExecute (..),
DBStepInfo (..),
ActionResult (..),
withNoStatistics,
ExecutionPlan,
ExecutionStep (..),
ExplainPlan (..),
@ -238,10 +240,19 @@ data DBStepInfo b = DBStepInfo
{ dbsiSourceName :: SourceName,
dbsiSourceConfig :: SourceConfig b,
dbsiPreparedQuery :: Maybe (PreparedQuery b),
dbsiAction :: OnBaseMonad (ExecutionMonad b) EncJSON,
dbsiAction :: OnBaseMonad (ExecutionMonad b) (ActionResult b),
dbsiResolvedConnectionTemplate :: ResolvedConnectionTemplate b
}
data ActionResult b = ActionResult
{ arStatistics :: Maybe (ExecutionStatistics b),
arResult :: EncJSON
}
-- | Lift a result from the database into an 'ActionResult'.
withNoStatistics :: EncJSON -> ActionResult b
withNoStatistics arResult = ActionResult {arStatistics = Nothing, arResult}
-- | Provides an abstraction over the base monad in which a computation runs.
--
-- Given a transformer @t@ and a type @a@, @OnBaseMonad t a@ represents a
@ -265,9 +276,12 @@ data DBStepInfo b = DBStepInfo
-- be able to create new spans as part of the execution, and several use
-- @MonadBaseControl IO@ to use 'try' in their error handling.
newtype OnBaseMonad t a = OnBaseMonad
{ runOnBaseMonad :: forall m. (MonadIO m, MonadBaseControl IO m, MonadTrace m, MonadError QErr m) => t m a
{ runOnBaseMonad :: forall m. (Functor (t m), MonadIO m, MonadBaseControl IO m, MonadTrace m, MonadError QErr m) => t m a
}
instance Functor (OnBaseMonad t) where
fmap f (OnBaseMonad xs) = OnBaseMonad (fmap f xs)
-- | The result of an explain query: for a given root field (denoted by its name): the generated SQL
-- query, and the detailed explanation obtained from the database (if any). We mostly use this type
-- as an intermediary step, and immediately tranform any value we obtain into an equivalent JSON

View File

@ -23,7 +23,7 @@ import Hasura.GraphQL.Execute.Instances ()
import Hasura.GraphQL.Execute.RemoteJoin.RemoteSchema qualified as RS
import Hasura.GraphQL.Execute.RemoteJoin.Source qualified as S
import Hasura.GraphQL.Execute.RemoteJoin.Types
import Hasura.GraphQL.Logging (MonadQueryLog)
import Hasura.GraphQL.Logging (MonadQueryLog, statsToAnyBackend)
import Hasura.GraphQL.RemoteServer (execRemoteGQ)
import Hasura.GraphQL.Transport.Backend qualified as TB
import Hasura.GraphQL.Transport.HTTP.Protocol (GQLReqOutgoing, GQLReqUnparsed, _grOperationName, _unOperationName)
@ -103,7 +103,7 @@ processRemoteJoins requestId logger env requestHeaders userInfo lhs maybeJoinTre
userInfo
logger
_sjcSourceConfig
(EB.dbsiAction _sjcStepInfo)
(fmap (statsToAnyBackend @b) (EB.dbsiAction _sjcStepInfo))
(EB.dbsiPreparedQuery _sjcStepInfo)
(EB.dbsiResolvedConnectionTemplate _sjcStepInfo)
pure $ encJToLBS $ snd response

View File

@ -1,8 +1,12 @@
{-# LANGUAGE StandaloneKindSignatures #-}
-- |
-- This module holds functions and data types used for logging at the GraphQL
-- layer. In contrast with, logging at the HTTP server layer.
module Hasura.GraphQL.Logging
( QueryLog (..),
ExecutionStats (..),
statsToAnyBackend,
GeneratedQuery (..),
MonadQueryLog (..),
QueryLogKind (..),
@ -11,12 +15,19 @@ where
import Data.Aeson qualified as J
import Data.HashMap.Strict qualified as Map
import Data.Kind (Type)
import Data.Text.Extended
import Hasura.EncJSON (EncJSON)
import Hasura.GraphQL.Execute.Backend (ActionResult (..))
import Hasura.GraphQL.Namespace (RootFieldAlias)
import Hasura.GraphQL.Transport.HTTP.Protocol (GQLReqUnparsed)
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.DDL.ConnectionTemplate (BackendResolvedConnectionTemplate (..))
import Hasura.RQL.Types.Backend (Backend (ExecutionStatistics))
import Hasura.SQL.AnyBackend (AnyBackend, dispatchAnyBackend', mkAnyBackend)
import Hasura.SQL.Backend (BackendType)
import Hasura.SQL.Tag (HasTag)
import Hasura.Server.Types (RequestId)
import Hasura.Tracing (TraceT)
@ -26,11 +37,28 @@ data QueryLog = QueryLog
{ _qlQuery :: !GQLReqUnparsed,
_qlGeneratedSql :: !(Maybe (RootFieldAlias, GeneratedQuery)),
_qlRequestId :: !RequestId,
_qlKind :: !QueryLogKind
_qlKind :: !QueryLogKind,
_qlStatistics :: !(Maybe (AnyBackend ExecutionStats))
}
-- | 'ExecutionStatistics' is a type family, which means we can't partially
-- apply it (in 'AnyBackend', for example). To get round this, we have a
-- newtype that really just wraps the type family.
type ExecutionStats :: BackendType -> Type
newtype ExecutionStats b = ExecutionStats (ExecutionStatistics b)
-- | When we want to log anything from 'DBStepInfo', we first need to transform
-- the backend-specific execution statistics into 'AnyBackend' statistics. This
-- is fine in practice because all we do with it is log it as JSON.
statsToAnyBackend :: forall b. (HasTag b) => ActionResult b -> (Maybe (AnyBackend ExecutionStats), EncJSON)
statsToAnyBackend ActionResult {..} =
(fmap (mkAnyBackend @b . ExecutionStats) arStatistics, arResult)
deriving newtype instance Backend b => J.ToJSON (ExecutionStats b)
data QueryLogKind
= QueryLogKindDatabase (Maybe (BackendResolvedConnectionTemplate))
| QueryLogKindDatabaseResponse (Maybe (BackendResolvedConnectionTemplate))
| QueryLogKindAction
| QueryLogKindRemoteSchema
| QueryLogKindCached
@ -39,6 +67,7 @@ data QueryLogKind
instance J.ToJSON QueryLogKind where
toJSON = \case
QueryLogKindDatabase _ -> "database"
QueryLogKindDatabaseResponse _ -> "database-response"
QueryLogKindAction -> "action"
QueryLogKindRemoteSchema -> "remote-schema"
QueryLogKindCached -> "cached"
@ -50,13 +79,16 @@ data GeneratedQuery = GeneratedQuery
}
instance J.ToJSON QueryLog where
toJSON (QueryLog gqlQuery generatedQuery reqId kind) =
toJSON (QueryLog gqlQuery generatedQuery reqId kind mstatistics) =
J.object $
[ "query" J..= gqlQuery,
-- NOTE: this customizes the default JSON instance of a pair
"generated_sql" J..= fmap fromPair generatedQuery,
"request_id" J..= reqId,
"kind" J..= kind
"kind" J..= kind,
"statistics" J..= case mstatistics of
Just statistics -> dispatchAnyBackend' @J.ToJSON statistics J.toJSON
Nothing -> J.toJSON ()
]
<> maybe [] (\val -> ["connection_template" J..= val]) (getResolvedConnectionTemplate kind)
where

View File

@ -9,12 +9,13 @@ import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.GraphQL.Execute.Backend
import Hasura.GraphQL.Execute.Subscription.Plan
import Hasura.GraphQL.Logging (MonadQueryLog)
import Hasura.GraphQL.Logging (ExecutionStats, MonadQueryLog)
import Hasura.GraphQL.Namespace (RootFieldAlias)
import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.Types.Backend
import Hasura.SQL.AnyBackend (AnyBackend)
import Hasura.SQL.Backend
import Hasura.Server.Types (RequestId)
import Hasura.Session
@ -37,7 +38,7 @@ class BackendExecute b => BackendTransport (b :: BackendType) where
UserInfo ->
L.Logger L.Hasura ->
SourceConfig b ->
OnBaseMonad (ExecutionMonad b) EncJSON ->
OnBaseMonad (ExecutionMonad b) (Maybe (AnyBackend ExecutionStats), EncJSON) ->
Maybe (PreparedQuery b) ->
ResolvedConnectionTemplate b ->
m (DiffTime, EncJSON)

View File

@ -50,6 +50,7 @@ import Hasura.GraphQL.Logging
( MonadQueryLog (logQueryLog),
QueryLog (..),
QueryLogKind (..),
statsToAnyBackend,
)
import Hasura.GraphQL.Namespace
import Hasura.GraphQL.ParameterizedQueryHash
@ -395,7 +396,7 @@ runGQ env logger reqId userInfo ipAddress reqHeaders queryType reqUnparsed = do
case fmap decodeGQResp cachedValue of
-- If we get a cache hit, annotate the response with metadata and return it.
Just cachedResponseData -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindCached
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindCached Nothing
pure $
AnnotatedResponse
{ arQueryType = Telem.Query,
@ -469,15 +470,15 @@ runGQ env logger reqId userInfo ipAddress reqHeaders queryType reqUnparsed = do
AB.dispatchAnyBackend @BackendTransport
exists
\(EB.DBStepInfo _ sourceConfig genSql tx resolvedConnectionTemplate :: EB.DBStepInfo b) ->
runDBQuery @b reqId reqUnparsed fieldName userInfo logger sourceConfig tx genSql resolvedConnectionTemplate
runDBQuery @b reqId reqUnparsed fieldName userInfo logger sourceConfig (fmap (statsToAnyBackend @b) tx) genSql resolvedConnectionTemplate
finalResponse <-
RJ.processRemoteJoins reqId logger env reqHeaders userInfo resp remoteJoins reqUnparsed
pure $ AnnotatedResponsePart telemTimeIO_DT Telem.Local finalResponse []
E.ExecStepRemote rsi resultCustomizer gqlReq remoteJoins -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindRemoteSchema
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindRemoteSchema Nothing
runRemoteGQ fieldName rsi resultCustomizer gqlReq remoteJoins
E.ExecStepAction aep _ remoteJoins -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindAction
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindAction Nothing
(time, resp) <- doQErr $ do
(time, (resp, _)) <- EA.runActionExecution userInfo aep
finalResponse <-
@ -485,7 +486,7 @@ runGQ env logger reqId userInfo ipAddress reqHeaders queryType reqUnparsed = do
pure (time, finalResponse)
pure $ AnnotatedResponsePart time Telem.Empty resp []
E.ExecStepRaw json -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindIntrospection
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindIntrospection Nothing
buildRaw json
-- For `ExecStepMulti`, execute all steps and then concat them in a list
E.ExecStepMulti lst -> do
@ -502,15 +503,15 @@ runGQ env logger reqId userInfo ipAddress reqHeaders queryType reqUnparsed = do
AB.dispatchAnyBackend @BackendTransport
exists
\(EB.DBStepInfo _ sourceConfig genSql tx resolvedConnectionTemplate :: EB.DBStepInfo b) ->
runDBMutation @b reqId reqUnparsed fieldName userInfo logger sourceConfig tx genSql resolvedConnectionTemplate
runDBMutation @b reqId reqUnparsed fieldName userInfo logger sourceConfig (fmap EB.arResult tx) genSql resolvedConnectionTemplate
finalResponse <-
RJ.processRemoteJoins reqId logger env reqHeaders userInfo resp remoteJoins reqUnparsed
pure $ AnnotatedResponsePart telemTimeIO_DT Telem.Local finalResponse responseHeaders
E.ExecStepRemote rsi resultCustomizer gqlReq remoteJoins -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindRemoteSchema
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindRemoteSchema Nothing
runRemoteGQ fieldName rsi resultCustomizer gqlReq remoteJoins
E.ExecStepAction aep _ remoteJoins -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindAction
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindAction Nothing
(time, (resp, hdrs)) <- doQErr $ do
(time, (resp, hdrs)) <- EA.runActionExecution userInfo aep
finalResponse <-
@ -518,7 +519,7 @@ runGQ env logger reqId userInfo ipAddress reqHeaders queryType reqUnparsed = do
pure (time, (finalResponse, hdrs))
pure $ AnnotatedResponsePart time Telem.Empty resp $ fromMaybe [] hdrs
E.ExecStepRaw json -> do
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindIntrospection
logQueryLog logger $ QueryLog reqUnparsed Nothing reqId QueryLogKindIntrospection Nothing
buildRaw json
-- For `ExecStepMulti`, execute all steps and then concat them in a list
E.ExecStepMulti lst -> do

View File

@ -505,7 +505,7 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
Left _err -> throwError ()
case cachedValue of
Just cachedResponseData -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindCached
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindCached Nothing
let reportedExecutionTime = 0
liftIO $ recordGQLQuerySuccess reportedExecutionTime gqlOpType
sendSuccResp cachedResponseData opName parameterizedQueryHash $ ES.SubscriptionMetadata reportedExecutionTime
@ -526,17 +526,17 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
userInfo
logger
sourceConfig
tx
(fmap (statsToAnyBackend @b) tx)
genSql
resolvedConnectionTemplate
finalResponse <-
RJ.processRemoteJoins requestId logger env reqHdrs userInfo resp remoteJoins q
pure $ AnnotatedResponsePart telemTimeIO_DT Telem.Local finalResponse []
E.ExecStepRemote rsi resultCustomizer gqlReq remoteJoins -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindRemoteSchema
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindRemoteSchema Nothing
runRemoteGQ requestId q fieldName userInfo reqHdrs rsi resultCustomizer gqlReq remoteJoins
E.ExecStepAction actionExecPlan _ remoteJoins -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction Nothing
(time, (resp, _)) <- doQErr $ do
(time, (resp, hdrs)) <- EA.runActionExecution userInfo actionExecPlan
finalResponse <-
@ -544,7 +544,7 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
pure (time, (finalResponse, hdrs))
pure $ AnnotatedResponsePart time Telem.Empty resp []
E.ExecStepRaw json -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindIntrospection
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindIntrospection Nothing
buildRaw json
E.ExecStepMulti lst -> do
allResponses <- traverse getResponse lst
@ -603,14 +603,14 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
userInfo
logger
sourceConfig
tx
(fmap EB.arResult tx)
genSql
resolvedConnectionTemplate
finalResponse <-
RJ.processRemoteJoins requestId logger env reqHdrs userInfo resp remoteJoins q
pure $ AnnotatedResponsePart telemTimeIO_DT Telem.Local finalResponse []
E.ExecStepAction actionExecPlan _ remoteJoins -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction Nothing
(time, (resp, hdrs)) <- doQErr $ do
(time, (resp, hdrs)) <- EA.runActionExecution userInfo actionExecPlan
finalResponse <-
@ -618,10 +618,10 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
pure (time, (finalResponse, hdrs))
pure $ AnnotatedResponsePart time Telem.Empty resp $ fromMaybe [] hdrs
E.ExecStepRemote rsi resultCustomizer gqlReq remoteJoins -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindRemoteSchema
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindRemoteSchema Nothing
runRemoteGQ requestId q fieldName userInfo reqHdrs rsi resultCustomizer gqlReq remoteJoins
E.ExecStepRaw json -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindIntrospection
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindIntrospection Nothing
buildRaw json
E.ExecStepMulti lst -> do
allResponses <- traverse getResponse lst
@ -632,7 +632,7 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
E.SubscriptionExecutionPlan subExec -> do
case subExec of
E.SEAsyncActionsWithNoRelationships actions -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction Nothing
liftIO do
let allActionIds = map fst $ toList actions
case NE.nonEmpty allActionIds of
@ -676,11 +676,11 @@ onStart env enabledLogTypes serverEnv wsConn shouldCaptureVariables (StartMsg op
-- Update async action query subscription state
case NE.nonEmpty (toList actionIds) of
Nothing -> do
logQueryLog logger $ QueryLog q Nothing requestId (QueryLogKindDatabase Nothing)
logQueryLog logger $ QueryLog q Nothing requestId (QueryLogKindDatabase Nothing) Nothing
-- No async action query fields present, do nothing.
pure ()
Just nonEmptyActionIds -> do
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction
logQueryLog logger $ QueryLog q Nothing requestId QueryLogKindAction Nothing
liftIO $ do
let asyncActionQueryLive =
ES.LAAQOnSourceDB $

View File

@ -116,6 +116,7 @@ class
ToJSON (BackendConfig b),
ToJSON (Column b),
ToJSON (ConstraintName b),
ToJSON (ExecutionStatistics b),
ToJSON (FunctionArgument b),
ToJSON (FunctionName b),
ToJSON (ScalarType b),
@ -311,6 +312,12 @@ class
resolveConnectionTemplate :: SourceConfig b -> ConnectionTemplateRequestContext b -> Either QErr EncJSON
resolveConnectionTemplate _ _ = Left (err400 (NotSupported) "connection template is not implemented")
-- | Information about the query execution that may be useful for debugging
-- or reporting.
type ExecutionStatistics b :: Type
type ExecutionStatistics b = ()
-- functions on types
isComparableType :: ScalarType b -> Bool
isNumType :: ScalarType b -> Bool