mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add winston formatting support for error causes (#6576)
* Add winston formatting support for error causes Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix failing to run built version - Finally make logger fully injectable - Simplify startMainApplication to only have runMany(Sync) invocations to fix time of use bugs related to logger Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove legacy type enforced ipc to fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
a4d0451dec
commit
8dd1d1a8fa
@ -290,7 +290,6 @@
|
||||
"uuid": "^8.3.2",
|
||||
"win-ca": "^3.5.0",
|
||||
"winston": "^3.8.2",
|
||||
"winston-console-format": "^1.0.8",
|
||||
"winston-transport-browserconsole": "^1.0.5",
|
||||
"ws": "^8.11.0",
|
||||
"xterm-link-provider": "^1.3.1"
|
||||
@ -366,6 +365,7 @@
|
||||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"adr": "^1.4.3",
|
||||
"ansi_up": "^5.1.0",
|
||||
"chalk": "^4.1.2",
|
||||
"chart.js": "^2.9.4",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"cli-progress": "^3.11.2",
|
||||
|
||||
13
src/common/app-paths/directory-for-logs.injectable.ts
Normal file
13
src/common/app-paths/directory-for-logs.injectable.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 appPathsInjectable from "./app-paths.injectable";
|
||||
|
||||
const directoryForLogsInjectable = getInjectable({
|
||||
id: "directory-for-logs",
|
||||
instantiate: (di) => di.inject(appPathsInjectable).logs,
|
||||
});
|
||||
|
||||
export default directoryForLogsInjectable;
|
||||
@ -1,131 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { onCorrect, onceCorrect } from "../type-enforced-ipc";
|
||||
|
||||
describe("type enforced ipc tests", () => {
|
||||
describe("onCorrect tests", () => {
|
||||
it("should call the handler if the args are valid", () => {
|
||||
let called = false;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called = true;
|
||||
const verifier = (args: unknown[]): args is [] => true;
|
||||
const channel = "foobar";
|
||||
|
||||
onCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
it("should not call the handler if the args are not valid", () => {
|
||||
let called = false;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called = true;
|
||||
const verifier = (args: unknown[]): args is [] => false;
|
||||
const channel = "foobar";
|
||||
|
||||
onCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
expect(called).toBe(false);
|
||||
});
|
||||
|
||||
it("should call the handler twice if the args are valid on two emits", () => {
|
||||
let called = 0;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called += 1;
|
||||
const verifier = (args: unknown[]): args is [] => true;
|
||||
const channel = "foobar";
|
||||
|
||||
onCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
source.emit(channel);
|
||||
expect(called).toBe(2);
|
||||
});
|
||||
|
||||
it("should call the handler twice if the args are [valid, invalid, valid]", () => {
|
||||
let called = 0;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called += 1;
|
||||
const results = [true, false, true];
|
||||
const verifier = (args: unknown[]): args is [] => results.pop() ?? false;
|
||||
const channel = "foobar";
|
||||
|
||||
onCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
source.emit(channel);
|
||||
source.emit(channel);
|
||||
expect(called).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onceCorrect tests", () => {
|
||||
it("should call the handler if the args are valid", () => {
|
||||
let called = false;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called = true;
|
||||
const verifier = (args: unknown[]): args is [] => true;
|
||||
const channel = "foobar";
|
||||
|
||||
onceCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
it("should not call the handler if the args are not valid", () => {
|
||||
let called = false;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called = true;
|
||||
const verifier = (args: unknown[]): args is [] => false;
|
||||
const channel = "foobar";
|
||||
|
||||
onceCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
expect(called).toBe(false);
|
||||
});
|
||||
|
||||
it("should call the handler only once even if args are valid multiple times", () => {
|
||||
let called = 0;
|
||||
const source = new EventEmitter();
|
||||
const listener = () => called += 1;
|
||||
const verifier = (args: unknown[]): args is [] => true;
|
||||
const channel = "foobar";
|
||||
|
||||
onceCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel);
|
||||
source.emit(channel);
|
||||
expect(called).toBe(1);
|
||||
});
|
||||
|
||||
it("should call the handler on only the first valid set of args", () => {
|
||||
let called = "";
|
||||
let verifierCalled = 0;
|
||||
const source = new EventEmitter();
|
||||
const listener = (info: any, arg: string) => called = arg;
|
||||
const verifier = (args: unknown[]): args is [string] => (++verifierCalled) % 3 === 0;
|
||||
const channel = "foobar";
|
||||
|
||||
onceCorrect({ source, listener, verifier, channel });
|
||||
|
||||
source.emit(channel, {}, "a");
|
||||
source.emit(channel, {}, "b");
|
||||
source.emit(channel, {}, "c");
|
||||
source.emit(channel, {}, "d");
|
||||
source.emit(channel, {}, "e");
|
||||
source.emit(channel, {}, "f");
|
||||
source.emit(channel, {}, "g");
|
||||
source.emit(channel, {}, "h");
|
||||
source.emit(channel, {}, "i");
|
||||
expect(called).toBe("c");
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -5,4 +5,3 @@
|
||||
|
||||
export * from "./ipc";
|
||||
export * from "./invalid-kubeconfig";
|
||||
export * from "./type-enforced-ipc";
|
||||
|
||||
@ -1,107 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { EventEmitter } from "events";
|
||||
import { ipcMain } from "electron";
|
||||
import logger from "../../main/logger";
|
||||
import type { Disposer } from "../utils";
|
||||
import { ipcMainHandle } from "./ipc";
|
||||
|
||||
export type ListenerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
|
||||
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
|
||||
export type Rest<T> = T extends [any, ...infer R] ? R : [];
|
||||
|
||||
/**
|
||||
* Adds a listener to `source` that waits for the first IPC message with the correct
|
||||
* argument data is sent.
|
||||
* @param channel The channel to be listened on
|
||||
* @param listener The function for the channel to be called if the args of the correct type
|
||||
* @param verifier The function to be called to verify that the args are the correct type
|
||||
*/
|
||||
export function onceCorrect<
|
||||
IPC extends EventEmitter,
|
||||
Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any,
|
||||
>({
|
||||
source,
|
||||
channel,
|
||||
listener,
|
||||
verifier,
|
||||
}: {
|
||||
source: IPC;
|
||||
channel: string;
|
||||
listener: Listener;
|
||||
verifier: ListVerifier<Rest<Parameters<Listener>>>;
|
||||
}): void {
|
||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]): void {
|
||||
if (verifier(args)) {
|
||||
source.removeListener(channel, wrappedListener); // remove immediately
|
||||
|
||||
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
|
||||
.catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error }));
|
||||
} else {
|
||||
logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
|
||||
}
|
||||
}
|
||||
|
||||
source.on(channel, wrappedListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to `source` that checks to verify the arguments before calling the handler.
|
||||
* @param channel The channel to be listened on
|
||||
* @param listener The function for the channel to be called if the args of the correct type
|
||||
* @param verifier The function to be called to verify that the args are the correct type
|
||||
*/
|
||||
export function onCorrect<
|
||||
IPC extends EventEmitter,
|
||||
Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any,
|
||||
>({
|
||||
source,
|
||||
channel,
|
||||
listener,
|
||||
verifier,
|
||||
}: {
|
||||
source: IPC;
|
||||
channel: string;
|
||||
listener: Listener;
|
||||
verifier: ListVerifier<Rest<Parameters<Listener>>>;
|
||||
}): Disposer {
|
||||
function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]) {
|
||||
if (verifier(args)) {
|
||||
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
|
||||
.catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error }));
|
||||
} else {
|
||||
logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
|
||||
}
|
||||
}
|
||||
|
||||
source.on(channel, wrappedListener);
|
||||
|
||||
return () => source.off(channel, wrappedListener);
|
||||
}
|
||||
|
||||
export function handleCorrect<
|
||||
Handler extends (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any,
|
||||
>({
|
||||
channel,
|
||||
handler,
|
||||
verifier,
|
||||
}: {
|
||||
channel: string;
|
||||
handler: Handler;
|
||||
verifier: ListVerifier<Rest<Parameters<Handler>>>;
|
||||
}): Disposer {
|
||||
function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType<Handler> {
|
||||
if (verifier(args)) {
|
||||
return handler(event, ...args);
|
||||
}
|
||||
|
||||
throw new TypeError(`Invalid args for invoke on channel: ${channel}`);
|
||||
}
|
||||
|
||||
ipcMainHandle(channel, wrappedHandler);
|
||||
|
||||
return () => ipcMain.removeHandler(channel);
|
||||
}
|
||||
@ -3,12 +3,19 @@
|
||||
* 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 logger from "./logger";
|
||||
import { loggerTransportInjectionToken } from "./logger/transports";
|
||||
|
||||
const loggerInjectable = getInjectable({
|
||||
id: "logger",
|
||||
instantiate: (): Logger => logger,
|
||||
instantiate: (di): Logger => createLogger({
|
||||
format: format.combine(
|
||||
format.splat(),
|
||||
format.simple(),
|
||||
),
|
||||
transports: di.injectMany(loggerTransportInjectionToken),
|
||||
}),
|
||||
});
|
||||
|
||||
export default loggerInjectable;
|
||||
|
||||
@ -3,12 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { app, ipcMain } from "electron";
|
||||
import winston, { format } from "winston";
|
||||
import type Transport from "winston-transport";
|
||||
import { consoleFormat } from "winston-console-format";
|
||||
import { isDebugging, isTestEnv } from "./vars";
|
||||
import BrowserConsole from "winston-transport-browserconsole";
|
||||
import { asLegacyGlobalForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||
import loggerInjectable from "./logger.injectable";
|
||||
|
||||
export interface Logger {
|
||||
info: (message: string, ...args: any) => void;
|
||||
@ -18,64 +14,7 @@ export interface Logger {
|
||||
silly: (message: string, ...args: any) => void;
|
||||
}
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL
|
||||
? process.env.LOG_LEVEL
|
||||
: isDebugging
|
||||
? "debug"
|
||||
: isTestEnv
|
||||
? "error"
|
||||
: "info";
|
||||
|
||||
const transports: Transport[] = [];
|
||||
|
||||
if (ipcMain) {
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
handleExceptions: false,
|
||||
level: logLevel,
|
||||
format: format.combine(
|
||||
format.colorize({ level: true, message: false }),
|
||||
format.padLevels(),
|
||||
format.ms(),
|
||||
consoleFormat({
|
||||
showMeta: true,
|
||||
inspectOptions: {
|
||||
depth: 4,
|
||||
colors: true,
|
||||
maxArrayLength: 10,
|
||||
breakLength: 120,
|
||||
compact: Infinity,
|
||||
},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
if (!isTestEnv) {
|
||||
transports.push(
|
||||
new winston.transports.File({
|
||||
handleExceptions: false,
|
||||
level: "debug",
|
||||
filename: "lens.log",
|
||||
/**
|
||||
* SAFTEY: the `ipcMain` check above should mean that this is only
|
||||
* called in the main process
|
||||
/**
|
||||
* @deprecated use `di.inject(loggerInjectable)` instead
|
||||
*/
|
||||
dirname: app.getPath("logs"),
|
||||
maxsize: 1024 * 1024,
|
||||
maxFiles: 16,
|
||||
tailable: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
transports.push(new BrowserConsole());
|
||||
}
|
||||
|
||||
export default winston.createLogger({
|
||||
format: format.combine(
|
||||
format.splat(),
|
||||
format.simple(),
|
||||
),
|
||||
transports,
|
||||
}) as Logger;
|
||||
export default asLegacyGlobalForExtensionApi(loggerInjectable);
|
||||
|
||||
11
src/common/logger/transports.ts
Normal file
11
src/common/logger/transports.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type TransportStream from "winston-transport";
|
||||
|
||||
export const loggerTransportInjectionToken = getInjectionToken<TransportStream>({
|
||||
id: "logger-transport",
|
||||
});
|
||||
@ -12,8 +12,8 @@ import { pathNames } from "../../common/app-paths/app-path-names";
|
||||
import { fromPairs, map } from "lodash/fp";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../start-main-application/runnable-tokens/before-electron-is-ready-injection-token";
|
||||
import appNameInjectable from "../../common/vars/app-name.injectable";
|
||||
import { appPathsRunnablePhaseInjectionToken } from "../start-main-application/runnable-tokens/phases";
|
||||
|
||||
const setupAppPathsInjectable = getInjectable({
|
||||
id: "setup-app-paths",
|
||||
@ -51,7 +51,7 @@ const setupAppPathsInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
injectionToken: appPathsRunnablePhaseInjectionToken,
|
||||
});
|
||||
|
||||
export default setupAppPathsInjectable;
|
||||
|
||||
@ -111,14 +111,12 @@ export class ContextHandler implements ClusterContextHandler {
|
||||
const potentialServices = await Promise.allSettled(
|
||||
providers.map(provider => provider.getPrometheusService(apiClient)),
|
||||
);
|
||||
const errors: any[] = [];
|
||||
const errors = [];
|
||||
|
||||
for (const res of potentialServices) {
|
||||
switch (res.status) {
|
||||
case "rejected":
|
||||
if (res.reason) {
|
||||
errors.push(String(res.reason));
|
||||
}
|
||||
errors.push(res.reason);
|
||||
break;
|
||||
|
||||
case "fulfilled":
|
||||
@ -128,7 +126,7 @@ export class ContextHandler implements ClusterContextHandler {
|
||||
}
|
||||
}
|
||||
|
||||
throw Object.assign(new Error("No Prometheus service found"), { cause: errors });
|
||||
throw new Error("No Prometheus service found", { cause: errors });
|
||||
}
|
||||
|
||||
async resolveAuthProxyUrl(): Promise<string> {
|
||||
|
||||
@ -11,15 +11,10 @@ import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||
import * as LensExtensionsMainApi from "../extensions/main-api";
|
||||
import { getDi } from "./getDi";
|
||||
import startMainApplicationInjectable from "./start-main-application/start-main-application.injectable";
|
||||
import shouldStartHiddenInjectable from "./electron-app/features/should-start-hidden.injectable";
|
||||
|
||||
const di = getDi();
|
||||
|
||||
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
|
||||
|
||||
const startApplication = di.inject(startMainApplicationInjectable);
|
||||
|
||||
void startApplication(!shouldStartHidden);
|
||||
void di.inject(startMainApplicationInjectable);
|
||||
|
||||
/**
|
||||
* Exports for virtual package "@k8slens/extensions" for main-process.
|
||||
|
||||
184
src/main/logger/console-format.ts
Normal file
184
src/main/logger/console-format.ts
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { LEVEL, MESSAGE, SPLAT } from "triple-beam";
|
||||
import chalk from "chalk";
|
||||
import type { InspectOptions } from "util";
|
||||
import { inspect } from "util";
|
||||
|
||||
// The following license was copied from https://github.com/duccio/winston-console-format/blob/master/LICENSE
|
||||
// This was modified to support formatting causes
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 Eugeny Dementev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export interface ConsoleFormatOptions {
|
||||
showMeta?: boolean;
|
||||
metaStrip?: string[];
|
||||
inspectOptions?: InspectOptions;
|
||||
}
|
||||
|
||||
interface TransformableInfo {
|
||||
level: string;
|
||||
message: string;
|
||||
[key: string | symbol]: any;
|
||||
}
|
||||
|
||||
export class ConsoleFormat {
|
||||
private static readonly reSpaces = /^\s+/;
|
||||
private static readonly reSpacesOrEmpty = /^(\s*)/;
|
||||
// eslint-disable-next-line no-control-regex
|
||||
private static readonly reColor = /\x1B\[\d+m/;
|
||||
private static readonly defaultStrip = [LEVEL, MESSAGE, SPLAT, "level", "message", "ms", "stack"];
|
||||
private static readonly chars = {
|
||||
singleLine: "▪",
|
||||
startLine: "┏",
|
||||
line: "┃",
|
||||
endLine: "┗",
|
||||
};
|
||||
|
||||
private readonly showMeta: boolean;
|
||||
private readonly metaStrip: string[];
|
||||
private readonly inspectOptions: InspectOptions;
|
||||
|
||||
public constructor(opts?: ConsoleFormatOptions) {
|
||||
this.showMeta = opts?.showMeta ?? true;
|
||||
this.metaStrip = opts?.metaStrip ?? [];
|
||||
this.inspectOptions = opts?.inspectOptions ?? {};
|
||||
}
|
||||
|
||||
private getLines(value: unknown): string[] {
|
||||
return inspect(value, this.inspectOptions).split("\n");
|
||||
}
|
||||
|
||||
private message(info: TransformableInfo, chr: string, color: string): string {
|
||||
const message = info.message.replace(
|
||||
ConsoleFormat.reSpacesOrEmpty,
|
||||
`$1${color}${chalk.dim(chr)}${chalk.reset(" ")}`,
|
||||
);
|
||||
|
||||
return `${info.level}:${message}`;
|
||||
}
|
||||
|
||||
private pad(message?: string): string {
|
||||
return message?.match(ConsoleFormat.reSpaces)?.[0] ?? "";
|
||||
}
|
||||
|
||||
private ms(info: TransformableInfo): string {
|
||||
if (info.ms) {
|
||||
return chalk.italic(chalk.dim(` ${info.ms}`));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private stack(info: TransformableInfo): string[] {
|
||||
const messages: string[] = [];
|
||||
|
||||
if (info.stack) {
|
||||
const error = new Error();
|
||||
|
||||
error.stack = info.stack;
|
||||
messages.push(...this.getLines(error));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
private _cause(source: unknown): string[] {
|
||||
const messages: string[] = [];
|
||||
|
||||
if (source instanceof Error && source.cause) {
|
||||
messages.push(`Cause: ${source.cause}`);
|
||||
messages.push(...this.getLines(source.cause).map(l => ` ${l}`));
|
||||
messages.push(...this._cause(source.cause));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
private cause(info: TransformableInfo): string[] {
|
||||
const splats = info[SPLAT];
|
||||
|
||||
if (Array.isArray(splats)) {
|
||||
return splats.flatMap(splat => this._cause(splat));
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private meta(info: TransformableInfo): string[] {
|
||||
const messages: string[] = [];
|
||||
const stripped = { ...info };
|
||||
|
||||
ConsoleFormat.defaultStrip.forEach((e) => delete stripped[e]);
|
||||
this.metaStrip?.forEach((e) => delete stripped[e]);
|
||||
|
||||
if (Object.keys(stripped).length > 0) {
|
||||
messages.push(...this.getLines(stripped));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
private getColor(info: TransformableInfo): string {
|
||||
return info.level.match(ConsoleFormat.reColor)?.[0] ?? "";
|
||||
}
|
||||
|
||||
private write(info: TransformableInfo, messages: string[], color: string): void {
|
||||
const pad = this.pad(info.message);
|
||||
|
||||
messages.forEach((line, index, arr) => {
|
||||
const lineNumber = chalk.dim(`[${(index + 1).toString().padStart(arr.length.toString().length, " ")}]`);
|
||||
let chr = ConsoleFormat.chars.line;
|
||||
|
||||
if (index === arr.length - 1) {
|
||||
chr = ConsoleFormat.chars.endLine;
|
||||
}
|
||||
info[MESSAGE] += `\n${chalk.dim(info.level)}:${pad}${color}${chalk.dim(chr)}${chalk.reset(" ")}`;
|
||||
info[MESSAGE] += `${lineNumber} ${line}`;
|
||||
});
|
||||
}
|
||||
|
||||
public transform(info: TransformableInfo): TransformableInfo {
|
||||
const messages: string[] = [];
|
||||
|
||||
if (this.showMeta) {
|
||||
messages.push(...this.stack(info));
|
||||
messages.push(...this.meta(info));
|
||||
messages.push(...this.cause(info));
|
||||
}
|
||||
|
||||
const color = this.getColor(info);
|
||||
|
||||
info[MESSAGE] = this.message(info, ConsoleFormat.chars[messages.length > 0 ? "startLine" : "singleLine"], color);
|
||||
info[MESSAGE] += this.ms(info);
|
||||
|
||||
this.write(info, messages, color);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
35
src/main/logger/console-transport.injectable.ts
Normal file
35
src/main/logger/console-transport.injectable.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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 { format, transports } from "winston";
|
||||
import { ConsoleFormat } from "./console-format";
|
||||
import { loggerTransportInjectionToken } from "../../common/logger/transports";
|
||||
import logLevelInjectable from "./level.injectable";
|
||||
|
||||
const consoleLoggerTransportInjectable = getInjectable({
|
||||
id: "console-logger-transport",
|
||||
instantiate: (di) => new transports.Console({
|
||||
handleExceptions: false,
|
||||
level: di.inject(logLevelInjectable),
|
||||
format: format.combine(
|
||||
format.colorize({ level: true, message: false }),
|
||||
format.padLevels(),
|
||||
format.ms(),
|
||||
new ConsoleFormat({
|
||||
showMeta: true,
|
||||
inspectOptions: {
|
||||
depth: 4,
|
||||
colors: true,
|
||||
maxArrayLength: 10,
|
||||
breakLength: 120,
|
||||
compact: Infinity,
|
||||
},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
injectionToken: loggerTransportInjectionToken,
|
||||
});
|
||||
|
||||
export default consoleLoggerTransportInjectable;
|
||||
28
src/main/logger/file-transport.injectable.ts
Normal file
28
src/main/logger/file-transport.injectable.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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";
|
||||
|
||||
const fileLoggerTranportInjectable = getInjectable({
|
||||
id: "file-logger-tranport",
|
||||
instantiate: (di) => new transports.File({
|
||||
handleExceptions: false,
|
||||
level: "debug",
|
||||
filename: "lens.log",
|
||||
/**
|
||||
* SAFTEY: the `ipcMain` check above should mean that this is only
|
||||
* called in the main process
|
||||
*/
|
||||
dirname: di.inject(directoryForLogsInjectable),
|
||||
maxsize: 1024 * 1024,
|
||||
maxFiles: 16,
|
||||
tailable: true,
|
||||
}),
|
||||
injectionToken: loggerTransportInjectionToken,
|
||||
});
|
||||
|
||||
export default fileLoggerTranportInjectable;
|
||||
9
src/main/logger/level.global-override-for-injectable.ts
Normal file
9
src/main/logger/level.global-override-for-injectable.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import logLevelInjectable from "./level.injectable";
|
||||
|
||||
export default getGlobalOverride(logLevelInjectable, () => "error");
|
||||
30
src/main/logger/level.injectable.ts
Normal file
30
src/main/logger/level.injectable.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 isDebuggingInjectable from "../../common/vars/is-debugging.injectable";
|
||||
|
||||
export type LogLevel = "silly" | "debug" | "info" | "warn" | "error";
|
||||
|
||||
const logLevelInjectable = getInjectable({
|
||||
id: "log-level",
|
||||
instantiate: (di): LogLevel => {
|
||||
const isDebugging = di.inject(isDebuggingInjectable);
|
||||
const baseLevel = process.env.LOG_LEVEL?.toLowerCase();
|
||||
|
||||
switch (baseLevel) {
|
||||
case "silly":
|
||||
case "debug":
|
||||
case "info":
|
||||
case "warn":
|
||||
case "error":
|
||||
return baseLevel;
|
||||
default:
|
||||
return isDebugging ? "debug" : "info";
|
||||
}
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default logLevelInjectable;
|
||||
@ -28,15 +28,18 @@ const loadMetricsFor = (getMetrics: GetMetrics) => async (promQueries: string[],
|
||||
try {
|
||||
return await getMetrics(cluster, prometheusPath, { query, ...queryParams });
|
||||
} catch (error) {
|
||||
if (isRequestError(error)) {
|
||||
if (lastAttempt || (error.statusCode && error.statusCode >= 400 && error.statusCode < 500)) {
|
||||
if (
|
||||
!isRequestError(error)
|
||||
|| lastAttempt
|
||||
|| (
|
||||
!lastAttempt && (
|
||||
typeof error.statusCode === "number" &&
|
||||
400 <= error.statusCode && error.statusCode < 500
|
||||
)
|
||||
)
|
||||
) {
|
||||
throw new Error("Metrics not available", { cause: error });
|
||||
}
|
||||
} else if (error instanceof Error) {
|
||||
throw new Error("Metrics not available", { cause: error });
|
||||
} else {
|
||||
throw new Error("Metrics not available");
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request
|
||||
}
|
||||
|
||||
28
src/main/start-main-application/runnable-tokens/phases.ts
Normal file
28
src/main/start-main-application/runnable-tokens/phases.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../../../common/runnable/run-many-for";
|
||||
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
|
||||
|
||||
/**
|
||||
* These tokens are here so that the importing of their respective dependencies
|
||||
* can be delayed until all of them are ready
|
||||
*/
|
||||
|
||||
/**
|
||||
* This runnable token should only have the app paths init so that it can be run by itself
|
||||
*/
|
||||
export const appPathsRunnablePhaseInjectionToken = getInjectionToken<RunnableSync>({
|
||||
id: "app-paths-runnable-phase",
|
||||
});
|
||||
|
||||
export const showLoadingRunnablePhaseInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "show-loading-runnable-phase",
|
||||
});
|
||||
|
||||
export const showInitialWindowRunnablePhaseInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "show-initial-window-runnable-phase",
|
||||
});
|
||||
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 shouldStartHiddenInjectable from "../../electron-app/features/should-start-hidden.injectable";
|
||||
import openDeepLinkInjectable from "../../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable";
|
||||
import commandLineArgumentsInjectable from "../../utils/command-line-arguments.injectable";
|
||||
import createFirstApplicationWindowInjectable from "../lens-window/application-window/create-first-application-window.injectable";
|
||||
import splashWindowInjectable from "../lens-window/splash-window/splash-window.injectable";
|
||||
import { showInitialWindowRunnablePhaseInjectionToken } from "../runnable-tokens/phases";
|
||||
|
||||
const getDeepLinkUrl = (commandLineArguments: string[]) => (
|
||||
commandLineArguments
|
||||
.map(arg => arg.toLowerCase())
|
||||
.find(arg => arg.startsWith("lens://"))
|
||||
);
|
||||
|
||||
const showInitialWindowInjectable = getInjectable({
|
||||
id: "show-initial-window",
|
||||
instantiate: (di) => {
|
||||
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
|
||||
const shouldStartWindow = !shouldStartHidden;
|
||||
const createFirstApplicationWindow = di.inject(createFirstApplicationWindowInjectable);
|
||||
const splashWindow = di.inject(splashWindowInjectable);
|
||||
const openDeepLink = di.inject(openDeepLinkInjectable);
|
||||
const commandLineArguments = di.inject(commandLineArgumentsInjectable);
|
||||
|
||||
return {
|
||||
id: "show-initial-window",
|
||||
run: async () => {
|
||||
if (shouldStartWindow) {
|
||||
const deepLinkUrl = getDeepLinkUrl(commandLineArguments);
|
||||
|
||||
if (deepLinkUrl) {
|
||||
await openDeepLink(deepLinkUrl);
|
||||
} else {
|
||||
const applicationWindow = createFirstApplicationWindow();
|
||||
|
||||
await applicationWindow.start();
|
||||
}
|
||||
|
||||
splashWindow.close();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: showInitialWindowRunnablePhaseInjectionToken,
|
||||
});
|
||||
|
||||
export default showInitialWindowInjectable;
|
||||
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 shouldStartHiddenInjectable from "../../electron-app/features/should-start-hidden.injectable";
|
||||
import splashWindowInjectable from "../lens-window/splash-window/splash-window.injectable";
|
||||
import { showLoadingRunnablePhaseInjectionToken } from "../runnable-tokens/phases";
|
||||
|
||||
const showLoadingInjectable = getInjectable({
|
||||
id: "show-loading",
|
||||
instantiate: (di) => {
|
||||
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
|
||||
const shouldShowLoadingWindow = !shouldStartHidden;
|
||||
const splashWindow = di.inject(splashWindowInjectable);
|
||||
|
||||
return {
|
||||
id: "show-loading",
|
||||
run: async () => {
|
||||
if (shouldShowLoadingWindow) {
|
||||
await splashWindow.start();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: showLoadingRunnablePhaseInjectionToken,
|
||||
});
|
||||
|
||||
export default showLoadingInjectable;
|
||||
@ -10,13 +10,8 @@ import { beforeElectronIsReadyInjectionToken } from "./runnable-tokens/before-el
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "./runnable-tokens/before-application-is-loading-injection-token";
|
||||
import { onLoadOfApplicationInjectionToken } from "./runnable-tokens/on-load-of-application-injection-token";
|
||||
import { afterApplicationIsLoadedInjectionToken } from "./runnable-tokens/after-application-is-loaded-injection-token";
|
||||
import splashWindowInjectable from "./lens-window/splash-window/splash-window.injectable";
|
||||
import openDeepLinkInjectable from "../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { find, map, startsWith, toLower } from "lodash/fp";
|
||||
import commandLineArgumentsInjectable from "../utils/command-line-arguments.injectable";
|
||||
import waitForElectronToBeReadyInjectable from "../electron-app/features/wait-for-electron-to-be-ready.injectable";
|
||||
import createFirstApplicationWindowInjectable from "./lens-window/application-window/create-first-application-window.injectable";
|
||||
import { appPathsRunnablePhaseInjectionToken, showInitialWindowRunnablePhaseInjectionToken, showLoadingRunnablePhaseInjectionToken } from "./runnable-tokens/phases";
|
||||
|
||||
const startMainApplicationInjectable = getInjectable({
|
||||
id: "start-main-application",
|
||||
@ -25,53 +20,29 @@ const startMainApplicationInjectable = getInjectable({
|
||||
const runMany = runManyFor(di);
|
||||
const runManySync = runManySyncFor(di);
|
||||
const waitForElectronToBeReady = di.inject(waitForElectronToBeReadyInjectable);
|
||||
const createFirstApplicationWindow = di.inject(createFirstApplicationWindowInjectable);
|
||||
const splashWindow = di.inject(splashWindowInjectable);
|
||||
const openDeepLink = di.inject(openDeepLinkInjectable);
|
||||
const commandLineArguments = di.inject(commandLineArgumentsInjectable);
|
||||
|
||||
const appPathsRunnablePhase = runManySync(appPathsRunnablePhaseInjectionToken);
|
||||
const beforeElectronIsReady = runManySync(beforeElectronIsReadyInjectionToken);
|
||||
const beforeApplicationIsLoading = runMany(beforeApplicationIsLoadingInjectionToken);
|
||||
const showLoadingRunnablePhase = runMany(showLoadingRunnablePhaseInjectionToken);
|
||||
const onLoadOfApplication = runMany(onLoadOfApplicationInjectionToken);
|
||||
const showInitialWindowRunnablePhase = runMany(showInitialWindowRunnablePhaseInjectionToken);
|
||||
const afterApplicationIsLoaded = runMany(afterApplicationIsLoadedInjectionToken);
|
||||
|
||||
return (shouldStartWindow: boolean) => {
|
||||
// Stuff happening before application is ready needs to be synchronous because of
|
||||
// https://github.com/electron/electron/issues/21370
|
||||
appPathsRunnablePhase();
|
||||
beforeElectronIsReady();
|
||||
|
||||
return (async () => {
|
||||
await waitForElectronToBeReady();
|
||||
|
||||
await beforeApplicationIsLoading();
|
||||
|
||||
if (shouldStartWindow) {
|
||||
await splashWindow.start();
|
||||
}
|
||||
|
||||
await showLoadingRunnablePhase();
|
||||
await onLoadOfApplication();
|
||||
|
||||
if (shouldStartWindow) {
|
||||
const deepLinkUrl = getDeepLinkUrl(commandLineArguments);
|
||||
|
||||
if (deepLinkUrl) {
|
||||
await openDeepLink(deepLinkUrl);
|
||||
} else {
|
||||
const applicationWindow = createFirstApplicationWindow();
|
||||
|
||||
await applicationWindow.start();
|
||||
}
|
||||
|
||||
splashWindow.close();
|
||||
}
|
||||
|
||||
await showInitialWindowRunnablePhase();
|
||||
await afterApplicationIsLoaded();
|
||||
})();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const getDeepLinkUrl = (commandLineArguments: string[]) =>
|
||||
pipeline(commandLineArguments, map(toLower), find(startsWith("lens://")));
|
||||
|
||||
export default startMainApplicationInjectable;
|
||||
|
||||
@ -68,6 +68,7 @@ import applicationMenuItemCompositeInjectable from "../../../features/applicatio
|
||||
import { getCompositePaths } from "../../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import { discoverFor } from "./discovery-of-html-elements";
|
||||
import { findComposite } from "../../../common/utils/composite/find-composite/find-composite";
|
||||
import shouldStartHiddenInjectable from "../../../main/electron-app/features/should-start-hidden.injectable";
|
||||
|
||||
type Callback = (di: DiContainer) => void | Promise<void>;
|
||||
|
||||
@ -313,11 +314,9 @@ export const getApplicationBuilder = () => {
|
||||
.map(toWindowWithHelpersFor(windowHelpers)),
|
||||
|
||||
get: (id) => {
|
||||
const applicationWindows = builder.applicationWindow.getAll();
|
||||
|
||||
const applicationWindow = applicationWindows.find(
|
||||
(window) => window.id === id,
|
||||
);
|
||||
const applicationWindow = builder.applicationWindow
|
||||
.getAll()
|
||||
.find((window) => window.id === id);
|
||||
|
||||
if (!applicationWindow) {
|
||||
throw new Error(`Tried to get application window with ID "${id}" but it was not found.`);
|
||||
@ -327,9 +326,7 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
create: (id) => {
|
||||
const createApplicationWindow = mainDi.inject(
|
||||
createApplicationWindowInjectable,
|
||||
);
|
||||
const createApplicationWindow = mainDi.inject(createApplicationWindowInjectable);
|
||||
|
||||
createApplicationWindow(id);
|
||||
|
||||
@ -656,11 +653,8 @@ export const getApplicationBuilder = () => {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
const startMainApplication = mainDi.inject(
|
||||
startMainApplicationInjectable,
|
||||
);
|
||||
|
||||
await startMainApplication(false);
|
||||
mainDi.override(shouldStartHiddenInjectable, () => true);
|
||||
await mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
applicationHasStarted = true;
|
||||
},
|
||||
@ -672,21 +666,15 @@ export const getApplicationBuilder = () => {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
const startMainApplication = mainDi.inject(
|
||||
startMainApplicationInjectable,
|
||||
);
|
||||
|
||||
await startMainApplication(true);
|
||||
mainDi.override(shouldStartHiddenInjectable, () => false);
|
||||
await mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
applicationHasStarted = true;
|
||||
|
||||
const applicationWindow = builder.applicationWindow.get(
|
||||
"first-application-window",
|
||||
);
|
||||
|
||||
assert(applicationWindow);
|
||||
|
||||
return applicationWindow.rendered;
|
||||
return builder
|
||||
.applicationWindow
|
||||
.get("first-application-window")
|
||||
.rendered;
|
||||
},
|
||||
|
||||
select: {
|
||||
|
||||
@ -5,10 +5,9 @@
|
||||
|
||||
import type { IpcRendererEvent } from "electron";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { onCorrect } from "../../common/ipc";
|
||||
import { Notifications } from "../components/notifications";
|
||||
import { defaultHotbarCells } from "../../common/hotbars/types";
|
||||
import { type ListNamespaceForbiddenArgs, clusterListNamespaceForbiddenChannel, isListNamespaceForbiddenArgs } from "../../common/ipc/cluster";
|
||||
import { type ListNamespaceForbiddenArgs, clusterListNamespaceForbiddenChannel } from "../../common/ipc/cluster";
|
||||
import { hotbarTooManyItemsChannel } from "../../common/ipc/hotbar";
|
||||
|
||||
function HotbarTooManyItemsHandler(): void {
|
||||
@ -23,15 +22,6 @@ interface Dependencies {
|
||||
}
|
||||
|
||||
export const registerIpcListeners = ({ listNamespacesForbiddenHandler }: Dependencies) => () => {
|
||||
onCorrect({
|
||||
source: ipcRenderer,
|
||||
channel: clusterListNamespaceForbiddenChannel,
|
||||
listener: listNamespacesForbiddenHandler,
|
||||
verifier: isListNamespaceForbiddenArgs,
|
||||
});
|
||||
onCorrect({
|
||||
source: ipcRenderer,
|
||||
channel: hotbarTooManyItemsChannel,
|
||||
listener: HotbarTooManyItemsHandler,
|
||||
verifier: (args: unknown[]): args is [] => args.length === 0,
|
||||
});};
|
||||
ipcRenderer.on(clusterListNamespaceForbiddenChannel, listNamespacesForbiddenHandler);
|
||||
ipcRenderer.on(hotbarTooManyItemsChannel, HotbarTooManyItemsHandler);
|
||||
};
|
||||
|
||||
@ -107,7 +107,7 @@ export class KubeWatchApi {
|
||||
unsubscribe.push(store.subscribe({ onLoadFailure, abortController: childController }));
|
||||
} catch (error) {
|
||||
if (!(error instanceof DOMException)) {
|
||||
this.log(Object.assign(new Error("Loading stores has failed"), { cause: error }), {
|
||||
this.log(new Error("Loading stores has failed", { cause: error }), {
|
||||
meta: { store, namespaces },
|
||||
});
|
||||
}
|
||||
|
||||
15
src/renderer/logger/browser-transport.injectable.ts
Normal file
15
src/renderer/logger/browser-transport.injectable.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 BrowserConsole from "winston-transport-browserconsole";
|
||||
import { loggerTransportInjectionToken } from "../../common/logger/transports";
|
||||
|
||||
const browserLoggerTransportInjectable = getInjectable({
|
||||
id: "browser-logger-transport",
|
||||
instantiate: () => new BrowserConsole(),
|
||||
injectionToken: loggerTransportInjectionToken,
|
||||
});
|
||||
|
||||
export default browserLoggerTransportInjectable;
|
||||
@ -7,30 +7,10 @@ import React from "react";
|
||||
import { ipcRenderer } from "electron";
|
||||
import * as proto from "../../../common/protocol-handler";
|
||||
import Url from "url-parse";
|
||||
import { onCorrect } from "../../../common/ipc";
|
||||
import type { LensProtocolRouterDependencies } from "../../../common/protocol-handler";
|
||||
import { foldAttemptResults, ProtocolHandlerInvalid, RouteAttempt } from "../../../common/protocol-handler";
|
||||
import { Notifications } from "../../components/notifications";
|
||||
|
||||
function verifyIpcArgs(args: unknown[]): args is [string, RouteAttempt] {
|
||||
if (args.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof args[0] !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (args[1]) {
|
||||
case RouteAttempt.MATCHED:
|
||||
case RouteAttempt.MISSING:
|
||||
case RouteAttempt.MISSING_EXTENSION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
interface Dependencies extends LensProtocolRouterDependencies {}
|
||||
|
||||
export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
@ -42,11 +22,7 @@ export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
* This function is needed to be called early on in the renderers lifetime.
|
||||
*/
|
||||
public init(): void {
|
||||
onCorrect({
|
||||
channel: proto.ProtocolHandlerInternal,
|
||||
source: ipcRenderer,
|
||||
verifier: verifyIpcArgs,
|
||||
listener: (event, rawUrl, mainAttemptResult) => {
|
||||
ipcRenderer.on(proto.ProtocolHandlerInternal, (event, rawUrl: string, mainAttemptResult: RouteAttempt) => {
|
||||
const rendererAttempt = this._routeToInternal(new Url(rawUrl, true));
|
||||
|
||||
if (foldAttemptResults(mainAttemptResult, rendererAttempt) === RouteAttempt.MISSING) {
|
||||
@ -58,13 +34,8 @@ export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
</p>
|
||||
));
|
||||
}
|
||||
},
|
||||
});
|
||||
onCorrect({
|
||||
channel: proto.ProtocolHandlerExtension,
|
||||
source: ipcRenderer,
|
||||
verifier: verifyIpcArgs,
|
||||
listener: async (event, rawUrl, mainAttemptResult) => {
|
||||
ipcRenderer.on(proto.ProtocolHandlerExtension, async (event, rawUrl: string, mainAttemptResult: RouteAttempt) => {
|
||||
const rendererAttempt = await this._routeToExtension(new Url(rawUrl, true));
|
||||
|
||||
switch (foldAttemptResults(mainAttemptResult, rendererAttempt)) {
|
||||
@ -87,12 +58,8 @@ export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
));
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
onCorrect({
|
||||
channel: ProtocolHandlerInvalid,
|
||||
source: ipcRenderer,
|
||||
listener: (event, error, rawUrl) => {
|
||||
ipcRenderer.on(ProtocolHandlerInvalid, (event, error: string, rawUrl: string) => {
|
||||
Notifications.error((
|
||||
<>
|
||||
<p>
|
||||
@ -107,10 +74,6 @@ export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
</p>
|
||||
</>
|
||||
));
|
||||
},
|
||||
verifier: (args): args is [string, string] => {
|
||||
return args.length === 2 && typeof args[0] === "string";
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
import Webpack from "webpack";
|
||||
import WebpackDevServer from "webpack-dev-server";
|
||||
import { webpackLensRenderer } from "./renderer";
|
||||
import logger from "../src/common/logger";
|
||||
import { buildDir, webpackDevServerPort } from "./vars";
|
||||
|
||||
/**
|
||||
@ -42,6 +41,6 @@ const server = new WebpackDevServer({
|
||||
},
|
||||
}, compiler);
|
||||
|
||||
logger.info(`[WEBPACK-DEV-SERVER]: created with options`, server.options);
|
||||
console.info(`[WEBPACK-DEV-SERVER]: created with options`, server.options);
|
||||
|
||||
server.start();
|
||||
|
||||
13
yarn.lock
13
yarn.lock
@ -4118,7 +4118,7 @@ colors@1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
|
||||
|
||||
colors@^1.3.3, colors@^1.4.0:
|
||||
colors@^1.3.3:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
|
||||
@ -8462,7 +8462,7 @@ lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
logform@^2.2.0, logform@^2.3.2, logform@^2.4.0:
|
||||
logform@^2.3.2, logform@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/logform/-/logform-2.4.0.tgz#131651715a17d50f09c2a2c1a524ff1a4164bcfe"
|
||||
integrity sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw==
|
||||
@ -12851,15 +12851,6 @@ win-ca@^3.5.0:
|
||||
node-forge "^1.2.1"
|
||||
split "^1.0.1"
|
||||
|
||||
winston-console-format@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/winston-console-format/-/winston-console-format-1.0.8.tgz#591adc8e9567c3397a3fa2e29e596d56e48db840"
|
||||
integrity sha512-dq7t/E0D0QRi4XIOwu6HM1+5e//WPqylH88GVjKEhQVrzGFg34MCz+G7pMJcXFBen9C0kBsu5GYgbYsE2LDwKw==
|
||||
dependencies:
|
||||
colors "^1.4.0"
|
||||
logform "^2.2.0"
|
||||
triple-beam "^1.3.0"
|
||||
|
||||
winston-transport-browserconsole@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/winston-transport-browserconsole/-/winston-transport-browserconsole-1.0.5.tgz#8ef1bc32da5fb0a66604f2b8b6f127ed725108c9"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user