mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 12:07:08 +00:00
Add diagnostics API endpoint.
Only available with write access and above. Reports used and available filesystem sizes and database space usage.
This commit is contained in:
@@ -312,6 +312,9 @@ app.map({
|
||||
}
|
||||
}
|
||||
},
|
||||
'/diagnostics/': {
|
||||
get: [ mw.auth.access.write, mw.etag.noSave, mw.admin.diagnostics.get ]
|
||||
},
|
||||
'/rss/': {
|
||||
get: [ mw.rss.get ]
|
||||
}
|
||||
|
||||
17
lib/www/server/api/middleware/admin/diagnostics/get.js
Normal file
17
lib/www/server/api/middleware/admin/diagnostics/get.js
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
const diagnostics = require('../../../../lib/diagnostics');
|
||||
|
||||
module.exports = async function (req, res, next) {
|
||||
|
||||
try {
|
||||
const d = await diagnostics();
|
||||
if (req.user?.role != "admin" && req.user?.role != "user") {
|
||||
}
|
||||
res.status(200).json(d);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
next();
|
||||
|
||||
};
|
||||
4
lib/www/server/api/middleware/admin/diagnostics/index.js
Normal file
4
lib/www/server/api/middleware/admin/diagnostics/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
module.exports = {
|
||||
get: require('./get')
|
||||
}
|
||||
3
lib/www/server/api/middleware/admin/index.js
Normal file
3
lib/www/server/api/middleware/admin/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
diagnostics: require('./diagnostics')
|
||||
};
|
||||
@@ -18,5 +18,6 @@ module.exports = {
|
||||
openapi: require('./openapi'),
|
||||
rss: require('./rss'),
|
||||
etag: require('./etag'),
|
||||
version: require('./version')
|
||||
version: require('./version'),
|
||||
admin: require('./admin')
|
||||
};
|
||||
|
||||
92
lib/www/server/lib/diagnostics.js
Normal file
92
lib/www/server/lib/diagnostics.js
Normal file
@@ -0,0 +1,92 @@
|
||||
const { statfs } = require('fs').promises;
|
||||
const { pool } = require('./db/connection');
|
||||
const cfg = require('./config');
|
||||
const { ALERT, ERROR, WARNING, NOTICE, INFO, DEBUG } = require('DOUGAL_ROOT/debug')(__filename);
|
||||
|
||||
|
||||
/** Return filesystem statistics
|
||||
*/
|
||||
async function df (fs="/") {
|
||||
const s = await statfs(fs);
|
||||
|
||||
if (s) {
|
||||
const total = (s.bsize * s.blocks); // bytes
|
||||
const free = (s.bfree * s.bsize);
|
||||
const available = (s.bavail * s.bsize);
|
||||
const used = total - free;
|
||||
const usedPercent = used/total * 100
|
||||
return {
|
||||
total,
|
||||
free,
|
||||
available,
|
||||
used,
|
||||
usedPercent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the size of the Dougal database
|
||||
*/
|
||||
async function dbSize () {
|
||||
const client = await pool.connect();
|
||||
let res;
|
||||
try {
|
||||
res = (await client.query("SELECT pg_database_size(current_database()) size;"))?.rows[0];
|
||||
} catch (err) {
|
||||
ERROR(err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async function dbSchemaSizes () {
|
||||
const text = `
|
||||
SELECT pid,
|
||||
(sum(table_size)::bigint) size,
|
||||
((sum(table_size) / pg_database_size(current_database())) * 100) percent
|
||||
FROM (
|
||||
SELECT pg_catalog.pg_namespace.nspname as schema_name,
|
||||
pg_relation_size(pg_catalog.pg_class.oid) as table_size
|
||||
FROM pg_catalog.pg_class
|
||||
JOIN pg_catalog.pg_namespace ON relnamespace = pg_catalog.pg_namespace.oid
|
||||
) t
|
||||
JOIN public.projects p ON schema_name = p.schema
|
||||
GROUP BY pid
|
||||
ORDER BY pid
|
||||
`;
|
||||
|
||||
const client = await pool.connect();
|
||||
let res;
|
||||
try {
|
||||
res = (await client.query(text))?.rows;
|
||||
} catch (err) {
|
||||
ERROR(err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async function diagnostics () {
|
||||
const paths = cfg._("global.imports.paths") ?? {};
|
||||
const data = {};
|
||||
for (path in paths) {
|
||||
data[path] = await df(paths[path]);
|
||||
}
|
||||
const res = {
|
||||
storage: {
|
||||
root: await df("/"),
|
||||
data
|
||||
},
|
||||
database: {
|
||||
...(await dbSize()),
|
||||
projects: Object.fromEntries((await dbSchemaSizes()).map(row => [ row.pid, {size: row.size, percent: row.percent} ]))
|
||||
}
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
module.exports = diagnostics;
|
||||
Reference in New Issue
Block a user