From a908125ea3716e17795e3d4a2f1e6ff771d36399 Mon Sep 17 00:00:00 2001 From: Jonny McCullagh Date: Mon, 20 Feb 2023 19:56:04 +0000 Subject: [PATCH] add metrics endpoint to api --- .../src/api/controllers/public/metrics.ts | 122 ++++++++++++++++++ .../server/src/api/routes/public/index.ts | 2 + .../server/src/api/routes/public/metrics.ts | 28 ++++ 3 files changed, 152 insertions(+) create mode 100644 packages/server/src/api/controllers/public/metrics.ts create mode 100644 packages/server/src/api/routes/public/metrics.ts diff --git a/packages/server/src/api/controllers/public/metrics.ts b/packages/server/src/api/controllers/public/metrics.ts new file mode 100644 index 0000000000..264df7f415 --- /dev/null +++ b/packages/server/src/api/controllers/public/metrics.ts @@ -0,0 +1,122 @@ +import { App, BBContext } from "@budibase/types" +import { db as dbCore, context } from "@budibase/backend-core" +import os from "os" + +export async function fetch(ctx: BBContext) { + const allDatabases = await dbCore.getAllDbs() + const devAppIDs = await dbCore.getDevAppIDs({ idsOnly: true }) + const prodAppIDs = await dbCore.getProdAppIDs({ idsOnly: true }) + const allAppIds = await dbCore.getAllApps({ idsOnly: true }) + + var outputString = "" + + const freeMem = os.freemem() + const totalMem = os.totalmem() + const usedMem = totalMem - freeMem + const uptime = os.uptime() + + // **** budibase_os_uptime **** + outputString += convertToOpenMetrics( + "budibase_os_uptime", + "Time in seconds that the host operating system has been up", + "counter", + uptime + ) + + // **** budibase_os_free_mem **** + outputString += convertToOpenMetrics( + "budibase_os_free_mem", + "Bytes of memory free for usage on the host operating system", + "gauge", + freeMem + ) + + // **** budibase_os_total_mem **** + outputString += convertToOpenMetrics( + "budibase_os_total_mem", + "Total bytes of memory on the host operating system", + "gauge", + totalMem + ) + + // **** budibase_os_used_mem **** + outputString += convertToOpenMetrics( + "budibase_os_used_mem", + "Total bytes of memory in use on the host operating system", + "gauge", + usedMem + ) + + // **** budibase_os_load1 **** + outputString += convertToOpenMetrics( + "budibase_os_load1", + "Host operating system load average", + "gauge", + os.loadavg()[0] + ) + + // **** budibase_os_load5 **** + outputString += convertToOpenMetrics( + "budibase_os_load5", + "Host operating system load average", + "gauge", + os.loadavg()[1] + ) + // **** budibase_os_load15 **** + outputString += convertToOpenMetrics( + "budibase_os_load15", + "Host operating system load average", + "gauge", + os.loadavg()[2] + ) + + // **** budibase_tenant_app_count **** + outputString += convertToOpenMetrics( + "budibase_tenant_app_count", + "The number of apps created by a user", + "gauge", + allAppIds.length + ) + + // **** budibase_tenant_production_app_count **** + outputString += convertToOpenMetrics( + "budibase_tenant_production_app_count", + "The number of apps a user has published", + "gauge", + prodAppIDs.length + ) + + // **** budibase_tenant_dev_app_count **** + outputString += convertToOpenMetrics( + "budibase_tenant_dev_app_count", + "The number of apps a user has unpublished in development", + "gauge", + devAppIDs.length + ) + + // **** budibase_tenant_db_count **** + outputString += convertToOpenMetrics( + "budibase_tenant_db_count", + "The number of couchdb databases including global tables such as _users", + "gauge", + allDatabases.length + ) + + ctx.body = outputString +} + +export function convertToOpenMetrics( + metricName: string, + metricHelp: string, + metricType: string, + metricValue: number +) { + return ` + # HELP ${metricName} ${metricHelp}. + # TYPE ${metricName} ${metricType} + ${metricName} ${metricValue}` +} + +export default { + fetch, +} diff --git a/packages/server/src/api/routes/public/index.ts b/packages/server/src/api/routes/public/index.ts index 79e7731752..e67c10fe02 100644 --- a/packages/server/src/api/routes/public/index.ts +++ b/packages/server/src/api/routes/public/index.ts @@ -1,4 +1,5 @@ import appEndpoints from "./applications" +import metricEndpoints from "./metrics" import queryEndpoints from "./queries" import tableEndpoints from "./tables" import rowEndpoints from "./rows" @@ -120,6 +121,7 @@ function applyRoutes( } applyRoutes(appEndpoints, PermissionType.APP, "appId") +applyRoutes(metricEndpoints, PermissionType.APP, "appId") applyRoutes(tableEndpoints, PermissionType.TABLE, "tableId") applyRoutes(userEndpoints, PermissionType.USER, "userId") applyRoutes(queryEndpoints, PermissionType.QUERY, "queryId") diff --git a/packages/server/src/api/routes/public/metrics.ts b/packages/server/src/api/routes/public/metrics.ts new file mode 100644 index 0000000000..67cae14388 --- /dev/null +++ b/packages/server/src/api/routes/public/metrics.ts @@ -0,0 +1,28 @@ +import controller from "../../controllers/public/metrics" +import Endpoint from "./utils/Endpoint" + +const read = [] + +/** + * @openapi + * /metrics: + * get: + * operationId: getById + * summary: Retrieve Budibase tenant metrics + * description: Output metrics in openMetrics format compatible with Prometheus + * tags: + * - metrics + * responses: + * 200: + * description: Returns tenant metrics. + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/tableOutput' + * examples: + * table: + * $ref: '#/components/examples/table' + */ +read.push(new Endpoint("get", "/metrics", controller.fetch)) + +export default { read }