diff --git a/client/src/utils/GraphQLClient.js b/client/src/utils/GraphQLClient.js index a2b2a01e6..0ec374750 100644 --- a/client/src/utils/GraphQLClient.js +++ b/client/src/utils/GraphQLClient.js @@ -1,11 +1,18 @@ -import { ApolloClient, ApolloLink, InMemoryCache, split } from "@apollo/client"; +import { + ApolloClient, + ApolloLink, + InMemoryCache, + operationName, + split, +} from "@apollo/client"; import { setContext } from "@apollo/client/link/context"; import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http"; import { RetryLink } from "@apollo/client/link/retry"; import { WebSocketLink } from "@apollo/client/link/ws"; +import { getMainDefinition } from "@apollo/client/utilities"; //import { split } from "apollo-link"; import apolloLogger from "apollo-link-logger"; -import { getMainDefinition } from "@apollo/client/utilities"; +import axios from "axios"; import { auth } from "../firebase/firebase.utils"; import errorLink from "../graphql/apollo-error-handling"; @@ -31,6 +38,25 @@ const wsLink = new WebSocketLink({ }, }); +const roundTripLink = new ApolloLink((operation, forward) => { + // Called before operation is sent to server + operation.setContext({ start: new Date() }); + + return forward(operation).map((data) => { + // Called after server responds + const time = new Date() - operation.getContext().start; + console.log( + `Operation ${operation.operationName} took ${time} to complete` + ); + TrackExecutionTime(operation.operationName, time); + return data; + }); +}); + +const TrackExecutionTime = async (operationName, time) => { + await axios.post("/ioevent", { operationName, time, dbevent: true }); +}; + const subscriptionMiddleware = { applyMiddleware: async (options, next) => { options.authToken = @@ -96,7 +122,11 @@ if (process.env.NODE_ENV === "development") { middlewares.push(apolloLogger); } -middlewares.push(retryLink.concat(errorLink.concat(authLink.concat(link)))); +middlewares.push( + roundTripLink.concat( + retryLink.concat(errorLink.concat(authLink.concat(link))) + ) +); const cache = new InMemoryCache({}); diff --git a/hasura/migrations/1619110268248_create_table_public_ioevents/down.yaml b/hasura/migrations/1619110268248_create_table_public_ioevents/down.yaml new file mode 100644 index 000000000..e9d364bb7 --- /dev/null +++ b/hasura/migrations/1619110268248_create_table_public_ioevents/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: DROP TABLE "public"."ioevents"; + type: run_sql diff --git a/hasura/migrations/1619110268248_create_table_public_ioevents/up.yaml b/hasura/migrations/1619110268248_create_table_public_ioevents/up.yaml new file mode 100644 index 000000000..520597ef7 --- /dev/null +++ b/hasura/migrations/1619110268248_create_table_public_ioevents/up.yaml @@ -0,0 +1,11 @@ +- args: + cascade: false + read_only: false + sql: CREATE TABLE "public"."ioevents"("id" bigserial NOT NULL, "created_at" timestamptz + NOT NULL DEFAULT now(), "operationname" text NOT NULL, "time" numeric, PRIMARY + KEY ("id") ); + type: run_sql +- args: + name: ioevents + schema: public + type: add_existing_table_or_view diff --git a/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/down.yaml b/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/down.yaml new file mode 100644 index 000000000..8286fc6c3 --- /dev/null +++ b/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."ioevents" DROP COLUMN "variables"; + type: run_sql diff --git a/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/up.yaml b/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/up.yaml new file mode 100644 index 000000000..43d735ea6 --- /dev/null +++ b/hasura/migrations/1619110302583_alter_table_public_ioevents_add_column_variables/up.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."ioevents" ADD COLUMN "variables" jsonb NULL; + type: run_sql diff --git a/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/down.yaml b/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/down.yaml new file mode 100644 index 000000000..97e3fc2b5 --- /dev/null +++ b/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."ioevents" DROP COLUMN "dbevent"; + type: run_sql diff --git a/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/up.yaml b/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/up.yaml new file mode 100644 index 000000000..43641898b --- /dev/null +++ b/hasura/migrations/1619110334411_alter_table_public_ioevents_add_column_dbevent/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."ioevents" ADD COLUMN "dbevent" Boolean NOT NULL DEFAULT + false; + type: run_sql diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index f46f06d8a..8e50cc15e 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -1814,6 +1814,9 @@ tables: - active: _eq: true allow_aggregations: true +- table: + schema: public + name: ioevents - table: schema: public name: job_conversations diff --git a/server.js b/server.js index 5d4c4e4c1..c0482374c 100644 --- a/server.js +++ b/server.js @@ -136,6 +136,9 @@ app.get("/qbo/callback", qbo.callback); var data = require("./server/data/data"); app.get("/data/ah", data.autohouse); +var ioevent = require("./server/ioevent/ioevent"); +app.post("/ioevent", ioevent.default); + app.get("/", async function (req, res) { res.status(200).send("Access Forbidden."); }); diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index efc09bad1..dfea14c62 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -778,3 +778,10 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT } } `; + +exports.INSERT_IOEVENT = ` mutation INSERT_IOEVENT($event: ioevents_insert_input!) { + insert_ioevents_one(object: $event) { + id + } +} +`; diff --git a/server/ioevent/ioevent.js b/server/ioevent/ioevent.js new file mode 100644 index 000000000..297ea1916 --- /dev/null +++ b/server/ioevent/ioevent.js @@ -0,0 +1,29 @@ +const client = require("../graphql-client/graphql-client").client; +const queries = require("../graphql-client/queries"); +const path = require("path"); + +require("dotenv").config({ + path: path.resolve( + process.cwd(), + `.env.${process.env.NODE_ENV || "development"}` + ), +}); + +exports.default = async (req, res) => { + const { operationName, time, dbevent } = req.body; + + try { + await client.request(queries.INSERT_IOEVENT, { + event: { + operationname: operationName, + time, + dbevent, + }, + }); + + res.sendStatus(200); + } catch (error) { + console.log("error", error); + res.status(400).send(error); + } +};