├── Client
├── .env
├── src
│ ├── global.d.ts
│ ├── app.html
│ ├── routes
│ │ ├── __layout.svelte
│ │ ├── logs.svelte
│ │ ├── index.svelte
│ │ ├── settings.svelte
│ │ └── graphs.svelte
│ ├── lib
│ │ ├── graphs
│ │ │ ├── LogLine.svelte
│ │ │ ├── card.svelte
│ │ │ ├── FusionVertical.svelte
│ │ │ ├── BarVerticalOriginal.svelte
│ │ │ ├── StackedBarHorizontal.svelte
│ │ │ ├── StackedBarHorizontalStatus.svelte
│ │ │ ├── StackedBarVerticalOriginal.svelte
│ │ │ ├── Histogram.svelte
│ │ │ └── Table.svelte
│ │ ├── navbar.svelte
│ │ ├── store.ts
│ │ ├── store
│ │ │ └── types.ts
│ │ └── storeProcessing.ts
│ └── electron.cjs
├── .vscode
│ ├── extensions.json
│ └── settings.json
├── globals.d.ts
├── static
│ ├── icon.png
│ ├── favicon.ico
│ ├── favicon.png
│ ├── logo50px.png
│ ├── pteroFull.png
│ ├── background.jpg
│ ├── logoFull30px.png
│ ├── logoFull50px.png
│ ├── sveltekit-electron.svg
│ └── sveltekit-electron1.svg
├── .prettierrc
├── .gitignore
├── jsconfig.json
├── babel.config.js
├── build.config.json
├── jest.config.js
├── global.css
├── .eslintrc.cjs
├── svelte.config.js
├── tsconfig.json
├── __tests
│ └── test.js
├── README.md
└── package.json
├── .gitignore
├── Ptero
├── images
│ ├── soluntion.png
│ └── pteroHighRes.png
├── mod.ts
├── types
│ └── types.ts
├── Dockerfile
├── .env
├── models
│ ├── redisClient.ts
│ ├── dinosaurs.ts
│ ├── users.ts
│ └── APILogModel.ts
├── routers
│ ├── routers.ts
│ ├── userRouter.ts
│ └── apiLogRouter.ts
├── dockerfile-compose.yml
├── controllers
│ ├── users.ts
│ ├── apiKey.ts
│ ├── apiLog.ts
│ └── dinosaurs.ts
├── __tests
│ ├── superoak.test.ts
│ └── redis.test.ts
├── utils
│ ├── dataLogging.ts
│ ├── middlewares.ts
│ └── redis.ts
├── main.ts
├── deps.ts
└── README.md
├── .vscode
└── settings.json
├── README.md
└── .ebextensions
└── .travis.yml
/Client/.env:
--------------------------------------------------------------------------------
1 | MONGODB_URI=
2 | MONGODB_DB=
--------------------------------------------------------------------------------
/Client/src/global.d.ts:
--------------------------------------------------------------------------------
1 | ///

deno upgrade in your terminal.
21 |
22 | ## Contributors
23 | - [Quentin Rousset](https://github.com/qrousset/)
24 | - [Rachel Weller](https://github.com/wellerr3/)
25 | - [Brian Vazquez](https://github.com/brianvazquez9)
26 | - [David Rhee](https://github.com/rheed14)
27 |
28 | ## Other Documents
29 | - PteroView - [README.md](Client/README.md)
30 | - Ptero (server-side) - [README.md](Ptero/README.md)
31 | - For more documentation - [Ptero](https://deno.land/x/ptero) in Deno.land
32 |
--------------------------------------------------------------------------------
/Client/__tests/test.js:
--------------------------------------------------------------------------------
1 | import Counter from './Counter.svelte'
2 | import { render, fireEvent } from '@testing-library/svelte'
3 |
4 | it('it works', async () => {
5 | const { getByText, getByTestId } = render(Counter)
6 |
7 | const increment = getByText('increment')
8 | const decrement = getByText('decrement')
9 | const counter = getByTestId('counter-value')
10 |
11 | await fireEvent.click(increment)
12 | await fireEvent.click(increment)
13 | await fireEvent.click(increment)
14 | await fireEvent.click(decrement)
15 |
16 | expect(counter.textContent).toBe('2')
17 |
18 | // with jest-dom
19 | expect(counter).toHaveTextContent('2')
20 | })
21 |
22 |
23 | // test that routes work on the header
24 |
25 | // testing for settings page
26 | //connection settings test
27 | // test for refresh button
28 | if('refresh button refreshes the logs page', async() => {
29 | const button = ;
30 | const { getByText, getByTestId } = render(button)
31 |
32 | // functional stuff?
33 | const refresh = getByText('refresh')
34 | const counter = getByTestId('refresh-counter')
35 |
36 | await fireEvent.click(button);
37 | await fireEvent.click(button);
38 | //expect content type of fetch request to be json-blah
39 | expect(counter)
40 | expect(refresh).toHaveTextContent('2')
41 | })
42 |
43 |
44 |
45 |
46 |
47 | // test for the "BackEnd Address"
48 | // test for "API key"
49 | //redis settings test
50 | // time to leave update tests
--------------------------------------------------------------------------------
/Ptero/utils/dataLogging.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Keeping track of the users and what information has been accessed is important in managing the RESTful API.
3 | These functinos will allow the API host to visualize all the requests in the server by storing the data into their cloud MongoDB.
4 | If additional information is desired from these logs, simply add variables that you want to monitor and retrieve the appropriate
5 | information from the request and response.
6 | */
7 |
8 | import { addLog } from "../deps.ts";
9 |
10 | export const logData = async (ctx: any, next: any) => {
11 | // Time Logger
12 | const start = Date.now();
13 | await next();
14 | const ms = Date.now() - start;
15 | ctx.response.headers.set("X-Response-Time", `${ms}ms`);
16 | const rt = ctx.response.headers.get("X-Response-Time");
17 |
18 | // logs in the terminal (method - url - response time)
19 | console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
20 |
21 | const ipAddress = ctx.request.ip;
22 | const method = ctx.request.method;
23 | const route = ctx.request.url.pathname;
24 | const status = ctx.response.status;
25 | const fromCache = ctx.request.fromCache;
26 |
27 | // if api key is provided, it is retrieved from the request header, if not api key is equal to null.
28 | let APIKey;
29 | if (ctx.request.headers.has('api_key')) APIKey = ctx.request.headers.get('api_key');
30 | else APIKey = null;
31 |
32 | const data = {
33 | ipAddress,
34 | method,
35 | APIKey,
36 | route,
37 | status,
38 | rt,
39 | fromCache,
40 | };
41 |
42 | // add log to the database
43 | await addLog(data);
44 | };
45 |
--------------------------------------------------------------------------------
/Ptero/utils/middlewares.ts:
--------------------------------------------------------------------------------
1 | /*
2 | These functions will allow the users information and data provided in the route to be stored in
3 | Redis cache. Before caching, these functions will check to see if the information already
4 | exists in the cache. If the data is in the cache, information will be pulled from cache and skip the process
5 | of requesting to the route. Retrieving information from the cache will accerate the whole process of acquiring the data.
6 | You will be able to see the response time difference between when data is accessed from the cache and when they is pulled from the actual route.
7 | */
8 |
9 | import {
10 | redisCheck, redisCheckUser, redisSet, redisSetUser, Context
11 | } from '../deps.ts';
12 |
13 | // checking if data is in Redis cache via redisCheck funciton and if not storing data in to Redis cache via redisCheck function
14 | export const caching = async (ctx: any, func: any) => {
15 | const method: string = ctx.request.method;
16 | const reqURL: string = ctx.request.url.pathname;
17 |
18 | if (await redisCheck(ctx, func) === true) {
19 | ctx.request.fromCache = true;
20 | } else {
21 | ctx.request.fromCache = false;
22 | await redisSet(ctx, 3000);
23 | }
24 | };
25 |
26 | // checking if user is in Redis cache via redisCheckUser funciton and if not storing data in to Redis cache via redisCheckUser function
27 | export const checkUser = async (ctx: Context, func: any) => {
28 | if (await redisCheckUser(ctx) === false) {
29 | await func(ctx);
30 | if (ctx.response.status === 202) await redisSetUser(ctx, 3000);
31 | else console.log("incorect API key");
32 | }
33 | };
34 |
35 |
--------------------------------------------------------------------------------
/Ptero/main.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Application, Router, logData, oakCors, Context, pteroRouter, apiLogRouter, userRouter
3 | } from './deps.ts';
4 | // import { Application, Router, RouterContext } from "https://deno.land/x/oak/mod.ts";
5 | // import { logData } from "./utils/dataLogging.ts";
6 | // import { oakCors } from "https://deno.land/x/cors/mod.ts";
7 | // import { Context } from "https://deno.land/x/oak@v9.0.1/context.ts"
8 | // import pteroRouter from "./routers/routers.ts";
9 | // import apiLogRouter from "./routers/apiLogRouter.ts";
10 | // import userRouter from "./routers/userRouter.ts";
11 | const env = Deno.env.toObject();
12 | const PORT = env.PORT || 9000;
13 | const HOST = env.HOST || "localhost";
14 |
15 | const app = new Application();
16 | const router = new Router();
17 |
18 | app.use(
19 | oakCors({
20 | origin: "http://localhost:3000",
21 | }),
22 | );
23 |
24 | // move this under the 'logData' if you want to log the route to '/log'
25 | app.use(apiLogRouter.prefix("/log").routes());
26 | app.use(userRouter.prefix("/users").routes());
27 |
28 | // Logging of the methods, routes, and response time
29 | app.use(async (ctx, next) => {
30 | await logData(ctx, next);
31 | });
32 |
33 | // routes to "/api"
34 | app.use(pteroRouter.prefix("/api").routes());
35 |
36 | // default methods require to use different routes in Denoo
37 | app.use(router.routes());
38 | app.use(router.allowedMethods());
39 |
40 | // global error handling
41 | router.get("/(.*)", async (ctx: any) => {
42 | ctx.response.status = 404;
43 | ctx.response.body = "404 | Page not Found";
44 | });
45 |
46 | // listening to localhost:PORT
47 | console.log(`Server running on port ${PORT}`);
48 | await app.listen(`${HOST}:${PORT}`);
49 |
--------------------------------------------------------------------------------
/Ptero/controllers/apiLog.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Bson,
3 | Context,
4 | APILog
5 | } from '../deps.ts';
6 |
7 | // retrieve all the logs from the database
8 | export const getLogs = async (ctx: Context, next: any) => {
9 | try {
10 | const data: any = await APILog.find({}, { noCursorTimeout: false }).toArray();
11 | ctx.response.body = {
12 | status: true,
13 | data: data
14 | };
15 | ctx.response.status = 200;
16 | }
17 | catch (err) {
18 | console.log("catch getLog");
19 | ctx.response.body = { status: false, data: null };
20 | ctx.response.status = 500;
21 | console.log(err);
22 | }
23 | };
24 |
25 | // get one log by id
26 | export const getOneLog = async (ctx: any, next: any) => {
27 | try {
28 | const id = ctx.params.id;
29 | const data: any = await APILog.findOne({ _id: new Bson.ObjectId(id) }, { noCursorTimeout: false });
30 |
31 | ctx.response.body = {
32 | status: true,
33 | data: data,
34 | }
35 | ctx.response.status = 200;
36 |
37 | }
38 | catch (err) {
39 | ctx.response.body = { status: false, data: null };
40 | ctx.response.status = 500;
41 | console.log(err);
42 | }
43 | };
44 |
45 | // add new log to database
46 | export const addLog = async (ctx: any) => {
47 | try {
48 | let { method, route, status, APIKey, ipAddress, rt, fromCache } = await ctx;
49 | if (fromCache === undefined) fromCache = false;
50 |
51 | await APILog.insertOne({
52 | method: method,
53 | route: route,
54 | timeAccessed: new Date(),
55 | status: status,
56 | responseTime: rt,
57 | APIKey: APIKey,
58 | ipAddress: ipAddress,
59 | fromCache: fromCache,
60 | });
61 | }
62 | catch (err) {
63 | console.log(err);
64 | };
65 | };
--------------------------------------------------------------------------------
/Ptero/__tests/redis.test.ts:
--------------------------------------------------------------------------------
1 | import {
2 | assertEquals,
3 | delay,
4 | redisConnect,
5 | redisSet,
6 | redisSetUser,
7 | } from "../deps.ts";
8 |
9 | // start redis connection
10 | const redisClient = await redisConnect({
11 | hostname: "server_redis_database",
12 | port: 6379,
13 | });
14 |
15 | // test if pingging redis gets back pong
16 | Deno.test("Check if redis database is connected", async () => {
17 | const ping = await redisClient.ping();
18 | assertEquals(ping, "PONG");
19 | });
20 |
21 | // test if can add object to redis
22 | Deno.test("Adds data to the redis cache", async () => {
23 | const ctx: any = {
24 | request: { url: { pathname: "key1" } },
25 | response: { body: "redis tester" },
26 | };
27 | await redisSet(ctx, 2);
28 |
29 | let data = await redisClient.get("key1");
30 |
31 | Deno.test("Data goes in Cache", async () => {
32 | assertEquals(data, `"${ctx.response.body}"`);
33 | });
34 |
35 | Deno.test("data is delayed and deleted", async () => {
36 | const delayedPromise = delay(2000);
37 | const result = await delayedPromise;
38 | data = await redisClient.get("key1");
39 | assertEquals(data, {});
40 | });
41 | });
42 |
43 | Deno.test("Adds user to the redis cache", async () => {
44 | let newHeaders = new Headers({ api_key: "9999" });
45 | const ctx = {
46 | request: { headers: newHeaders },
47 | response: { body: "user tester" },
48 | };
49 | await redisSetUser(ctx, 2);
50 |
51 | let data = await redisClient.get("9999");
52 |
53 | Deno.test("Data goes in Cache", async () => {
54 | assertEquals(data, `"${ctx.response.body}"`);
55 | });
56 |
57 | Deno.test("User is delayed and deleted after time", async () => {
58 | const delayedPromise = delay(2000);
59 | const result = await delayedPromise;
60 | data = await redisClient.get("9999");
61 | assertEquals(data, {});
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/Ptero/deps.ts:
--------------------------------------------------------------------------------
1 | //from deno.land
2 | import { connect as redisConnect } from "https://deno.land/x/redis/mod.ts";
3 | import { assertEquals } from "https://deno.land/std@0.110.0/testing/asserts.ts";
4 | import { delay } from "https://deno.land/std/async/mod.ts";
5 | import { Application, Router } from "https://deno.land/x/oak@v9.0.1/mod.ts";
6 | import { superoak } from "https://x.nest.land/superoak@4.4.0/mod.ts";
7 | import { MongoClient, Bson } from "https://deno.land/x/mongo@v0.27.0/mod.ts";
8 | import { config } from "https://deno.land/x/dotenv/mod.ts";
9 | import { Context } from "https://deno.land/x/oak@v9.0.1/context.ts"
10 | import { oakCors } from "https://deno.land/x/cors/mod.ts";
11 |
12 | //from within Ptero
13 | import { redisSet, redisSetUser, redisCheck, redisCheckUser } from "./utils/redis.ts";
14 | import apiLogRouter from "./routers/apiLogRouter.ts";
15 | import { getLogs, getOneLog, addLog } from "./controllers/apiLog.ts";
16 | import { checkApiKey } from "./controllers/apiKey.ts";
17 | import { caching, checkUser } from "./utils/middlewares.ts";
18 | import { getUser, getUsers } from "./controllers/users.ts"
19 | import { APILog } from "./models/APILogModel.ts";
20 | import { db, Users } from './models/users.ts';
21 | import { redisClient } from "./models/redisClient.ts";
22 | import { logData } from "./utils/dataLogging.ts";
23 | import pteroRouter from "./routers/routers.ts";
24 | import userRouter from "./routers/userRouter.ts";
25 |
26 | export {
27 | redisConnect,
28 | assertEquals,
29 | redisSet,
30 | redisSetUser,
31 | delay,
32 | Application,
33 | Router,
34 | superoak,
35 | apiLogRouter,
36 | getLogs,
37 | MongoClient,
38 | Bson,
39 | config,
40 | Context,
41 | getOneLog,
42 | APILog,
43 | db,
44 | Users,
45 | checkApiKey,
46 | caching,
47 | checkUser,
48 | getUser,
49 | getUsers,
50 | addLog,
51 | redisCheck,
52 | redisCheckUser,
53 | redisClient,
54 | logData,
55 | oakCors,
56 | pteroRouter,
57 | userRouter
58 | }
--------------------------------------------------------------------------------
/Client/src/routes/logs.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | | Status | 13 |Method | 14 |Route | 15 |Date | 16 |Response Time | 17 |API Key | 18 |Cached | 19 |||||
|---|---|---|---|---|---|---|---|---|---|---|
| {log.status} | 27 | {:else if log.status >= 500} 28 |{log.status} | 29 | {:else} 30 |{log.status} | 31 | {/if} 32 |{log.method} | 35 | {:else if log.method === 'PUT' || log.method === 'POST'} 36 |{log.method} | 37 | {:else} 38 |{log.method} | 39 | {/if} 40 | 41 | 42 |{log.route} | 43 |{new Date(log.time).toUTCString()} | 44 |{log.respTime} | 45 |{log.key} | 46 |{log.cached} | 47 | 48 |
npm install |
10 | | Develop | npm run dev |
11 | | Develop | npm run dev:svelte |
12 | | Build | npm run build |
13 |
14 |
15 | To get started on PteroView make sure the server that hosts your log data is running, then simply install and open the PteroView app. There you will be greated by the opening page, go into settings and paste in the URI to your log stream. At this point you should be able to edit certain settings in the setting page including refresh rate as well as a manual refresh button.
16 |
17 | From here you can see the graphs page as well as the home page to see a variaty of graphs and statistics about your logs. The logs themselves can be find under the log tab.
18 |
19 | ## Metrics
20 | Following model is all the information that is collected with the Ptero Deno module.
21 | ```js
22 | interface LogSchema {
23 | _id: { $oid: string },
24 | method: string,
25 | route: string,
26 | timeAccessed: Date,
27 | status: string,
28 | responseTime: string,
29 | APIKey: string,
30 | ipAddress: string,
31 | fromCache: boolean,
32 | }
33 | ```
34 | ### Requests per day over the last month
35 | - It is a vertical line graph that shows how many requests were made to the API depending on the day of the month.
36 |
37 | 
38 |
39 | ### Avg cached time against non-cached
40 | - Simple GUI that shows the average time of the data retrieved from cache verses the average time of the data pulled from the server.
41 |
42 | 
43 |
44 | ### Methods per status
45 | - It is a horizontal line graph that shows what type of methods executed with different status codes differentiated by color.
46 |
47 | 
48 |
49 | ### Requests per endpoint and method
50 | - It is a horizontal line graph that shows what type of methods were requested to the different endpoint of the API's.
51 |
52 | 
53 |
54 | ### More to Come!
55 | - The open source nature of our project means that new visualizations can be added using the data already collected from the Ptero module. Including user metrics, cached statistics, and usage over time!
56 |
--------------------------------------------------------------------------------
/Client/src/lib/graphs/StackedBarVerticalOriginal.svelte:
--------------------------------------------------------------------------------
1 |
28 |
29 | _checkApiKey_ function from the below code.
25 |
26 | ### To Set-up Redis:
27 | - Make sure you have Redis installed in your machine.
28 | - To install Redis, check out the [Redis Quick Start Guide](https://redis.io/topics/quickstart).
29 | - Run a Redis instance:
30 | - For Mac Users:
31 | - type redis-cli in your terminal.
32 | - For WSL/Windows Users:
33 | - type: sudo service redis-server start in your terminal.
34 | - then type: redis-cli in your terminal.
35 | - keys * gets all of the keys stored in Redis cache.
36 | - get (key) gets the value associated with the key.
37 |
38 | ### Prerequisite
39 | ```js
40 | // Example Routing
41 | const testRouter = new Router();
42 | ```
43 | This code along with an import statement for it should be put into the router that would route the user to the api key checking.
44 | ```js
45 | // If the server requires an api key
46 | testRouter.use("/", async (ctx: Context, next: any) => {
47 | await checkUser(ctx, checkApiKey);
48 | if (ctx.response.status === 401) return;
49 | await next();
50 | });
51 | ```
52 | This code along with an import statement for it should be put into the router that would route the user to the data.
53 | ```js
54 | // Example Get Method
55 | testRouter.get("/endpoint", async (ctx: Context, next: any) => {
56 | await caching(ctx, getController);
57 | });
58 | ```
59 |
60 | ## Testing
61 | We have build our test suites using a Deno third party module: [SuperOak](https://deno.land/x/superoak@4.4.0). SuperOak was used for testing HTTP in Deno's Oak web framework. Deno also has built-in testing using __*Deno.test*__, which was used in our application to test Redis caching of the server.
62 |
63 | ## Dependencies
64 | - [Oak](https://deno.land/x/oak@v9.0.1)
65 | - [Redis](https://deno.land/x/redis@v0.25.0)
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Client/src/lib/graphs/Table.svelte:
--------------------------------------------------------------------------------
1 |
107 |
--------------------------------------------------------------------------------
/Client/static/sveltekit-electron.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/Client/static/sveltekit-electron1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/Client/src/lib/storeProcessing.ts:
--------------------------------------------------------------------------------
1 | /* This file is used to store the different functions supporting the computation
2 | * of the difference pieces of state used in the graphs */
3 | import type {
4 | Logs,
5 | DailyData,
6 | interfaceReqPerEndpointAndMethod,
7 | interfaceReqPerStatus,
8 | DayRouteTotal,
9 | RouteDaily,
10 | TempDate,
11 | TotalsPerStatus,
12 | } from "./store/types.ts";
13 |
14 | const totalsPerStatus = async (tempLogs: Logs[], TotalsStatus) => {
15 | const totalsPerStatusObj: TotalsPerStatus = {};
16 | const totalsPerStatusArr: TotalsPerStatus[] = [];
17 |
18 | await tempLogs.forEach((el: Logs) => {
19 | if (!totalsPerStatusObj[el.status]) totalsPerStatusObj[el.status] = 0;
20 | totalsPerStatusObj[el.status] += 1;
21 | });
22 | for (const status in totalsPerStatusObj) {
23 | const temp: any = {};
24 | temp[status] = totalsPerStatusObj[status];
25 | totalsPerStatusArr.push(temp);
26 | }
27 | TotalsStatus.set(totalsPerStatusArr);
28 | return;
29 | };
30 |
31 | const reqPerEndpointAndMethodFn = async (tempLogs: Logs[], ReqPerEndpointAndMethod: interfaceReqPerEndpointAndMethod) => {
32 | const routeObj: interfaceReqPerEndpointAndMethod = {};
33 | const tempIndexBars = [];
34 |
35 | tempLogs.forEach((el: Logs, index: number) => {
36 | if (!routeObj[el.route]) {
37 | routeObj[el.route] = {
38 | route: el.route,
39 | GET: 0,
40 | POST: 0,
41 | PUT: 0,
42 | DELETE:0,
43 | id: index + 1,
44 | tot: 0
45 | };
46 | }
47 | if (el.method === "GET") routeObj[el.route]["GET"] += 1;
48 | else if (el.method === "POST") routeObj[el.route]["POST"] += 1;
49 | else if (el.method === "PUT") routeObj[el.route]["PUT"] += 1;
50 | else if (el.method === "DELETE") routeObj[el.route]["DELETE"] += 1;
51 | routeObj[el.route]["tot"] += 1;
52 | });
53 |
54 | for (const route in routeObj) {
55 | tempIndexBars.push(routeObj[route]);
56 | }
57 |
58 | await tempIndexBars.sort((a, b) => {
59 | return b["tot"] - a["tot"];
60 | });
61 | await tempIndexBars.forEach((element, index) => {
62 | element.id = index + 1;
63 | });
64 | await ReqPerEndpointAndMethod.set(tempIndexBars);
65 | return;
66 | };
67 |
68 | const reqPerStatusAndMethodProcess = async (
69 | tempLogs: Logs[],
70 | ReqPerStatusAndMethod: interfaceReqPerStatus,
71 | ) => {
72 | const statusObj: interfaceReqPerStatus = {};
73 | const tempStatusObj = [];
74 |
75 | tempLogs.forEach((el, index: number) => {
76 | // const test = {};
77 | // test["status"] = el.status;
78 | if (!statusObj[el.status]) {
79 | statusObj[el.status] = {
80 | status: el.status,
81 | GET: 0,
82 | POST: 0,
83 | PUT: 0,
84 | DELETE:0,
85 | id: index + 1,
86 | tot: 0
87 | };
88 | }
89 | if (el.method === "GET") statusObj[el.status]["GET"] += 1;
90 | else if (el.method === "POST") statusObj[el.status]["POST"] += 1;
91 | else if (el.method === "PUT") statusObj[el.status]["PUT"] += 1;
92 | else if (el.method === "DELETE") statusObj[el.status]["DELETE"] += 1;
93 | statusObj[el.status]["tot"] += 1;
94 | });
95 |
96 | for (const route in statusObj) {
97 | tempStatusObj.push(statusObj[route]);
98 | }
99 |
100 | await tempStatusObj.sort((a, b) => {
101 | return b["tot"] - a["tot"];
102 | });
103 | await tempStatusObj.forEach((element, index) => {
104 | element.id = index + 1;
105 | });
106 | await ReqPerStatusAndMethod.set(tempStatusObj);
107 |
108 | return;
109 | };
110 |
111 | const avgRspTimeCvsNC = async (tempLogs: Logs[], CachedvsNotCached: any) => {
112 | const avg = { cached: 0, notCached: 0 };
113 | const cached = { time: 0, num: 0 };
114 | const notCached = { time: 0, num: 0 };
115 |
116 | tempLogs.forEach((logs) => {
117 | if (logs.cached === true) {
118 | cached.time = cached.time + parseInt(logs.respTime, 10);
119 | cached.num += 1;
120 | } else {
121 | notCached.time += parseInt(logs.respTime, 10);
122 | notCached.num += 1;
123 | }
124 | });
125 | avg.cached = Math.floor(cached.time / cached.num);
126 | avg.notCached = Math.floor(notCached.time / notCached.num);
127 | CachedvsNotCached.set(avg);
128 | return;
129 | };
130 |
131 | const routePerDay = async (tempLogs: Logs[], DailyData: DailyData, DayRouteTotal: DayRouteTotal) => {
132 | const tempDailyData: DailyData = {};
133 | await tempLogs.forEach((log: any) => {
134 | const route = log.route;
135 | const date = log.time;
136 | const year = date.substring(0, 4);
137 | const month = date.substring(5, 7);
138 | const day = date.substring(8, 10);
139 | // const strDate = `${year}/${month}/${day}`;
140 | const strDate = day;
141 |
142 | if (!tempDailyData[strDate]) {
143 | tempDailyData[strDate] = {totals: 0};
144 | // tempDailyData[strDate]["totals"] = 0;
145 | }
146 | tempDailyData[strDate]["totals"] += 1;
147 | if (!tempDailyData[strDate][route]) {
148 | tempDailyData[strDate][route] = {
149 | "total": 0,
150 | "status": {},
151 | "cached": { "cached": 0, "notCached": 0 },
152 | };
153 | }
154 | tempDailyData[strDate][route]["total"] += 1;
155 | if (log.cached === true) {
156 | tempDailyData[strDate][route]["cached"]["cached"] += 1;
157 | } else tempDailyData[strDate][route]["cached"]["notCached"] += 1;
158 |
159 | if (!tempDailyData[strDate][route]["status"][log.status]) {
160 | tempDailyData[strDate][route]["status"][log.status] = 0;
161 | }
162 | tempDailyData[strDate][route]["status"][log.status] += 1;
163 | });
164 |
165 | DailyData.set(tempDailyData);
166 |
167 | const tempDayRouteTotal = [];
168 | let id = 0;
169 | for (const key in tempDailyData) {
170 | for (const prop in tempDailyData[key]) {
171 | if (prop !== "totals") {
172 | const currentObj: DayRouteTotal = {
173 | date: parseInt(key),
174 | route: prop,
175 | total: tempDailyData[key][prop]["total"],
176 | id: id,
177 | };
178 | tempDayRouteTotal.push(currentObj);
179 | id++;
180 | }
181 | }
182 | }
183 | DayRouteTotal.set(tempDayRouteTotal);
184 | return;
185 | };
186 |
187 | const RouteHistoryProcess = async (tempLogs: Logs[], RouteHistory: any) => {
188 | const tempRouteDaily: RouteDaily = {}
189 | await tempLogs.forEach((log: Logs) => {
190 | const route: string = log.route;
191 | const date: string = log.time;
192 | const year = date.substring(0, 4);
193 | const month = date.substring(5, 7);
194 | const day = date.substring(8, 10);
195 | const strDate = `${day}`;
196 |
197 | if (!tempRouteDaily[route]) tempRouteDaily[route] = {};
198 | if (!tempRouteDaily[route][strDate]) tempRouteDaily[route][strDate] = 0;
199 | tempRouteDaily[route][strDate]++;
200 | });
201 |
202 | const allDays: string[] = [];
203 | for (const key in tempRouteDaily) {
204 | for (const day in tempRouteDaily[key]) {
205 | // console.log(day);
206 | if (!allDays.includes(day)) allDays.push(day);
207 | }
208 | }
209 |
210 | const DailyCallsPerRoute = [];
211 | for (const key in tempRouteDaily) {
212 | const currentObj = { name: "", data: [] };
213 | currentObj.name = key;
214 | for (const day in allDays) {
215 | if (tempRouteDaily[key][allDays[day]]) {
216 | const tempDate: TempDate = {
217 | x: parseFloat(allDays[day]),
218 | y: tempRouteDaily[key][allDays[day]]
219 | };
220 | currentObj.data.push(tempDate);
221 | }
222 | }
223 | DailyCallsPerRoute.push(currentObj);
224 | }
225 | RouteHistory.set(DailyCallsPerRoute);
226 | // console.log(DailyCallsPerRoute);
227 | return;
228 | };
229 |
230 | export {
231 | avgRspTimeCvsNC,
232 | reqPerEndpointAndMethodFn,
233 | reqPerStatusAndMethodProcess,
234 | RouteHistoryProcess,
235 | routePerDay,
236 | totalsPerStatus,
237 | };
238 |
--------------------------------------------------------------------------------