├── .gitignore ├── README.md ├── bin ├── client │ ├── dist │ │ └── index.html │ ├── get-data.js │ ├── index.html │ └── src │ │ ├── PageInterface.ts │ │ ├── components │ │ ├── App.css │ │ ├── App.tsx │ │ ├── Data.tsx │ │ ├── Header.css │ │ ├── Header.tsx │ │ ├── Main.css │ │ ├── Main.tsx │ │ ├── Mutations.css │ │ ├── Mutations.tsx │ │ ├── Overview.css │ │ ├── Overview.tsx │ │ ├── Queries.css │ │ ├── Queries.tsx │ │ ├── Resolvers.css │ │ └── Resolvers.tsx │ │ ├── index.css │ │ ├── index.html │ │ └── index.tsx ├── db │ ├── data.json │ ├── err.json │ └── fileController.js ├── exec.js ├── goblin.js └── server │ ├── express.js │ └── wsServer.js ├── package-lock.json ├── package.json ├── src ├── enableTracking.js ├── grabFields.js ├── main.js └── mapResolvers.js ├── test ├── enableMonitoring.test.js └── enableTracking.test.js ├── testResolvers └── mockResolvers.js ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # goblinsharks 2 | la30-goblinsharks production project repository 3 | -------------------------------------------------------------------------------- /bin/client/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /bin/client/get-data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | // connection.addEventListener('open',()=>{ 7 | // console.log('websocket connection established to port 9000'); 8 | // }) 9 | 10 | // connection.addEventListener('message',(e) => { 11 | // console.log('message received through socket connection') 12 | // console.log(e) 13 | // }) 14 | 15 | const connection = new WebSocket('ws://localhost:9000'); 16 | connection.onopen = () => { 17 | console.log("socket is open on port 9000") 18 | connection.onmessage = (message) => { 19 | console.log(message); 20 | console.log('socket server message: ' + (message.data)); 21 | 22 | fetch('./db/data.json') 23 | .then((data)=>data.json()) 24 | .then((res)=>{ 25 | console.log(res); 26 | }) 27 | } 28 | } 29 | 30 | 31 | window.onload = () => { 32 | console.log(data) 33 | fetch('../db/data.json') 34 | .then((data)=>data.json()) 35 | .then((res)=>{ 36 | const vals = Object.values(res); 37 | vals.forEach((value)=>{ 38 | document.querySelector('#data').append(`${JSON.stringify(value)}`); 39 | }) 40 | }) 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /bin/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /bin/client/src/PageInterface.ts: -------------------------------------------------------------------------------- 1 | export default interface Page { 2 | color: string; 3 | } 4 | -------------------------------------------------------------------------------- /bin/client/src/components/App.css: -------------------------------------------------------------------------------- 1 | #modeWrapper { 2 | display: flex; 3 | justify-content: center; 4 | }; -------------------------------------------------------------------------------- /bin/client/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | // src/components/App.tsx 2 | import * as React from 'react'; 3 | import { useState, useEffect } from 'react'; 4 | 5 | // Components. 6 | import Header from './Header'; 7 | import Overview from './Overview'; 8 | import Queries from './Queries'; 9 | import Mutations from './Mutations'; 10 | import Resolvers from './Resolvers'; 11 | 12 | // Style. 13 | import "./App.css"; 14 | 15 | // TODO: Make this responsive to changes. 16 | import { processedData, getOverviewData, getResolversData } from './Data'; 17 | 18 | // Renders App. 19 | const App = () => { 20 | // An array of Modes. 21 | const [ data, updateData ] = useState(processedData); 22 | 23 | // This establishes socket connection. Invokes once. 24 | useEffect(() => { 25 | // Connection. 26 | const connection = new WebSocket('ws://localhost:9000'); 27 | 28 | // On open connection, update data. 29 | connection.onopen = () => { 30 | console.log("socket is open on port 9000") 31 | fetch('./db/data.json') 32 | .then(data => data.json()) 33 | .then(res => updateData({ overview: getOverviewData(res), resolvers: getResolversData(res) })) 34 | .catch(e => console.log('error fetching from json', e)) 35 | 36 | // On message listener. Updates data according to message body. 37 | connection.onmessage = (message) => { 38 | console.log('socket server message: ' + (message.data)); 39 | 40 | fetch('./db/data.json') 41 | .then(data => data.json()) 42 | .then(res => updateData({ overview: getOverviewData(res), resolvers: getResolversData(res) })) 43 | .catch(e => console.log('error fetching from json', e)) 44 | } 45 | } 46 | }, []) 47 | 48 | // Hook to update the current mode. 49 | const [currentMode, updateMode] = useState('overview'); 50 | 51 | // useEffect hook to change the css styling of the active mode. 52 | useEffect(() => { 53 | // Remove 'active' from class names. 54 | Array.from(document.getElementsByClassName("header-navigation-item")) 55 | .forEach(el => el.classList.remove('active')); 56 | // Add 'active' to the current Mode css. 57 | document.getElementById("header-navigation-item-" + currentMode)! 58 | .classList.toggle('active'); 59 | }); 60 | 61 | // Initialize the current view. 62 | let currentView = ; 63 | 64 | // Conditionally render the following based on current mode. 65 | switch (currentMode) { 66 | case 'overview': 67 | currentView = ; 68 | break; 69 | case 'queries': 70 | currentView = ; 71 | break; 72 | case 'mutations': 73 | currentView = ; 74 | break; 75 | case 'resolvers': 76 | currentView = ; 77 | break; 78 | } 79 | 80 | // Render App with the following DOM. 81 | const modes = ['Overview', 'Resolvers']; 82 | 83 | // Render the following: 84 | return ( 85 |
86 |
87 |
88 | {currentView} 89 |
90 |
91 | ) 92 | } 93 | 94 | export default App 95 | -------------------------------------------------------------------------------- /bin/client/src/components/Data.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Data.tsx 2 | 3 | // TS types. 4 | type RequestObject = { 5 | speed: number, 6 | time: number, 7 | frequency: number, 8 | id: string 9 | } 10 | 11 | // Output object. 12 | const testingData = { 13 | Query:{ state: [] } 14 | } 15 | const processedData = { 16 | overview: getOverviewData(testingData), 17 | resolvers: getResolversData(testingData), 18 | }; 19 | 20 | /** 21 | * For Preparing Overview data. 22 | * @param data 23 | */ 24 | function getOverviewData (data: object) { 25 | // Init data to return. 26 | let minTS = Infinity; 27 | let maxTS = -Infinity; 28 | 29 | // Gets min and max TS. 30 | for (var entrypoint in data['Query']) { 31 | data['Query'][entrypoint].forEach((request: RequestObject) => { 32 | minTS = request.time < minTS ? request.time : minTS; 33 | maxTS = request.time > maxTS ? request.time : maxTS; 34 | } 35 | )}; 36 | 37 | // Init object of processed data to return. 38 | const returnData = { 39 | summary: getOverviewSummaryData(data), 40 | requests: getOverviewRequestsData(data), 41 | response: getOverviewResponseData(data), 42 | resolvers: getOverviewResolversData(data) 43 | }; 44 | 45 | // Gets summary data from 'data'. 46 | function getOverviewSummaryData (data: object) { 47 | // Init data to return. 48 | const rtnObj = { 49 | 'numTotalRequests': 0 50 | }; 51 | 52 | // Count total requests. 53 | for (var entrypoint in data['Query']) { 54 | rtnObj.numTotalRequests += data['Query'][entrypoint].length; 55 | } 56 | 57 | // Return the data. 58 | return rtnObj; 59 | } 60 | 61 | /** 62 | * Gets Requests data from 'data'. 63 | * @params 64 | * @todo: account for empty bins. 65 | */ 66 | function getOverviewRequestsData (data: object) { 67 | // Init data to return. 68 | const rtnObj = { 69 | 'times': [''], 70 | 'rpm': [null], 71 | 'ave': 0, 72 | 'count': 0 73 | }; 74 | 75 | // Counts total requests. 76 | const tempData = { "count": {} }; 77 | for (var entrypoint in data['Query']) { 78 | data['Query'][entrypoint].forEach((request: RequestObject) => { 79 | // Get the bin of the data. 80 | let bin = Number(Math.floor((request.time - minTS)/1000)*1000 + minTS); 81 | tempData["count"][bin] = bin in tempData["count"] ? tempData["count"][bin] + 1 : 1; 82 | }) 83 | } 84 | // Cast the counts obj to array and sort. 85 | const tempDataAsSortedArray = Object.keys(tempData["count"]) 86 | .map(key => [Number(key), tempData['count'][key]]) 87 | .sort((a, b)=> a[0] - b[0]); 88 | 89 | rtnObj["times"] = tempDataAsSortedArray.map(el => new Date(el[0]).toTimeString().split(' ')[0]); 90 | rtnObj["rpm"] = tempDataAsSortedArray.map(el => el[1]); 91 | 92 | return rtnObj; 93 | }; 94 | 95 | // Gets Response data from 'data'. 96 | function getOverviewResponseData (data: object) { 97 | // Init data to return. 98 | const rtnObj = { 99 | 'times': [''], 100 | '90': [null], 101 | 'ave': 0.0, 102 | 'count': 0 103 | }; 104 | 105 | // Counts total requests. 106 | const tempData = { "speed": {} , "counts": {} }; 107 | for (var entrypoint in data['Query']) { 108 | data['Query'][entrypoint].forEach((request: RequestObject) => { 109 | // Bin the results. 110 | let bin = Number(Math.floor((request.time - minTS)/1000)*1000 + minTS); 111 | tempData["counts"][bin] = bin in tempData["counts"] ? tempData["counts"][bin] + 1 : 1; 112 | tempData["speed"][bin] = bin in tempData["speed"] ? 113 | ((tempData["counts"][bin] - 1) * tempData["speed"][bin] / tempData["counts"][bin]) 114 | + (request.speed / tempData["counts"][bin]) : request.speed; 115 | 116 | // Set the average. 117 | rtnObj['count']++; 118 | rtnObj['ave'] = ( rtnObj['ave'] * (rtnObj['count']-1) / rtnObj['count'] ) 119 | + ( request.speed / rtnObj['count'] ); 120 | }) 121 | } 122 | 123 | // Cast the counts obj to array and sort. 124 | const tempDataAsSortedArray = Object.keys(tempData["speed"]) 125 | .map(key => [Number(key), tempData['speed'][key]]) 126 | .sort((a, b)=> a[0] - b[0]); 127 | 128 | rtnObj["times"] = tempDataAsSortedArray.map(el => new Date(el[0]).toTimeString().split(' ')[0]); 129 | rtnObj["90"] = tempDataAsSortedArray.map(el => el[1]); 130 | 131 | return rtnObj; 132 | }; 133 | 134 | // Execution Times data. 135 | function getOverviewResolversData(data: object) { 136 | // Init an object to hold our analysis. 137 | const rtnObj = { 138 | 'times': [''], 139 | 'aveSpeed': [null] 140 | }; 141 | 142 | const tempData = { "speed": {} , "counts": {} }; 143 | // Init a recursive funtion to count nested resolvers. 144 | const recurseSpeed = (key: any, element: any) => { 145 | if (Array.isArray(element)) { 146 | 147 | element.forEach(request => { 148 | let bin = Number(Math.floor((request.time - minTS)/1000)*1000 + minTS); 149 | tempData["counts"][bin] = bin in tempData["counts"] ? tempData["counts"][bin] + 1 : 1; 150 | tempData["speed"][bin] = bin in tempData["speed"] ? 151 | ((tempData["counts"][bin] - 1) * tempData["speed"][bin] / tempData["counts"][bin]) 152 | + (request.speed / tempData["counts"][bin]) : request.speed; 153 | }); 154 | 155 | } else for (let el in element) recurseSpeed(key + ":" + el, element[el]); 156 | } 157 | 158 | // Iterate through top level Resolvers. 159 | for (let key in data) if (key !== "Query") recurseSpeed(key, data[key]); 160 | 161 | // Cast the counts obj to array and sort. 162 | const tempDataAsSortedArray = Object.keys(tempData["speed"]) 163 | .map(key => [Number(key), tempData['speed'][key]]) 164 | .sort((a, b)=> a[0] - b[0]); 165 | 166 | rtnObj["times"] = tempDataAsSortedArray.map(el => new Date(el[0]).toTimeString().split(' ')[0]); 167 | rtnObj["aveSpeed"] = tempDataAsSortedArray.map(el => el[1]); 168 | 169 | // Return 170 | return rtnObj; 171 | } 172 | 173 | // Return. 174 | return returnData; 175 | } 176 | 177 | /** 178 | * For Preparing Resolvers data. 179 | * @param data 180 | */ 181 | function getResolversData(data: object) { 182 | const returnData = { 183 | invocationCounts: getInvocationCountsData(data), 184 | executionTimes: getExecutionTimesData(data), 185 | averageTime: 0.0, 186 | }; 187 | 188 | // Invocation Counts data. 189 | function getInvocationCountsData(data: object) { 190 | // Init an object to hold our analysis. 191 | const rtnObj = {}; 192 | 193 | // Init a recursive funtion to count nested resolvers. 194 | const recurseCount = (key: any, element: any) => { 195 | if (Array.isArray(element)) rtnObj[key] = element.length; 196 | else for (let el in element) recurseCount(key + ":" + el, element[el]); 197 | } 198 | 199 | // Fill out the top level Resolvers. 200 | for (let key in data) if (key !== "Query") recurseCount(key, data[key]); 201 | 202 | // Return 203 | return rtnObj; 204 | } 205 | 206 | // Execution Times data. 207 | function getExecutionTimesData(data: object) { 208 | // Init an object to hold our analysis. 209 | const rtnObj = {}; 210 | 211 | // Init a recursive funtion to count nested resolvers. 212 | const recurseSpeed = (key: any, element: any) => { 213 | if (Array.isArray(element)) { 214 | let speedArr = element.map(request => request["speed"]); 215 | rtnObj[key]={ 216 | ave: speedArr.reduce((a,c) => a+c) / speedArr.length, 217 | count: speedArr.length, 218 | }; 219 | } else for (let el in element) recurseSpeed(key + ":" + el, element[el]); 220 | } 221 | 222 | // Iterate through top level Resolvers. 223 | for (let key in data) if (key !== "Query") recurseSpeed(key, data[key]); 224 | 225 | // Return 226 | return rtnObj; 227 | } 228 | 229 | 230 | // Get Average Times data. 231 | let sumAve = 0.0; 232 | let count = 0; 233 | 234 | for (let key in returnData.executionTimes) { 235 | count += returnData.executionTimes[key]['count'] 236 | sumAve += returnData.executionTimes[key]['ave'] * returnData.executionTimes[key]['count']; 237 | } 238 | 239 | returnData['averageTime'] = sumAve / count; 240 | 241 | // Return. 242 | return returnData; 243 | } 244 | 245 | // Export. 246 | export { processedData, getOverviewData, getResolversData }; 247 | -------------------------------------------------------------------------------- /bin/client/src/components/Header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | width: 100%; 3 | top: 0px; 4 | left: 0px; 5 | background-color: #000; 6 | color: #fff; 7 | display: flex; 8 | justify-content: space-between; 9 | align-items: center; 10 | font-family: 'Open Sans', sans-serif; 11 | padding: .5em; 12 | } 13 | 14 | .active { 15 | color: #fff !important; 16 | font-weight: 600; 17 | } 18 | 19 | .header .header-logo { 20 | display: flex; 21 | font-size: 2em; 22 | color: #fff; 23 | margin-left: 50px; 24 | } 25 | 26 | .header .header-navigation { 27 | justify-content: space-between; 28 | display: flex; 29 | } 30 | 31 | .header-navigation-item { 32 | margin: 0em 1em 0em 1em; 33 | text-transform: uppercase; 34 | cursor: pointer; 35 | color: #a0a0a0; 36 | } 37 | 38 | .header .header-moreinformation { 39 | justify-content: space-between; 40 | display: flex; 41 | margin-right: 50px; 42 | } 43 | 44 | .svg_icons{ 45 | transform: scale(1.8); 46 | padding: 0em .5em 0em .5em; 47 | } 48 | -------------------------------------------------------------------------------- /bin/client/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Header.tsx 2 | 3 | import * as React from 'react'; 4 | import { HelpOutline, SettingsApplications, Refresh } from '@material-ui/icons'; 5 | 6 | import './Header.css' 7 | 8 | // Header Props TS typedef. 9 | type HeaderProps = { modes: Array, updateMode: Function } 10 | 11 | // Header functional component def. 12 | function Header({ modes, updateMode }: HeaderProps) { 13 | // An array of mode buttons for the header. 14 | const modeNavigationItems = modes.map(modeName => { 15 | return ( 16 | updateMode(modeName.toLowerCase())}> 20 | {modeName} 21 | 22 | ) 23 | }); 24 | 25 | // Header FC renders the following DOM: 26 | return ( 27 |
28 |
Goblin Monitor
29 |
{modeNavigationItems}
30 |
31 | 32 | 33 | 34 |
35 |
36 | ); 37 | } 38 | 39 | export default Header; 40 | -------------------------------------------------------------------------------- /bin/client/src/components/Main.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/goblinsharks/d573085a9e1d2cdd6d944025ee8686da1f140afa/bin/client/src/components/Main.css -------------------------------------------------------------------------------- /bin/client/src/components/Main.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Hello.tsx 2 | 3 | import * as React from 'react'; 4 | 5 | import './Main.css' 6 | 7 | function Main({}) { 8 | return ( 9 |
10 |
11 | ); 12 | } 13 | 14 | export default Main; 15 | -------------------------------------------------------------------------------- /bin/client/src/components/Mutations.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/goblinsharks/d573085a9e1d2cdd6d944025ee8686da1f140afa/bin/client/src/components/Mutations.css -------------------------------------------------------------------------------- /bin/client/src/components/Mutations.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Overview.tsx 2 | 3 | import * as React from 'react'; 4 | 5 | import './Mutations.css' 6 | 7 | // Header Props TS typedef. 8 | // type OverviewProps = { 9 | // modes: Array, 10 | // updateMode: Function 11 | // } 12 | 13 | type MutationsProps = { 14 | data: Object 15 | } 16 | 17 | function Mutations({ data }: MutationsProps) { 18 | return ( 19 |
20 |
21 | ) 22 | } 23 | 24 | export default Mutations; 25 | -------------------------------------------------------------------------------- /bin/client/src/components/Overview.css: -------------------------------------------------------------------------------- 1 | #modeOverview { 2 | position: absolute; 3 | background: #f3f3f3; 4 | width: 1000px; 5 | bottom: 0px; 6 | top: 100px; 7 | padding: 10px; 8 | } 9 | 10 | .overview-content { 11 | padding: 5px; 12 | margin-bottom: 15px; 13 | } 14 | 15 | .overview-content-whitebg { 16 | background: #fff; 17 | padding: 5px; 18 | } 19 | 20 | .content-title { 21 | font-size: 1.5em; 22 | margin-bottom: 10px; 23 | } 24 | 25 | .bold { 26 | font-weight: 600; 27 | } 28 | 29 | #overview-summary-statistics-wrapper { 30 | justify-content: space-around; 31 | display: flex; 32 | } 33 | 34 | .overview-summary-statistic-stat { 35 | font-size: 1.5em; 36 | font-weight: 600; 37 | } 38 | 39 | .overview-summary-statistic-val { 40 | color: orange; 41 | font-size: 3em; 42 | } 43 | 44 | .overview-summary-statistic-statval { 45 | text-align: center; 46 | } 47 | 48 | .chart-wrapper { 49 | height: 200px; 50 | width: 100%; 51 | padding: 5px 0px 5px 0px; 52 | } 53 | 54 | 55 | 56 | .modeOverview .overview-summary { 57 | 58 | } 59 | 60 | .modeOverview .overview-requests { 61 | 62 | } 63 | 64 | .modeOverview .overview-response { 65 | 66 | } 67 | 68 | .modeOverview .overview-errors { 69 | 70 | } -------------------------------------------------------------------------------- /bin/client/src/components/Overview.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Overview.tsx 2 | 3 | import * as React from 'react'; 4 | import { Line } from 'react-chartjs-2'; 5 | // let = require("react-chartjs-2").Line; 6 | 7 | 8 | import './Overview.css' 9 | 10 | // Header Props TS typedef. 11 | // type OverviewProps = { 12 | // modes: Array, 13 | // updateMode: Function 14 | // } 15 | 16 | interface OverviewProps { 17 | overviewData: OverviewData, 18 | resolversData: ResolversData 19 | } 20 | 21 | type OverviewData = { 22 | summary: Object, 23 | requests: Object, 24 | response: Object, 25 | resolvers: Object 26 | } 27 | 28 | type ResolversData = { 29 | invocationCounts: Object, 30 | executionTimes: Object, 31 | averageTime: Number 32 | } 33 | 34 | // type OverviewSummaryProps = { 35 | // summary: OverviewSummaryData 36 | // } 37 | 38 | // type OverviewSummaryData = { 39 | // numRequests: number 40 | // } 41 | 42 | 43 | // type OverviewRequestsProps = { 44 | // requests: Object 45 | // } 46 | 47 | 48 | /** 49 | * Overview-Summary functional component. 50 | * @param props 51 | */ 52 | function OverviewSummary(props: any) { 53 | // Render the summary statistics according to the following. 54 | return ( 55 |
56 |
57 | Summary 58 |
59 | 60 |
61 | 62 |
64 |
Total Requests
65 |
{props.summary.numTotalRequests}
66 |
67 | 68 |
70 |
Average Response Time (ms)
71 |
{props.averageTime.toFixed(2)}
72 |
73 | 74 | 75 |
76 |
77 | ) 78 | } 79 | 80 | /** 81 | * Overview-Requests functional component. 82 | * 83 | * @param props 84 | */ 85 | function OverviewRequests(props: any) { 86 | // Chart.js data. 87 | const chartData = { 88 | labels: props.requests.times.slice(-100), 89 | datasets: [ 90 | { 91 | label: 'Requests Per Second', 92 | fill: false, 93 | lineTension: 0.1, 94 | backgroundColor: 'rgba(75,192,192,0.4)', 95 | borderColor: 'rgba(75,192,192,1)', 96 | // borderCapStyle: 'butt', 97 | borderDash: [], 98 | borderDashOffset: 0.0, 99 | // borderJoinStyle: 'miter', 100 | pointBorderColor: 'rgba(75,192,192,1)', 101 | pointBackgroundColor: '#fff', 102 | pointBorderWidth: 1, 103 | pointHoverRadius: 5, 104 | pointHoverBackgroundColor: 'rgba(75,192,192,1)', 105 | pointHoverBorderColor: 'rgba(220,220,220,1)', 106 | pointHoverBorderWidth: 2, 107 | pointRadius: 1, 108 | pointHitRadius: 10, 109 | data: props.requests.rpm.slice(-100) 110 | } 111 | ] 112 | }; 113 | 114 | // Chart.js options. 115 | const chartOptions = { 116 | maintainAspectRatio: false, 117 | legend: { display: false } 118 | } 119 | 120 | // Render the following: 121 | return ( 122 |
123 |
125 | Requests Per Second this session: 126 |
127 |
129 | 130 |
131 |
132 | ) 133 | } 134 | 135 | /** 136 | * Overview-Response functional component. 137 | * 138 | * @param props 139 | */ 140 | function OverviewResponse(props: any) { 141 | // Chart.js data. 142 | const chartData = { 143 | labels: props.resolvers['times'].slice(-100), 144 | datasets: [ 145 | { 146 | label: 'Response Time', 147 | fill: false, 148 | lineTension: 0.1, 149 | backgroundColor: 'rgba(75,192,192,0.4)', 150 | borderColor: 'rgba(75,192,192,1)', 151 | // borderCapStyle: 'butt', 152 | borderDash: [], 153 | borderDashOffset: 0.0, 154 | // borderJoinStyle: 'miter', 155 | pointBorderColor: 'rgba(75,192,192,1)', 156 | pointBackgroundColor: '#fff', 157 | pointBorderWidth: 1, 158 | pointHoverRadius: 5, 159 | pointHoverBackgroundColor: 'rgba(75,192,192,1)', 160 | pointHoverBorderColor: 'rgba(220,220,220,1)', 161 | pointHoverBorderWidth: 2, 162 | pointRadius: 1, 163 | pointHitRadius: 10, 164 | data: props.resolvers["aveSpeed"].slice(-100) 165 | } 166 | ] 167 | }; 168 | 169 | // Chart.js options. 170 | const chartOptions = { 171 | maintainAspectRatio: false, 172 | legend: { display: false } 173 | } 174 | 175 | // Render the following: 176 | return ( 177 |
178 |
179 | Response Time 90 (ms) this session: 180 |
181 |
182 | 183 |
184 |
185 | ) 186 | } 187 | 188 | /** 189 | * Overview-Errors functional component. 190 | */ 191 | function OverviewErrors() { 192 | return ( 193 |
195 |
196 | ) 197 | } 198 | 199 | /** 200 | * Overview parent functional component. Renders 'Summary', 'Requests', 201 | * 'Response', and 'Errors' containers. 202 | * 203 | * @param props 204 | */ 205 | function Overview(props: OverviewProps) { 206 | return ( 207 |
208 | 209 | 210 | 211 | 212 |
213 | ) 214 | } 215 | 216 | // Export. 217 | export default Overview; 218 | -------------------------------------------------------------------------------- /bin/client/src/components/Queries.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/goblinsharks/d573085a9e1d2cdd6d944025ee8686da1f140afa/bin/client/src/components/Queries.css -------------------------------------------------------------------------------- /bin/client/src/components/Queries.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Overview.tsx 2 | 3 | import * as React from 'react'; 4 | 5 | import './Queries.css' 6 | 7 | // Header Props TS typedef. 8 | // type OverviewProps = { 9 | // modes: Array, 10 | // updateMode: Function 11 | // } 12 | 13 | type QueriesProps = { 14 | data: Object 15 | } 16 | function Queries({ data }: QueriesProps) { 17 | return ( 18 |
19 |
20 | ) 21 | } 22 | 23 | export default Queries; 24 | -------------------------------------------------------------------------------- /bin/client/src/components/Resolvers.css: -------------------------------------------------------------------------------- 1 | #modeResolvers { 2 | position: absolute; 3 | background: #f3f3f3; 4 | width: 1000px; 5 | bottom: 0px; 6 | top: 100px; 7 | padding: 10px; 8 | } 9 | 10 | 11 | .resolverListItem { 12 | display: flex; 13 | justify-content: space-between; 14 | padding: 10px; 15 | font-size: 1.2em; 16 | } 17 | 18 | .resolvers-content { 19 | padding: 5px; 20 | margin-bottom: 15px; 21 | } 22 | 23 | 24 | #resolvers-popularity{ 25 | 26 | } 27 | 28 | #resolvers-title{ 29 | 30 | } 31 | 32 | 33 | 34 | #resolvers-popularitylist-wrapper { 35 | height: 200px; 36 | overflow: scroll; 37 | } 38 | 39 | .content-title { 40 | font-size: 1.5em; 41 | margin-bottom: 10px; 42 | } 43 | 44 | .resolvers-content-whitebg { 45 | background: #fff; 46 | padding: 5px; 47 | } -------------------------------------------------------------------------------- /bin/client/src/components/Resolvers.tsx: -------------------------------------------------------------------------------- 1 | // src/components/Overview.tsx 2 | 3 | import * as React from 'react'; 4 | 5 | import './Resolvers.css' 6 | 7 | 8 | // ResolversProps type. 9 | type ResolversProps = { 10 | resolversData: ResolversData, 11 | } 12 | 13 | // ResolversData type. 14 | type ResolversData = { 15 | invocationCounts: Object, 16 | executionTimes: Object, 17 | } 18 | 19 | /** 20 | * Renders the list of resolvers sorted by invocation count, descending. 21 | * @param props 22 | */ 23 | function ResolversInvocationCount(props: any) { 24 | // Sort the object of objects by count popularity descending. 25 | const resolverListSortedByPopularity = 26 | Object.keys(props.invocationCounts).map(path => { 27 | return [path, props.invocationCounts[path]]; 28 | }).sort((a, b) => b[1] - a[1]); 29 | 30 | // Create array of DOM elements for the resolvers. 31 | const resolverListItems = resolverListSortedByPopularity.map((item, idx) => { 32 | return ( 33 |
34 |
{item[0]}
35 |
{item[1]}
36 |
37 | ) 38 | }); 39 | 40 | // Render the following: 41 | return ( 42 |
43 | 44 |
45 | Resolver Operations by invocation count: 46 |
47 | 48 |
49 | {resolverListItems} 50 |
51 |
52 | ) 53 | } 54 | 55 | 56 | /** 57 | * Renders the list of resolvers sorted by average execution time, descending. 58 | * @param props 59 | */ 60 | function ResolversExecutionTime(props: any) { 61 | // Sort the object of objects by count popularity descending. 62 | const resolverListSortedByExecutionTime = 63 | Object.keys(props.executionTimes).map(path => { 64 | return [path, props.executionTimes[path]['ave']]; 65 | }).sort((a, b) => b[1] - a[1]); 66 | 67 | // Create array of DOM elements for the resolvers. 68 | const resolverListItems = resolverListSortedByExecutionTime.map((item, idx) => { 69 | return ( 70 |
71 |
{item[0]}
72 |
{item[1].toFixed(2)}
73 |
74 | ) 75 | }); 76 | 77 | // Render the following: 78 | return ( 79 |
80 | 81 |
82 | Resolver Operations by average execution time (ms): 83 |
84 | 85 |
86 | {resolverListItems} 87 |
88 |
89 | ) 90 | } 91 | 92 | 93 | /** 94 | * Resolvers FC renders the following. 95 | * @param props 96 | */ 97 | function Resolvers(props: ResolversProps) { 98 | return ( 99 |
100 | 101 | 102 |
103 | ) 104 | } 105 | 106 | export default Resolvers; 107 | -------------------------------------------------------------------------------- /bin/client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /bin/client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /bin/client/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import App from './components/App'; 4 | import './index.css'; 5 | // import registerServiceWorker from './registerServiceWorker'; 6 | 7 | 8 | 9 | ReactDOM.render( 10 | , 11 | document.getElementById('root') as HTMLElement 12 | ); 13 | // registerServiceWorker(); 14 | -------------------------------------------------------------------------------- /bin/db/err.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "function dsum(bigint) does not exist", 5 | "path": [ 6 | "state", 7 | "total_dosage" 8 | ], 9 | "time": 1566949016121, 10 | "stacktrace": [ 11 | "error: function dsum(bigint) does not exist", 12 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 13 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 14 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 15 | " at Socket.emit (events.js:198:13)", 16 | " at addChunk (_stream_readable.js:288:12)", 17 | " at readableAddChunk (_stream_readable.js:269:11)", 18 | " at Socket.Readable.push (_stream_readable.js:224:10)", 19 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 20 | ] 21 | }, 22 | { 23 | "message": "function dsum(bigint) does not exist", 24 | "path": [ 25 | "state", 26 | "total_dosage" 27 | ], 28 | "time": 1566952368434, 29 | "stacktrace": [ 30 | "error: function dsum(bigint) does not exist", 31 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 32 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 33 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 34 | " at Socket.emit (events.js:198:13)", 35 | " at addChunk (_stream_readable.js:288:12)", 36 | " at readableAddChunk (_stream_readable.js:269:11)", 37 | " at Socket.Readable.push (_stream_readable.js:224:10)", 38 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 39 | ] 40 | }, 41 | { 42 | "message": "function dsum(bigint) does not exist", 43 | "path": [ 44 | "state", 45 | "total_dosage" 46 | ], 47 | "time": 1566952452448, 48 | "stacktrace": [ 49 | "error: function dsum(bigint) does not exist", 50 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 51 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 52 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 53 | " at Socket.emit (events.js:198:13)", 54 | " at addChunk (_stream_readable.js:288:12)", 55 | " at readableAddChunk (_stream_readable.js:269:11)", 56 | " at Socket.Readable.push (_stream_readable.js:224:10)", 57 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 58 | ] 59 | }, 60 | { 61 | "message": "function dsum(bigint) does not exist", 62 | "path": [ 63 | "state", 64 | "total_dosage" 65 | ], 66 | "time": 1566952533598, 67 | "stacktrace": [ 68 | "error: function dsum(bigint) does not exist", 69 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 70 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 71 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 72 | " at Socket.emit (events.js:198:13)", 73 | " at addChunk (_stream_readable.js:288:12)", 74 | " at readableAddChunk (_stream_readable.js:269:11)", 75 | " at Socket.Readable.push (_stream_readable.js:224:10)", 76 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 77 | ] 78 | }, 79 | { 80 | "message": "function dsum(bigint) does not exist", 81 | "path": [ 82 | "state", 83 | "total_dosage" 84 | ], 85 | "time": 1566952594895, 86 | "stacktrace": [ 87 | "error: function dsum(bigint) does not exist", 88 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 89 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 90 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 91 | " at Socket.emit (events.js:198:13)", 92 | " at addChunk (_stream_readable.js:288:12)", 93 | " at readableAddChunk (_stream_readable.js:269:11)", 94 | " at Socket.Readable.push (_stream_readable.js:224:10)", 95 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 96 | ] 97 | }, 98 | { 99 | "message": "function dsum(bigint) does not exist", 100 | "path": [ 101 | "state", 102 | "total_dosage" 103 | ], 104 | "time": 1566952897304, 105 | "stacktrace": [ 106 | "error: function dsum(bigint) does not exist", 107 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 108 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 109 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 110 | " at Socket.emit (events.js:198:13)", 111 | " at addChunk (_stream_readable.js:288:12)", 112 | " at readableAddChunk (_stream_readable.js:269:11)", 113 | " at Socket.Readable.push (_stream_readable.js:224:10)", 114 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 115 | ] 116 | }, 117 | { 118 | "message": "function dsum(bigint) does not exist", 119 | "path": [ 120 | "state", 121 | "total_dosage" 122 | ], 123 | "time": 1566952898799, 124 | "stacktrace": [ 125 | "error: function dsum(bigint) does not exist", 126 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 127 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 128 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 129 | " at Socket.emit (events.js:198:13)", 130 | " at addChunk (_stream_readable.js:288:12)", 131 | " at readableAddChunk (_stream_readable.js:269:11)", 132 | " at Socket.Readable.push (_stream_readable.js:224:10)", 133 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 134 | ] 135 | }, 136 | { 137 | "message": "function dsum(bigint) does not exist", 138 | "path": [ 139 | "state", 140 | "total_dosage" 141 | ], 142 | "time": 1566952899705, 143 | "stacktrace": [ 144 | "error: function dsum(bigint) does not exist", 145 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 146 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 147 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 148 | " at Socket.emit (events.js:198:13)", 149 | " at addChunk (_stream_readable.js:288:12)", 150 | " at readableAddChunk (_stream_readable.js:269:11)", 151 | " at Socket.Readable.push (_stream_readable.js:224:10)", 152 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 153 | ] 154 | }, 155 | { 156 | "message": "function dsum(bigint) does not exist", 157 | "path": [ 158 | "state", 159 | "total_dosage" 160 | ], 161 | "time": 1566952900146, 162 | "stacktrace": [ 163 | "error: function dsum(bigint) does not exist", 164 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 165 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 166 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 167 | " at Socket.emit (events.js:198:13)", 168 | " at addChunk (_stream_readable.js:288:12)", 169 | " at readableAddChunk (_stream_readable.js:269:11)", 170 | " at Socket.Readable.push (_stream_readable.js:224:10)", 171 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 172 | ] 173 | }, 174 | { 175 | "message": "function dsum(bigint) does not exist", 176 | "path": [ 177 | "state", 178 | "total_dosage" 179 | ], 180 | "time": 1566952900571, 181 | "stacktrace": [ 182 | "error: function dsum(bigint) does not exist", 183 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 184 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 185 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 186 | " at Socket.emit (events.js:198:13)", 187 | " at addChunk (_stream_readable.js:288:12)", 188 | " at readableAddChunk (_stream_readable.js:269:11)", 189 | " at Socket.Readable.push (_stream_readable.js:224:10)", 190 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 191 | ] 192 | }, 193 | { 194 | "message": "function dsum(bigint) does not exist", 195 | "path": [ 196 | "state", 197 | "total_dosage" 198 | ], 199 | "time": 1566952931366, 200 | "stacktrace": [ 201 | "error: function dsum(bigint) does not exist", 202 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 203 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 204 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 205 | " at Socket.emit (events.js:198:13)", 206 | " at addChunk (_stream_readable.js:288:12)", 207 | " at readableAddChunk (_stream_readable.js:269:11)", 208 | " at Socket.Readable.push (_stream_readable.js:224:10)", 209 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 210 | ] 211 | }, 212 | { 213 | "message": "function dsum(bigint) does not exist", 214 | "path": [ 215 | "state", 216 | "total_dosage" 217 | ], 218 | "time": 1566952934292, 219 | "stacktrace": [ 220 | "error: function dsum(bigint) does not exist", 221 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 222 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 223 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 224 | " at Socket.emit (events.js:198:13)", 225 | " at addChunk (_stream_readable.js:288:12)", 226 | " at readableAddChunk (_stream_readable.js:269:11)", 227 | " at Socket.Readable.push (_stream_readable.js:224:10)", 228 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 229 | ] 230 | }, 231 | { 232 | "message": "function dsum(bigint) does not exist", 233 | "path": [ 234 | "state", 235 | "total_dosage" 236 | ], 237 | "time": 1566952937298, 238 | "stacktrace": [ 239 | "error: function dsum(bigint) does not exist", 240 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 241 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 242 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 243 | " at Socket.emit (events.js:198:13)", 244 | " at addChunk (_stream_readable.js:288:12)", 245 | " at readableAddChunk (_stream_readable.js:269:11)", 246 | " at Socket.Readable.push (_stream_readable.js:224:10)", 247 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 248 | ] 249 | }, 250 | { 251 | "message": "function dsum(bigint) does not exist", 252 | "path": [ 253 | "state", 254 | "total_dosage" 255 | ], 256 | "time": 1566952937891, 257 | "stacktrace": [ 258 | "error: function dsum(bigint) does not exist", 259 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 260 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 261 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 262 | " at Socket.emit (events.js:198:13)", 263 | " at addChunk (_stream_readable.js:288:12)", 264 | " at readableAddChunk (_stream_readable.js:269:11)", 265 | " at Socket.Readable.push (_stream_readable.js:224:10)", 266 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 267 | ] 268 | }, 269 | { 270 | "message": "function dsum(bigint) does not exist", 271 | "path": [ 272 | "state", 273 | "total_dosage" 274 | ], 275 | "time": 1566952964594, 276 | "stacktrace": [ 277 | "error: function dsum(bigint) does not exist", 278 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 279 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 280 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 281 | " at Socket.emit (events.js:198:13)", 282 | " at addChunk (_stream_readable.js:288:12)", 283 | " at readableAddChunk (_stream_readable.js:269:11)", 284 | " at Socket.Readable.push (_stream_readable.js:224:10)", 285 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 286 | ] 287 | }, 288 | { 289 | "message": "function dsum(bigint) does not exist", 290 | "path": [ 291 | "state", 292 | "total_dosage" 293 | ], 294 | "time": 1566952967243, 295 | "stacktrace": [ 296 | "error: function dsum(bigint) does not exist", 297 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 298 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 299 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 300 | " at Socket.emit (events.js:198:13)", 301 | " at addChunk (_stream_readable.js:288:12)", 302 | " at readableAddChunk (_stream_readable.js:269:11)", 303 | " at Socket.Readable.push (_stream_readable.js:224:10)", 304 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 305 | ] 306 | }, 307 | { 308 | "message": "function dsum(bigint) does not exist", 309 | "path": [ 310 | "state", 311 | "total_dosage" 312 | ], 313 | "time": 1566952976226, 314 | "stacktrace": [ 315 | "error: function dsum(bigint) does not exist", 316 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 317 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 318 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 319 | " at Socket.emit (events.js:198:13)", 320 | " at addChunk (_stream_readable.js:288:12)", 321 | " at readableAddChunk (_stream_readable.js:269:11)", 322 | " at Socket.Readable.push (_stream_readable.js:224:10)", 323 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 324 | ] 325 | }, 326 | { 327 | "message": "function dsum(bigint) does not exist", 328 | "path": [ 329 | "state", 330 | "total_dosage" 331 | ], 332 | "time": 1566952978091, 333 | "stacktrace": [ 334 | "error: function dsum(bigint) does not exist", 335 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 336 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 337 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 338 | " at Socket.emit (events.js:198:13)", 339 | " at addChunk (_stream_readable.js:288:12)", 340 | " at readableAddChunk (_stream_readable.js:269:11)", 341 | " at Socket.Readable.push (_stream_readable.js:224:10)", 342 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 343 | ] 344 | }, 345 | { 346 | "message": "function dsum(bigint) does not exist", 347 | "path": [ 348 | "state", 349 | "total_dosage" 350 | ], 351 | "time": 1566952978553, 352 | "stacktrace": [ 353 | "error: function dsum(bigint) does not exist", 354 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 355 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 356 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 357 | " at Socket.emit (events.js:198:13)", 358 | " at addChunk (_stream_readable.js:288:12)", 359 | " at readableAddChunk (_stream_readable.js:269:11)", 360 | " at Socket.Readable.push (_stream_readable.js:224:10)", 361 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 362 | ] 363 | }, 364 | { 365 | "message": "function dsum(bigint) does not exist", 366 | "path": [ 367 | "state", 368 | "total_dosage" 369 | ], 370 | "time": 1566953006365, 371 | "stacktrace": [ 372 | "error: function dsum(bigint) does not exist", 373 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 374 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 375 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 376 | " at Socket.emit (events.js:198:13)", 377 | " at addChunk (_stream_readable.js:288:12)", 378 | " at readableAddChunk (_stream_readable.js:269:11)", 379 | " at Socket.Readable.push (_stream_readable.js:224:10)", 380 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 381 | ] 382 | }, 383 | { 384 | "message": "function dsum(bigint) does not exist", 385 | "path": [ 386 | "state", 387 | "total_dosage" 388 | ], 389 | "time": 1566953012198, 390 | "stacktrace": [ 391 | "error: function dsum(bigint) does not exist", 392 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 393 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 394 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 395 | " at Socket.emit (events.js:198:13)", 396 | " at addChunk (_stream_readable.js:288:12)", 397 | " at readableAddChunk (_stream_readable.js:269:11)", 398 | " at Socket.Readable.push (_stream_readable.js:224:10)", 399 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 400 | ] 401 | }, 402 | { 403 | "message": "function dsum(bigint) does not exist", 404 | "path": [ 405 | "state", 406 | "total_dosage" 407 | ], 408 | "time": 1566953016411, 409 | "stacktrace": [ 410 | "error: function dsum(bigint) does not exist", 411 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 412 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 413 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 414 | " at Socket.emit (events.js:198:13)", 415 | " at addChunk (_stream_readable.js:288:12)", 416 | " at readableAddChunk (_stream_readable.js:269:11)", 417 | " at Socket.Readable.push (_stream_readable.js:224:10)", 418 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 419 | ] 420 | }, 421 | { 422 | "message": "function dsum(bigint) does not exist", 423 | "path": [ 424 | "state", 425 | "total_dosage" 426 | ], 427 | "time": 1566953021769, 428 | "stacktrace": [ 429 | "error: function dsum(bigint) does not exist", 430 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 431 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 432 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 433 | " at Socket.emit (events.js:198:13)", 434 | " at addChunk (_stream_readable.js:288:12)", 435 | " at readableAddChunk (_stream_readable.js:269:11)", 436 | " at Socket.Readable.push (_stream_readable.js:224:10)", 437 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 438 | ] 439 | }, 440 | { 441 | "message": "syntax error at or near \"SELECT\"", 442 | "path": [ 443 | "state", 444 | "name" 445 | ], 446 | "time": 1566953097526, 447 | "stacktrace": [ 448 | "error: syntax error at or near \"SELECT\"", 449 | " at Connection.parseE (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:604:11)", 450 | " at Connection.parseMessage (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:401:19)", 451 | " at Socket. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/pg/lib/connection.js:121:22)", 452 | " at Socket.emit (events.js:198:13)", 453 | " at addChunk (_stream_readable.js:288:12)", 454 | " at readableAddChunk (_stream_readable.js:269:11)", 455 | " at Socket.Readable.push (_stream_readable.js:224:10)", 456 | " at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)" 457 | ] 458 | }, 459 | { 460 | "message": "Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 461 | "time": 1566964064529, 462 | "stacktrace": [ 463 | "GraphQLError: Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 464 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 465 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 466 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 467 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 468 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 469 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 470 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 471 | " at Generator.next ()", 472 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 473 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 474 | ] 475 | }, 476 | { 477 | "message": "Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 478 | "time": 1566964067105, 479 | "stacktrace": [ 480 | "GraphQLError: Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 481 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 482 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 483 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 484 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 485 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 486 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 487 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 488 | " at Generator.next ()", 489 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 490 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 491 | ] 492 | }, 493 | { 494 | "message": "Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 495 | "time": 1566964067266, 496 | "stacktrace": [ 497 | "GraphQLError: Cannot query field \"named\" on type \"State\". Did you mean \"name\"?", 498 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 499 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 500 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 501 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 502 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 503 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 504 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 505 | " at Generator.next ()", 506 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 507 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 508 | ] 509 | }, 510 | { 511 | "message": "Cannot query field \"nameadsada\" on type \"State\".", 512 | "time": 1566964076503, 513 | "stacktrace": [ 514 | "GraphQLError: Cannot query field \"nameadsada\" on type \"State\".", 515 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 516 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 517 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 518 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 519 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 520 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 521 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 522 | " at Generator.next ()", 523 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 524 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 525 | ] 526 | }, 527 | { 528 | "message": "Cannot query field \"nameadsada\" on type \"State\".", 529 | "time": 1566964076888, 530 | "stacktrace": [ 531 | "GraphQLError: Cannot query field \"nameadsada\" on type \"State\".", 532 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 533 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 534 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 535 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 536 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 537 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 538 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 539 | " at Generator.next ()", 540 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 541 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 542 | ] 543 | }, 544 | { 545 | "message": "Cannot query field \"nameadsada\" on type \"State\".", 546 | "time": 1566964076991, 547 | "stacktrace": [ 548 | "GraphQLError: Cannot query field \"nameadsada\" on type \"State\".", 549 | " at Object.Field (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)", 550 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:324:29)", 551 | " at Object.enter (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:375:25)", 552 | " at visit (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/language/visitor.js:242:26)", 553 | " at Object.validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/graphql/validation/validate.js:73:24)", 554 | " at validate (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:211:32)", 555 | " at Object. (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:124:42)", 556 | " at Generator.next ()", 557 | " at fulfilled (/Users/andrewtang/Desktop/goblinsharks-apollo/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)", 558 | " at process._tickCallback (internal/process/next_tick.js:68:7)" 559 | ] 560 | } 561 | ] 562 | } -------------------------------------------------------------------------------- /bin/db/fileController.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs').promises; 2 | const path = require('path'); 3 | const jsonData = require("./data.json"); 4 | const errData = require('./err.json'); 5 | 6 | async function createFile(filename) { 7 | try { // if file does not exist. 8 | const fileStatus = await fs.open(__dirname + '/data.json','r') 9 | } 10 | catch { // creates file. 11 | await fs.writeFile(__dirname + '/data.json',JSON.stringify({})) 12 | } 13 | } 14 | 15 | async function appendFile(queryKey,resolverName,speed,id){ 16 | try{ 17 | if (!jsonData[queryKey]){ // checking if the query type is defined - - 18 | jsonData[queryKey]= {}; 19 | } 20 | if (!jsonData[queryKey][resolverName]){ // checking if the particular resolver has been defined. 21 | jsonData[queryKey][resolverName] = []; 22 | } 23 | jsonData[queryKey][resolverName].push({ // each resolver execution is logged with this object - 24 | speed: speed, 25 | frequency: 1, 26 | time: Date.now(), 27 | id: id 28 | }) 29 | fs.writeFile(path.join(__dirname,'data.json'), JSON.stringify(jsonData,null,2)) // write new data to json 30 | } catch { 31 | console.log('unable to append') 32 | } 33 | }; 34 | 35 | async function trackError (err, time) { 36 | try{ 37 | const { extensions, message } = err; // declaring path separately to avoid overwriting path module 38 | const resolverPath = err.path 39 | const errObj = { 40 | message, 41 | path : resolverPath, 42 | time, 43 | stacktrace: extensions.exception.stacktrace 44 | } 45 | if (!errData.errors) { 46 | errData.errors = []; 47 | } 48 | errData.errors.push(errObj) 49 | console.log(errData) 50 | console.log('dirname inside of filecontroller', __dirname); 51 | await fs.writeFile(path.join(__dirname,'err.json'), JSON.stringify(errData,null,2)) 52 | // await fs.writeFile(path.join(__dirname,'errors.json'), JSON.stringify({},null,2)) 53 | } catch(e) { 54 | console.log(e) 55 | console.log('unable to track errors') 56 | } 57 | // console.log(err); 58 | 59 | }; 60 | 61 | 62 | module.exports = { 63 | createFile, 64 | appendFile, 65 | trackError 66 | } 67 | -------------------------------------------------------------------------------- /bin/exec.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { exec } = require('child_process'); 3 | const goblin = require('commander'); 4 | const path = require('path'); 5 | 6 | goblin 7 | .command('monitor') // argument passed to bin script 8 | .alias('m') // shorthand for monitor argument e.g. goblin monitor === goblin m 9 | .description('Start GoblinQL Monitoring Service') // part of --help flag for goblin script 10 | .action(() => exec(`node ${__dirname}/server/wsServer.js & sleep 0.25; open http://localhost:9000` )) 11 | 12 | goblin.parse(process.argv); // commander parses and processes arguments to execute script in shell 13 | 14 | 15 | // .action(() => exec(`node ${__dirname}/server.js & open http://localhost:9000/goblinql` )) 16 | -------------------------------------------------------------------------------- /bin/goblin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { exec } = require('child_process'); 3 | const goblin = require('commander'); 4 | 5 | goblin 6 | .command('server') 7 | .alias('s') 8 | .description('Start GoblinQL Monitoring') 9 | .action(() => exec('node ./node_modules/goblin-ql/server.js & open http://localhost:9000/goblinql')) 10 | 11 | goblin.parse(process.argv); -------------------------------------------------------------------------------- /bin/server/express.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const app = express(); 4 | // const cors = require('cors'); 5 | 6 | 7 | console.log('connected to server'); 8 | 9 | app.use(express.static(path.join(__dirname,'../../bin'))); // serving the bin directory as main source of static files. 10 | 11 | app.get('/', (req, res) => { 12 | res.sendFile(path.resolve(__dirname + '../../client/dist/index.html')); 13 | }); 14 | 15 | 16 | 17 | module.exports = app; -------------------------------------------------------------------------------- /bin/server/wsServer.js: -------------------------------------------------------------------------------- 1 | const httpServer = require('http').createServer(); 2 | const WebSocket = require('ws').Server 3 | const app = require('./express.js') 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | 8 | // Note: both the express server and the Websocket server sit on top of the Httpserver (port 9000) 9 | 10 | const wss = new WebSocket({ 11 | server: httpServer 12 | }); 13 | 14 | httpServer.on('request', app); 15 | 16 | wss.on('connection', (ws) => { // initiating ws connection 17 | console.log('Websocket connection established'); 18 | fs.watchFile(path.join(__dirname,'../db/data.json'), { interval:1000 }, (data) => { // listening for changes to data.json 19 | // broadcast(data); 20 | ws.send(JSON.stringify({hello:"World"})); // sending to client updated data 21 | console.log('file changed'); 22 | }) 23 | }); 24 | 25 | 26 | 27 | httpServer.listen(9000, () => { 28 | console.log('listening on port 9000') 29 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goblin-ql", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/main.js", 6 | "bin": { 7 | "goblin": "./bin/exec.js" 8 | }, 9 | "scripts": { 10 | "test": "jest", 11 | "start": "webpack --mode development", 12 | "dev": "webpack --mode development & goblin monitor", 13 | "build": "webpack --mode production" 14 | }, 15 | "keywords": [], 16 | "author": "Andrew Tang, Justin Fung, Billy Lee, Sorouuush", 17 | "license": "ISC", 18 | "dependencies": { 19 | "@material-ui/core": "^4.3.3", 20 | "@material-ui/icons": "^4.2.1", 21 | "@types/react": "^16.9.2", 22 | "@types/react-dom": "^16.9.0", 23 | "chart.js": "^2.8.0", 24 | "commander": "^3.0.0", 25 | "express": "^4.17.1", 26 | "g": "^2.0.1", 27 | "nodemon": "^1.19.1", 28 | "performance-now": "^2.1.0", 29 | "react": "^16.9.0", 30 | "react-chartjs-2": "^2.7.6", 31 | "react-dom": "^16.9.0", 32 | "sleep-ms": "^2.0.1", 33 | "uniqid": "^5.0.3", 34 | "ws": "^7.1.2" 35 | }, 36 | "devDependencies": { 37 | "awesome-typescript-loader": "^5.2.1", 38 | "cors": "^2.8.5", 39 | "css-loader": "^3.2.0", 40 | "enzyme": "^3.10.0", 41 | "enzyme-adapter-react-16": "^1.14.0", 42 | "html-webpack-plugin": "^3.2.0", 43 | "jest": "^24.9.0", 44 | "style-loader": "^1.0.0", 45 | "typescript": "^3.6.2", 46 | "webpack": "^4.39.3", 47 | "webpack-cli": "^3.3.7", 48 | "webpack-dev-server": "^3.8.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/enableTracking.js: -------------------------------------------------------------------------------- 1 | const now = require('performance-now') 2 | const { appendFile } = require("../bin/db/fileController") 3 | const uniqid = require('uniqid'); 4 | 5 | module.exports = function enableTracking(resolversObject,queryField) { 6 | // takes resolvers object of key value pairs - 7 | // key refers to resolver name, value refers to resolver function definition 8 | const newResolversObject = {} 9 | const fields = Object.keys(resolversObject); 10 | const resolverFunctions = Object.values(resolversObject); 11 | 12 | const updatedResolverFunctions = resolverFunctions.map((resolverFunc,index) => { 13 | const fieldName = fields[index]; 14 | const currentResolver = async function(...args) { 15 | const [parent, params, ctx, info] = args // 4 arguments available to resolvers. 16 | // if (!parent){ 17 | // // console.log(info) 18 | // } 19 | if (!ctx['id']) { // setting a unique id per request on the context obj 20 | ctx['id'] = uniqid.process(); 21 | 22 | } 23 | const id = ctx.id 24 | var t0 = now(); 25 | const resolverReturnValue = await resolverFunc(...args) // executing the original resolver. 26 | var t1 = now(); 27 | let speed = parseFloat((t1-t0).toFixed(4)); 28 | await appendFile(queryField,fieldName,speed,id); 29 | 30 | console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to run the ', fieldName + ' resolver.'); 31 | return resolverReturnValue 32 | } 33 | Object.defineProperty(currentResolver,'name', {value:fieldName,writable:true}) // dynamically naming all of the resolvers respective to their original name 34 | return currentResolver 35 | }) 36 | 37 | fields.forEach((field,index) => { // mapping to each field each respective resolver that has been updated. 38 | newResolversObject[field] = updatedResolverFunctions[index] 39 | }) 40 | return newResolversObject 41 | } 42 | -------------------------------------------------------------------------------- /src/grabFields.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/goblinsharks/d573085a9e1d2cdd6d944025ee8686da1f140afa/src/grabFields.js -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const mapResolvers = require("./mapResolvers") 2 | const { trackError } = require("../bin/db/fileController.js") 3 | 4 | 5 | const enableMonitoring = (resolvers) => { 6 | const injectedResolvers = mapResolvers(resolvers) 7 | return injectedResolvers 8 | }; 9 | 10 | 11 | 12 | 13 | module.exports = { enableMonitoring, trackError} 14 | -------------------------------------------------------------------------------- /src/mapResolvers.js: -------------------------------------------------------------------------------- 1 | const enableTracking = require("./enableTracking") 2 | 3 | function mapResolvers(originalResolversObject) { 4 | const updatedResolvers = {} 5 | const queries = Object.keys(originalResolversObject) // custom query types 6 | const resolvers = Object.values(originalResolversObject); // object containing a bunch of objects key value pairs of resolvers & field names 7 | 8 | 9 | queries.forEach((key,index)=>{ 10 | updatedResolvers[key] = enableTracking(resolvers[index],key) // should return an object which contains keys of 11 | }) 12 | 13 | return updatedResolvers 14 | 15 | } 16 | 17 | 18 | module.exports = mapResolvers -------------------------------------------------------------------------------- /test/enableMonitoring.test.js: -------------------------------------------------------------------------------- 1 | const { enableMonitoring } = require('../src/main'); 2 | const {stateTypeResolvers } = require('../testResolvers/mockResolvers') 3 | 4 | test('should return an object', () => { 5 | expect(typeof enableMonitoring({})).toBe('object') 6 | }) 7 | 8 | test('resolver state does not change', () => { 9 | expect(JSON.stringify(enableMonitoring(stateTypeResolvers).State.name)).toBe((JSON.stringify(stateTypeResolvers.State.name))) 10 | }) 11 | 12 | // test('resolver name does not change', () => { 13 | // expect(enableMonitoring(stateTypeResolvers).State.county.name).toBe(('name')) 14 | // }) 15 | 16 | test('checking the state type', () => { 17 | console.log(stateTypeResolvers); 18 | expect(JSON.stringify(enableMonitoring(stateTypeResolvers))).toBe(JSON.stringify(stateTypeResolvers)) 19 | 20 | }) 21 | 22 | test('checking State total dosage', () => { 23 | expect(JSON.stringify(enableMonitoring(stateTypeResolvers).State.total_dosage)).toBe((JSON.stringify(stateTypeResolvers.State.total_dosage))) 24 | }) 25 | 26 | test('checking total_manufactured', () => { 27 | expect(JSON.stringify(enableMonitoring(stateTypeResolvers).State.total_manufactured)).toBe((JSON.stringify(stateTypeResolvers.State.total_manufactured))) 28 | }) 29 | 30 | test('Checking county', () => { 31 | expect(JSON.stringify(enableMonitoring(stateTypeResolvers).State.county)).toBe((JSON.stringify(stateTypeResolvers.State.county))) 32 | }) -------------------------------------------------------------------------------- /test/enableTracking.test.js: -------------------------------------------------------------------------------- 1 | const enableTracking = require('../src/enableTracking'); 2 | 3 | test('should return an object', () => { 4 | expect(typeof enableTracking({})).toBe('object') 5 | }) 6 | 7 | 8 | // test('checking if filds value is right', () => { 9 | // console.log(enableTracking); 10 | // expect(JSON.stringify(enableTracking.fields)).toBe(JSON.stringify(Object.keys(resolversObject))) 11 | 12 | // }) 13 | -------------------------------------------------------------------------------- /testResolvers/mockResolvers.js: -------------------------------------------------------------------------------- 1 | const stateTypeResolvers = { 2 | Query: { 3 | state(parent, args, context, info) { 4 | // allowing child resolvers to access the arg -- 5 | return 'California' 6 | } 7 | }, 8 | State: { 9 | async name(parent,args) { 10 | return ("California") 11 | }, 12 | async total_dosage(parent,args) { 13 | console.log(21) 14 | }, 15 | 16 | async total_manufactured(parent,args) { 17 | console.log(421312) 18 | }, 19 | county(parent,args){ // giving access state and county to child field nodes 20 | return {state: parent, county:args.county} 21 | } 22 | } 23 | } 24 | 25 | 26 | const mockResolverObject = { 27 | async name(parent,args) { 28 | console.log("California") 29 | }, 30 | async total_dosage(parent,args) { 31 | console.log(21) 32 | }, 33 | 34 | async total_manufactured(parent,args) { 35 | console.log(421312) 36 | }, 37 | county(parent,args){ // giving access state and county to child field nodes 38 | return {state: parent, county:args.county} 39 | } 40 | } 41 | 42 | module.exports = { 43 | stateTypeResolvers, 44 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "noImplicitAny": false, 5 | "module": "commonjs", 6 | "target": "es6", 7 | "lib": [ 8 | "es2015", 9 | "es2017", 10 | "dom" 11 | ], 12 | "removeComments": true, 13 | "allowSyntheticDefaultImports": false, 14 | "jsx": "react", 15 | "allowJs": true, 16 | "baseUrl": "./", 17 | "paths": { 18 | "components/*": [ 19 | "src/components/*" 20 | ], 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | watch: true, 6 | watchOptions: { 7 | ignored: /node_modules/, 8 | aggregateTimeout: 1000 9 | }, 10 | entry: './bin/client/src/index.tsx', 11 | resolve: { 12 | extensions: ['.ts', '.tsx', '.js'] 13 | }, 14 | output: { 15 | path: path.join(__dirname, '/bin/client/dist'), 16 | filename: 'bundle.min.js' 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.tsx?$/, 22 | loader: 'awesome-typescript-loader' 23 | }, 24 | { 25 | test: /\.css$/, 26 | use: ['style-loader', 'css-loader'], 27 | } 28 | ] 29 | }, 30 | } 31 | --------------------------------------------------------------------------------