expressjs-stats 1.0.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of expressjs-stats might be problematic. Click here for more details.

package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # **Simple and easy statistics**
2
+
3
+ `expressjs-stats` is a small NPM package that allows you to create simple statistics for your ExpressJS REST API.
4
+
5
+ ### **Installation**
6
+
7
+ ```bash
8
+ npm install expressjs-stats
9
+ ```
10
+
11
+ ## **Middleware implementation**
12
+
13
+ The setup is super easy and done in under a minute. Just import `routesTracker` from `expressjs-stats`:
14
+
15
+ ```js
16
+ const { routesTracker } = require('expressjs-stats')
17
+ ```
18
+
19
+ After that add it to any route you want to get tracked.
20
+
21
+ ```js
22
+ app.get('/', routesTracker, async (req, res) => {
23
+ return res.send('Awesome!')
24
+ })
25
+ ```
26
+
27
+ And you are completely done. Congratulations!
28
+
29
+ ## **Get statistics data**
30
+
31
+ We do not only want to track them but also access the data. Simply import `getStats` from `expressjs-stats`.
32
+
33
+ ```js
34
+ const { routesTracker, getStats } = require('expressjs-stats')
35
+ ```
36
+
37
+ Now await this function anywhere you want and get the data.
38
+
39
+ ```js
40
+ app.get('/stats', routesTracker, async(req, res) => {
41
+ const stats = await getStats()
42
+ return res.send(stats)
43
+ })
44
+ ```
45
+
46
+ There's also the `range` option. You can define the time period in which you want to get all the data. The default value is `alltime`.
47
+
48
+ **Examples:**
49
+ - `20min`
50
+ - `3d`
51
+ - `90d`
52
+ - `1y`
53
+
54
+ ```js
55
+ app.get('/stats', routesTracker, async(req, res) => {
56
+ const stats = await getStats(range = '1h')
57
+ return res.send(stats)
58
+ })
59
+ ```
60
+
61
+ **Example Response:**
62
+ ```json
63
+ ```
package/index.js ADDED
@@ -0,0 +1,109 @@
1
+ const { PrismaClient } = require('@prisma/client')
2
+ const prisma = new PrismaClient()
3
+
4
+ const DeviceDetector = require("device-detector-js");
5
+ const deviceDetector = new DeviceDetector();
6
+
7
+ const ms = require('ms')
8
+
9
+ async function routesTracker(req, res, next) {
10
+ const informations = deviceDetector.parse(req.headers['user-agent'])
11
+
12
+ var data = {
13
+ ip: null,
14
+ browser: null,
15
+ os: null,
16
+ device: null,
17
+ route: null,
18
+ timestamp: +new Date()
19
+ }
20
+
21
+ try { data.ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress } catch (error) {}
22
+ if(data.ip == '::1') data.ip = 'localhost'
23
+ try { data.browser = informations.client.type } catch (error) {}
24
+ try { data.os = informations.os.name } catch (error) {}
25
+ try { data.device = informations.device.type } catch (error) {}
26
+ try { data.route = req.path } catch (error) {}
27
+
28
+ await prisma.requests.create({
29
+ data: data,
30
+ })
31
+
32
+ next()
33
+ }
34
+
35
+ async function getStats( range = 'alltime') {
36
+ var time_period = 0
37
+ if(range !== 'alltime') time_period = ms(range)
38
+ if(!time_period) return 'Invalid range'
39
+
40
+ var timestamp_gte = 0
41
+ if(range !== 'alltime') timestamp_gte = +new Date() - time_period
42
+
43
+ const getData = await prisma.requests.findMany({
44
+ where: {
45
+ timestamp: {
46
+ gte: timestamp_gte
47
+ },
48
+ }
49
+ })
50
+
51
+ const ips = [...new Set(getData.map(data => data.ip))]
52
+ const devices = [...new Set(getData.map(data => data.device))]
53
+ const os = [...new Set(getData.map(data => data.os))]
54
+ const browsers = [...new Set(getData.map(data => data.browser))]
55
+ const routes = [...new Set(getData.map(data => data.route))]
56
+
57
+ const categories = ['ip', 'device', 'os', 'browser', 'route']
58
+ const values = [ips, devices, os, browsers, routes]
59
+
60
+ var dataArray = {}
61
+
62
+ const totalAmount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte } } })
63
+
64
+ dataArray['time_range'] = range
65
+ dataArray['total_requests'] = totalAmount
66
+ dataArray['unique_users'] = ips.length
67
+
68
+ for (let index = 0; index < categories.length; index++) {
69
+ var catgAmount = 0
70
+
71
+ if(categories[index] === 'device') catgAmount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { device: null } } })
72
+ if(categories[index] === 'os') catgAmount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { os: null } } })
73
+ if(categories[index] === 'browser') catgAmount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { browser: null } } })
74
+ if(categories[index] === 'route') catgAmount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte } } })
75
+
76
+ var categoryDataArray = []
77
+
78
+ if(categories[index] !== 'ip') {
79
+ for (let i = 0; i < values[index].length; i++) {
80
+ const element = values[index][i]
81
+
82
+ if(element) {
83
+ var amount = 0
84
+
85
+ if(categories[index] === 'device') amount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { device: null }, device: element } })
86
+ if(categories[index] === 'os') amount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { os: null }, os: element } })
87
+ if(categories[index] === 'browser') amount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, NOT: { browser: null }, browser: element } })
88
+ if(categories[index] === 'route') amount = await prisma.requests.count({ where: { timestamp: { gte: timestamp_gte }, route: element } })
89
+
90
+ const percentage = (amount / catgAmount * 100).toFixed(2)
91
+
92
+ categoryDataArray.push({
93
+ name: element,
94
+ requests: amount,
95
+ percentage: percentage + '%'
96
+ })
97
+ }
98
+ }
99
+
100
+ categoryDataArray.sort((a, b) => parseFloat(b.requests) - parseFloat(a.requests))
101
+
102
+ dataArray[categories[index]] = categoryDataArray
103
+ }
104
+ }
105
+
106
+ return dataArray
107
+ }
108
+
109
+ module.exports = { routesTracker, getStats }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "expressjs-stats",
3
+ "version": "1.0.7",
4
+ "description": "Simple and easy statistics for your expressjs REST API",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "postinstall": "prisma generate && prisma migrate dev --name init"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/JannisMilz/expressjs-stats.git"
13
+ },
14
+ "keywords": [
15
+ "expressjs",
16
+ "statistics",
17
+ "middleware"
18
+ ],
19
+ "author": "AquaDev",
20
+ "license": "ISC",
21
+ "bugs": {
22
+ "url": "https://github.com/JannisMilz/expressjs-stats/issues"
23
+ },
24
+ "homepage": "https://github.com/JannisMilz/expressjs-stats#readme",
25
+ "dependencies": {
26
+ "@prisma/client": "^3.12.0",
27
+ "prisma": "^3.12.0",
28
+ "device-detector-js": "^3.0.3",
29
+ "ms": "^2.1.3"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^17.0.27",
33
+ "express": "^4.18.0",
34
+ "sqlite": "^4.1.1",
35
+ "ts-node": "^10.7.0",
36
+ "typescript": "^4.6.3"
37
+ }
38
+ }
@@ -0,0 +1,18 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "sqlite"
7
+ url = "file:./requests.db"
8
+ }
9
+
10
+ model requests {
11
+ id Int @id @default(autoincrement())
12
+ ip String?
13
+ device String?
14
+ os String?
15
+ browser String?
16
+ route String
17
+ timestamp Decimal
18
+ }