1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Introduce white-listing for params of telemetry

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
Iku-turso 2023-03-02 16:22:06 +02:00
parent 556fa8dd33
commit 9414626c66
4 changed files with 123 additions and 52 deletions

View File

@ -22,6 +22,11 @@ describe("emit-telemetry-from-specific-function-calls", () => {
beforeEach(() => { beforeEach(() => {
di.override(telemetryWhiteListForFunctionsInjectable, () => [ di.override(telemetryWhiteListForFunctionsInjectable, () => [
"some-white-listed-function", "some-white-listed-function",
{
id: "some-white-listed-function-with-white-listed-argument",
getParams: (irrelevantArg, arg) => ({ someParam: arg }),
},
]); ]);
emitEventMock = jest.fn(); emitEventMock = jest.fn();
@ -32,6 +37,7 @@ describe("emit-telemetry-from-specific-function-calls", () => {
let whiteListedFunctionMock: jest.Mock; let whiteListedFunctionMock: jest.Mock;
let nonWhiteListedFunctionMock: jest.Mock; let nonWhiteListedFunctionMock: jest.Mock;
let injectedWhiteListedFunction: jest.Mock; let injectedWhiteListedFunction: jest.Mock;
let injectedWhiteListedFunctionWithArgument: jest.Mock;
let injectedNonWhiteListedFunction: jest.Mock; let injectedNonWhiteListedFunction: jest.Mock;
beforeEach(() => { beforeEach(() => {
@ -43,16 +49,30 @@ describe("emit-telemetry-from-specific-function-calls", () => {
instantiate: () => whiteListedFunctionMock, instantiate: () => whiteListedFunctionMock,
}); });
const whiteListedInjectableWithArgument = getInjectable({
id: "some-white-listed-function-with-white-listed-argument",
instantiate: () => whiteListedFunctionMock,
});
const nonWhiteListedInjectable = getInjectable({ const nonWhiteListedInjectable = getInjectable({
id: "some-non-white-listed-function", id: "some-non-white-listed-function",
instantiate: () => nonWhiteListedFunctionMock, instantiate: () => nonWhiteListedFunctionMock,
}); });
runInAction(() => { runInAction(() => {
di.register(whiteListedInjectable, nonWhiteListedInjectable); di.register(
whiteListedInjectable,
whiteListedInjectableWithArgument,
nonWhiteListedInjectable
);
}); });
injectedWhiteListedFunction = di.inject(whiteListedInjectable); injectedWhiteListedFunction = di.inject(whiteListedInjectable);
injectedWhiteListedFunctionWithArgument = di.inject(
whiteListedInjectableWithArgument
);
injectedNonWhiteListedFunction = di.inject(nonWhiteListedInjectable); injectedNonWhiteListedFunction = di.inject(nonWhiteListedInjectable);
}); });
@ -60,22 +80,51 @@ describe("emit-telemetry-from-specific-function-calls", () => {
expect(emitEventMock).not.toHaveBeenCalled(); expect(emitEventMock).not.toHaveBeenCalled();
}); });
describe("when the white-listed function is called with parameters", () => { describe("when a normal white-listed function is called with arguments", () => {
beforeEach(() => { beforeEach(() => {
injectedWhiteListedFunction("some-arg", "some-other-arg"); injectedWhiteListedFunction("some-arg", "some-other-arg");
}); });
it("telemetry is emitted in event bus", () => { it("telemetry is emitted in event bus without the arguments", () => {
expect(emitEventMock).toHaveBeenCalledWith({ expect(emitEventMock).toHaveBeenCalledWith({
destination: "auto-capture", destination: "auto-capture",
action: "telemetry-from-business-action", action: "telemetry-from-business-action",
name: "some-white-listed-function", name: "some-white-listed-function",
params: { args: ["some-arg", "some-other-arg"] },
}); });
}); });
}); });
describe("when the white-listed function is called with MobX reactive content", () => { describe("when a white-listed function with a white-listed argument is called with arguments", () => {
beforeEach(() => {
injectedWhiteListedFunctionWithArgument("some-arg", "some-other-arg");
});
it("telemetry is emitted in event bus with the arguments as params", () => {
expect(emitEventMock).toHaveBeenCalledWith({
action: "telemetry-from-business-action",
destination: "auto-capture",
name: "some-white-listed-function-with-white-listed-argument",
params: { someParam: "some-other-arg" },
});
});
});
describe("when a white-listed function with a white-listed argument is called without arguments", () => {
beforeEach(() => {
injectedWhiteListedFunctionWithArgument();
});
it("telemetry is emitted in event bus without params", () => {
expect(emitEventMock).toHaveBeenCalledWith({
action: "telemetry-from-business-action",
destination: "auto-capture",
name: "some-white-listed-function-with-white-listed-argument",
params: { someParam: undefined },
});
});
});
describe("when the white-listed function with a white-listed argument is called with MobX reactive content", () => {
beforeEach(() => { beforeEach(() => {
const someComputedProperty = computed(() => "some-computed-value"); const someComputedProperty = computed(() => "some-computed-value");
@ -84,22 +133,23 @@ describe("emit-telemetry-from-specific-function-calls", () => {
someComputedProperty, someComputedProperty,
}; };
injectedWhiteListedFunction(someObservable); injectedWhiteListedFunctionWithArgument(
"irrelevant-argument",
someObservable
);
}); });
it("telemetry is emitted in event bus without MobX internals or computeds", () => { it("telemetry is emitted in event bus without MobX internals or computeds", () => {
expect(emitEventMock).toHaveBeenCalledWith({ expect(emitEventMock).toHaveBeenCalledWith({
destination: "auto-capture", destination: "auto-capture",
action: "telemetry-from-business-action", action: "telemetry-from-business-action",
name: "some-white-listed-function", name: "some-white-listed-function-with-white-listed-argument",
params: { params: {
args: [ someParam: {
{ someStaticProperty: "some-static-value",
someStaticProperty: "some-static-value", someComputedProperty: "some-computed-value",
someComputedProperty: "some-computed-value", },
},
],
}, },
}); });
}); });

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; import emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
import { toJS, observable } from "mobx"; import { observable, toJS } from "mobx";
const emitTelemetryInjectable = getInjectable({ const emitTelemetryInjectable = getInjectable({
id: "emit-telemetry", id: "emit-telemetry",
@ -12,12 +12,12 @@ const emitTelemetryInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const emitEvent = di.inject(emitEventInjectable); const emitEvent = di.inject(emitEventInjectable);
return ({ action, args }: { action: string; args: any[] }) => { return ({ action, params }: { action: string; params?: object }) => {
emitEvent({ emitEvent({
destination: "auto-capture", destination: "auto-capture",
action: "telemetry-from-business-action", action: "telemetry-from-business-action",
name: action, name: action,
params: { args: toJS(observable(args)) }, ...(params ? { params: toJS(observable(params)) } : {}),
}); });
}; };
}, },

View File

@ -2,21 +2,21 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { import type { DiContainerForInjection } from "@ogre-tools/injectable";
DiContainerForInjection,
Injectable,
} from "@ogre-tools/injectable";
import { import {
lifecycleEnum,
getInjectable, getInjectable,
instantiationDecoratorToken, instantiationDecoratorToken,
lifecycleEnum,
} from "@ogre-tools/injectable"; } from "@ogre-tools/injectable";
import assert from "assert";
import assert from "assert";
import { isFunction } from "lodash/fp"; import { isFunction } from "lodash/fp";
import emitTelemetryInjectable from "./emit-telemetry.injectable"; import emitTelemetryInjectable from "./emit-telemetry.injectable";
import telemetryWhiteListForFunctionsInjectable from "./telemetry-white-list-for-functions.injectable";
import telemetryWhiteListForFunctionsInjectable, {
WhiteListItem,
} from "./telemetry-white-list-for-functions.injectable";
const telemetryDecoratorInjectable = getInjectable({ const telemetryDecoratorInjectable = getInjectable({
id: "telemetry-decorator", id: "telemetry-decorator",
@ -25,33 +25,40 @@ const telemetryDecoratorInjectable = getInjectable({
const emitTelemetry = diForDecorator.inject(emitTelemetryInjectable); const emitTelemetry = diForDecorator.inject(emitTelemetryInjectable);
const whiteList = diForDecorator.inject( const whiteList = diForDecorator.inject(
telemetryWhiteListForFunctionsInjectable, telemetryWhiteListForFunctionsInjectable
); );
const shouldEmitTelemetry = shouldEmitTelemetryFor(whiteList); const whitleListMap = getWhitleListMap(whiteList);
return { return {
decorate: decorate:
(instantiateToBeDecorated: any) => (instantiateToBeDecorated: any) =>
(di: DiContainerForInjection, instantiationParameter: any) => { (di: DiContainerForInjection, instantiationParameter: any) => {
const instance = instantiateToBeDecorated(di, instantiationParameter); const instance = instantiateToBeDecorated(di, instantiationParameter);
if (isFunction(instance)) { if (isFunction(instance)) {
return (...args: any[]) => { return (...args: any[]) => {
const currentContext = di.context.at(-1); const currentContext = di.context.at(-1);
assert(currentContext); assert(currentContext);
if (shouldEmitTelemetry(currentContext.injectable)) { const whiteListed = whitleListMap.get(
emitTelemetry({ action: currentContext.injectable.id, args }); currentContext.injectable.id
} );
return instance(...args); if (whiteListed) {
}; emitTelemetry({
} action: currentContext.injectable.id,
params: whiteListed.getParams(...args),
});
}
return instance; return instance(...args);
}, };
}
return instance;
},
}; };
}, },
@ -61,8 +68,23 @@ const telemetryDecoratorInjectable = getInjectable({
injectionToken: instantiationDecoratorToken, injectionToken: instantiationDecoratorToken,
}); });
const shouldEmitTelemetryFor = const getWhitleListMap = (whiteList: WhiteListItem[]) =>
(whiteList: string[]) => (injectable: Injectable<any, any, any>) => new Map(
whiteList.includes(injectable.id); whiteList.map((item) =>
typeof item === "string"
? [
item,
{
getParams: (...args: any[]) => undefined,
},
]
: [
item.id,
{
getParams: item.getParams,
},
]
)
);
export default telemetryDecoratorInjectable; export default telemetryDecoratorInjectable;

View File

@ -3,6 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { AppEvent } from "../../../common/app-event-bus/event-bus";
const navigateTo = [ const navigateTo = [
"navigate-to-preference-tab-id", "navigate-to-preference-tab-id",
@ -88,21 +89,19 @@ const extensions = [
"uninstall-extension", "uninstall-extension",
]; ];
const externalActions = [ const externalActions = ["open-link-in-browser"];
"open-link-in-browser",
];
const uiInteraction = [ const uiInteraction = ["show-details"];
"show-details",
];
const terminal = [ const terminal = ["create-terminal-tab"];
"create-terminal-tab",
]; export type WhiteListItem =
| string
| { id: string; getParams: (...args: unknown[]) => AppEvent["params"] };
const telemetryWhiteListForFunctionsInjectable = getInjectable({ const telemetryWhiteListForFunctionsInjectable = getInjectable({
id: "telemetry-white-list-for-functions", id: "telemetry-white-list-for-functions",
instantiate: () => [ instantiate: (): WhiteListItem[] => [
...navigateTo, ...navigateTo,
...helmInjectableIds, ...helmInjectableIds,
...kubeConfigActions, ...kubeConfigActions,