diff --git a/packages/core/src/common/logger.injectable.ts b/packages/core/src/common/logger.injectable.ts index 8e9dd2a6a7..82ff682c46 100644 --- a/packages/core/src/common/logger.injectable.ts +++ b/packages/core/src/common/logger.injectable.ts @@ -3,20 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { createLogger, format } from "winston"; import type { Logger } from "./logger"; -import { loggerTransportInjectionToken } from "./logger/transports"; +import winstonLoggerInjectable from "./winston-logger.injectable"; const loggerInjectable = getInjectable({ id: "logger", instantiate: (di): Logger => { - const baseLogger = createLogger({ - format: format.combine( - format.splat(), - format.simple(), - ), - transports: di.injectMany(loggerTransportInjectionToken), - }); + const baseLogger = di.inject(winstonLoggerInjectable); return { debug: (message, ...data) => baseLogger.debug(message, ...data), diff --git a/packages/core/src/common/winston-logger.injectable.ts b/packages/core/src/common/winston-logger.injectable.ts new file mode 100644 index 0000000000..ec3854d8b9 --- /dev/null +++ b/packages/core/src/common/winston-logger.injectable.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { createLogger, format } from "winston"; +import { loggerTransportInjectionToken } from "./logger/transports"; + +const winstonLoggerInjectable = getInjectable({ + id: "winston-logger", + instantiate: (di) => createLogger({ + format: format.combine( + format.splat(), + format.simple(), + ), + transports: di.injectMany(loggerTransportInjectionToken), + }), +}); + +export default winstonLoggerInjectable; diff --git a/packages/core/src/renderer/bootstrap.tsx b/packages/core/src/renderer/bootstrap.tsx index f509847c74..f74c74986f 100644 --- a/packages/core/src/renderer/bootstrap.tsx +++ b/packages/core/src/renderer/bootstrap.tsx @@ -54,7 +54,9 @@ export async function bootstrap(di: DiContainer) { } try { - await initializeApp(() => unmountComponentAtNode(rootElem)); + await initializeApp(() => { + unmountComponentAtNode(rootElem); + }); } catch (error) { console.error(`[BOOTSTRAP]: view initialization error: ${error}`, { origin: location.href, diff --git a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable.ts b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable.ts index c640264ee3..a9a923f860 100644 --- a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable.ts +++ b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable.ts @@ -12,6 +12,7 @@ import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event. import loadExtensionsInjectable from "../../load-extensions.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; import showErrorNotificationInjectable from "../../../components/notifications/show-error-notification.injectable"; +import closeRendererLogFileInjectable from "../../../logger/close-renderer-log-file.injectable"; const initClusterFrameInjectable = getInjectable({ id: "init-cluster-frame", @@ -29,6 +30,7 @@ const initClusterFrameInjectable = getInjectable({ emitAppEvent: di.inject(emitAppEventInjectable), logger: di.inject(loggerInjectable), showErrorNotification: di.inject(showErrorNotificationInjectable), + closeFileLogging: di.inject(closeRendererLogFileInjectable), }); }, }); diff --git a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts index 109ae0f0bc..31f4bfe96e 100644 --- a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts +++ b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts @@ -2,6 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { once } from "lodash"; import type { Cluster } from "../../../../common/cluster/cluster"; import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry"; import type { ShowNotification } from "../../../components/notifications"; @@ -18,6 +19,7 @@ interface Dependencies { emitAppEvent: EmitAppEvent; logger: Logger; showErrorNotification: ShowNotification; + closeFileLogging: () => void; } const logPrefix = "[CLUSTER-FRAME]:"; @@ -30,6 +32,7 @@ export const initClusterFrame = ({ emitAppEvent, logger, showErrorNotification, + closeFileLogging, }: Dependencies) => async (unmountRoot: () => void) => { // TODO: Make catalogEntityRegistry already initialized when passed as dependency @@ -73,11 +76,14 @@ export const initClusterFrame = ({ }); }); - window.onbeforeunload = () => { + const onCloseFrame = once(() => { logger.info( `${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`, ); - + closeFileLogging(); unmountRoot(); - }; + }); + + window.addEventListener("beforeunload", onCloseFrame); + window.addEventListener("pagehide", onCloseFrame); }; diff --git a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts index 8d2c3a43be..2f698c5c89 100644 --- a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts +++ b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts @@ -13,6 +13,7 @@ import loggerInjectable from "../../../common/logger.injectable"; import { delay } from "../../../common/utils"; import { broadcastMessage } from "../../../common/ipc"; import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling"; +import closeRendererLogFileInjectable from "../../logger/close-renderer-log-file.injectable"; const initRootFrameInjectable = getInjectable({ id: "init-root-frame", @@ -24,6 +25,7 @@ const initRootFrameInjectable = getInjectable({ const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable); const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); const logger = di.inject(loggerInjectable); + const closeRendererLogFile = di.inject(closeRendererLogFileInjectable); return async (unmountRoot: () => void) => { catalogEntityRegistry.init(); @@ -59,7 +61,7 @@ const initRootFrameInjectable = getInjectable({ window.addEventListener("beforeunload", () => { logger.info("[ROOT-FRAME]: Unload app"); - + closeRendererLogFile(); unmountRoot(); }); }; diff --git a/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts b/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts new file mode 100644 index 0000000000..8480589c39 --- /dev/null +++ b/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import winstonLoggerInjectable from "../../common/winston-logger.injectable"; +import rendererFileLoggerTransportInjectable from "./file-transport.injectable"; + +const closeRendererLogFileInjectable = getInjectable({ + id: "close-renderer-log-file", + instantiate: (di) => { + const winstonLogger = di.inject(winstonLoggerInjectable); + const fileLoggingTransport = di.inject(rendererFileLoggerTransportInjectable); + + return () => { + fileLoggingTransport.close?.(); + winstonLogger.remove(fileLoggingTransport); + }; + }, +}); + +export default closeRendererLogFileInjectable; diff --git a/packages/core/src/renderer/logger/file-transport.injectable.ts b/packages/core/src/renderer/logger/file-transport.injectable.ts new file mode 100644 index 0000000000..0cd8607e83 --- /dev/null +++ b/packages/core/src/renderer/logger/file-transport.injectable.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { transports } from "winston"; +import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable"; +import { loggerTransportInjectionToken } from "../../common/logger/transports"; +import windowLocationInjectable from "../../common/k8s-api/window-location.injectable"; +import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; +import { getClusterIdFromHost } from "../utils"; + +const rendererFileLoggerTransportInjectable = getInjectable({ + id: "renderer-file-logger-transport", + instantiate: (di) => { + let frameId: string; + + const currentlyInClusterFrame = di.inject( + currentlyInClusterFrameInjectable, + ); + + if (currentlyInClusterFrame) { + const { host } = di.inject(windowLocationInjectable); + const clusterId = getClusterIdFromHost(host); + + frameId = clusterId ? `cluster-${clusterId}` : "cluster"; + } else { + frameId = "main"; + } + + return new transports.File({ + handleExceptions: false, + level: "info", + filename: `lens-renderer-${frameId}.log`, + dirname: di.inject(directoryForLogsInjectable), + maxsize: 1024 * 1024, + maxFiles: 2, + tailable: true, + }); + }, + injectionToken: loggerTransportInjectionToken, +}); + +export default rendererFileLoggerTransportInjectable;