expressjs-stats 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
+ }