From bb28d09eababb682930d53512d931efd09188d2c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 10 Jul 2023 13:25:24 +0200 Subject: [PATCH] Add logs endpoint --- packages/backend-core/src/logging/index.ts | 1 + .../backend-core/src/logging/localLogging.ts | 20 ----------- .../backend-core/src/logging/pino/logger.ts | 2 +- packages/backend-core/src/logging/system.ts | 33 +++++++++++++++++++ packages/frontend-core/src/api/index.js | 2 ++ packages/frontend-core/src/api/logs.js | 14 ++++++++ packages/frontend-core/src/utils/download.js | 14 ++++++++ packages/frontend-core/src/utils/index.js | 2 +- .../worker/src/api/controllers/system/logs.ts | 8 +++++ packages/worker/src/api/routes/index.ts | 2 ++ packages/worker/src/api/routes/system/logs.ts | 9 +++++ 11 files changed, 85 insertions(+), 22 deletions(-) delete mode 100644 packages/backend-core/src/logging/localLogging.ts create mode 100644 packages/backend-core/src/logging/system.ts create mode 100644 packages/frontend-core/src/api/logs.js create mode 100644 packages/worker/src/api/controllers/system/logs.ts create mode 100644 packages/worker/src/api/routes/system/logs.ts diff --git a/packages/backend-core/src/logging/index.ts b/packages/backend-core/src/logging/index.ts index b87062c478..f7e1c4fa41 100644 --- a/packages/backend-core/src/logging/index.ts +++ b/packages/backend-core/src/logging/index.ts @@ -1,6 +1,7 @@ export * as correlation from "./correlation/correlation" export { logger } from "./pino/logger" export * from "./alerts" +export * as system from "./system" // turn off or on context logging i.e. tenantId, appId etc export let LOG_CONTEXT = true diff --git a/packages/backend-core/src/logging/localLogging.ts b/packages/backend-core/src/logging/localLogging.ts deleted file mode 100644 index bd42ce08d1..0000000000 --- a/packages/backend-core/src/logging/localLogging.ts +++ /dev/null @@ -1,20 +0,0 @@ -import fs from "fs" -import path from "path" -import * as rfs from "rotating-file-stream" - -import env from "../environment" -import { budibaseTempDir } from "../objectStore" - -export function localFileDestination() { - const fileName = path.join(budibaseTempDir(), `budibase.logs`) - const outFile = rfs.createStream(fileName, { - size: env.ROLLING_LOG_MAX_SIZE, - teeToStdout: true, - }) - - outFile.on("rotation", () => { - fs.copyFileSync(fileName, `${fileName}.bak`) - }) - - return outFile -} diff --git a/packages/backend-core/src/logging/pino/logger.ts b/packages/backend-core/src/logging/pino/logger.ts index 0689ba6af2..0b130068f3 100644 --- a/packages/backend-core/src/logging/pino/logger.ts +++ b/packages/backend-core/src/logging/pino/logger.ts @@ -8,7 +8,7 @@ import * as context from "../../context" import * as correlation from "../correlation" import { LOG_CONTEXT } from "../index" -import { localFileDestination } from "../localLogging" +import { localFileDestination } from "../system" // LOGGER diff --git a/packages/backend-core/src/logging/system.ts b/packages/backend-core/src/logging/system.ts new file mode 100644 index 0000000000..7bca469e5c --- /dev/null +++ b/packages/backend-core/src/logging/system.ts @@ -0,0 +1,33 @@ +import fs from "fs" +import path from "path" +import * as rfs from "rotating-file-stream" + +import env from "../environment" +import { budibaseTempDir } from "../objectStore" + +const logsFileName = path.join(budibaseTempDir(), `budibase.logs`) +const rollingFileName = `${logsFileName}.bak` + +export function localFileDestination() { + const outFile = rfs.createStream(logsFileName, { + size: env.ROLLING_LOG_MAX_SIZE, + teeToStdout: true, + }) + + outFile.on("rotation", () => { + fs.copyFileSync(logsFileName, rollingFileName) + }) + + return outFile +} + +export function getLogReadStream() { + const logsContent = fs.readFileSync(logsFileName) + if (!fs.existsSync(rollingFileName)) { + return logsContent + } + + const rollingContent = fs.readFileSync(rollingFileName) + const combinedContent = Buffer.concat([logsContent, rollingContent]) + return combinedContent +} diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js index 7b823d28c2..5bffb82f4d 100644 --- a/packages/frontend-core/src/api/index.js +++ b/packages/frontend-core/src/api/index.js @@ -30,6 +30,7 @@ import { buildBackupsEndpoints } from "./backups" import { buildEnvironmentVariableEndpoints } from "./environmentVariables" import { buildEventEndpoints } from "./events" import { buildAuditLogsEndpoints } from "./auditLogs" +import { buildLogsEndpoints } from "./logs" /** * Random identifier to uniquely identify a session in a tab. This is @@ -277,5 +278,6 @@ export const createAPIClient = config => { ...buildEnvironmentVariableEndpoints(API), ...buildEventEndpoints(API), ...buildAuditLogsEndpoints(API), + ...buildLogsEndpoints(API), } } diff --git a/packages/frontend-core/src/api/logs.js b/packages/frontend-core/src/api/logs.js new file mode 100644 index 0000000000..d8c97b4773 --- /dev/null +++ b/packages/frontend-core/src/api/logs.js @@ -0,0 +1,14 @@ +export const buildLogsEndpoints = API => ({ + /** + * Gets a list of datasources. + */ + getServerLogs: async () => { + return await API.get({ + url: "/api/global/system/logs", + json: false, + parseResponse: async response => { + return response + }, + }) + }, +}) diff --git a/packages/frontend-core/src/utils/download.js b/packages/frontend-core/src/utils/download.js index 681bc8648e..5c00a0023e 100644 --- a/packages/frontend-core/src/utils/download.js +++ b/packages/frontend-core/src/utils/download.js @@ -11,3 +11,17 @@ export function downloadText(filename, text) { URL.revokeObjectURL(url) } + +export async function downloadStream(filename, streamResponse) { + const blob = await streamResponse.blob() + const resBlob = new Blob([blob]) + + const blobUrl = URL.createObjectURL(resBlob) + + const link = document.createElement("a") + link.href = blobUrl + link.download = filename + link.click() + + URL.revokeObjectURL(blobUrl) +} diff --git a/packages/frontend-core/src/utils/index.js b/packages/frontend-core/src/utils/index.js index dd04dd6c28..3f00c00e47 100644 --- a/packages/frontend-core/src/utils/index.js +++ b/packages/frontend-core/src/utils/index.js @@ -5,4 +5,4 @@ export * as RoleUtils from "./roles" export * as Utils from "./utils" export { memo, derivedMemo } from "./memo" export { createWebsocket } from "./websocket" -export { downloadText } from "./download" +export * from "./download" diff --git a/packages/worker/src/api/controllers/system/logs.ts b/packages/worker/src/api/controllers/system/logs.ts new file mode 100644 index 0000000000..f38a8f57a7 --- /dev/null +++ b/packages/worker/src/api/controllers/system/logs.ts @@ -0,0 +1,8 @@ +import { UserCtx } from "@budibase/types" +import { logging } from "@budibase/backend-core" + +export async function getLogs(ctx: UserCtx) { + const logReadStream = logging.system.getLogReadStream() + + ctx.body = logReadStream +} diff --git a/packages/worker/src/api/routes/index.ts b/packages/worker/src/api/routes/index.ts index 4131f14c74..31e93c45cc 100644 --- a/packages/worker/src/api/routes/index.ts +++ b/packages/worker/src/api/routes/index.ts @@ -16,6 +16,7 @@ import licenseRoutes from "./global/license" import migrationRoutes from "./system/migrations" import accountRoutes from "./system/accounts" import restoreRoutes from "./system/restore" +import systemLogRoutes from "./system/logs" export const routes: Router[] = [ configRoutes, @@ -37,4 +38,5 @@ export const routes: Router[] = [ restoreRoutes, eventRoutes, pro.scim, + systemLogRoutes, ] diff --git a/packages/worker/src/api/routes/system/logs.ts b/packages/worker/src/api/routes/system/logs.ts new file mode 100644 index 0000000000..98ebcab24e --- /dev/null +++ b/packages/worker/src/api/routes/system/logs.ts @@ -0,0 +1,9 @@ +import Router from "@koa/router" +import { middleware } from "@budibase/backend-core" +import * as controller from "../../controllers/system/logs" + +const router: Router = new Router() + +router.get("/api/global/system/logs", middleware.adminOnly, controller.getLogs) + +export default router