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

View File

@ -4,7 +4,7 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
import { toJS, observable } from "mobx";
import { observable, toJS } from "mobx";
const emitTelemetryInjectable = getInjectable({
id: "emit-telemetry",
@ -12,12 +12,12 @@ const emitTelemetryInjectable = getInjectable({
instantiate: (di) => {
const emitEvent = di.inject(emitEventInjectable);
return ({ action, args }: { action: string; args: any[] }) => {
return ({ action, params }: { action: string; params?: object }) => {
emitEvent({
destination: "auto-capture",
action: "telemetry-from-business-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.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type {
DiContainerForInjection,
Injectable,
} from "@ogre-tools/injectable";
import type { DiContainerForInjection } from "@ogre-tools/injectable";
import {
lifecycleEnum,
getInjectable,
instantiationDecoratorToken,
lifecycleEnum,
} from "@ogre-tools/injectable";
import assert from "assert";
import assert from "assert";
import { isFunction } from "lodash/fp";
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({
id: "telemetry-decorator",
@ -25,33 +25,40 @@ const telemetryDecoratorInjectable = getInjectable({
const emitTelemetry = diForDecorator.inject(emitTelemetryInjectable);
const whiteList = diForDecorator.inject(
telemetryWhiteListForFunctionsInjectable,
telemetryWhiteListForFunctionsInjectable
);
const shouldEmitTelemetry = shouldEmitTelemetryFor(whiteList);
const whitleListMap = getWhitleListMap(whiteList);
return {
decorate:
(instantiateToBeDecorated: any) =>
(di: DiContainerForInjection, instantiationParameter: any) => {
const instance = instantiateToBeDecorated(di, instantiationParameter);
(di: DiContainerForInjection, instantiationParameter: any) => {
const instance = instantiateToBeDecorated(di, instantiationParameter);
if (isFunction(instance)) {
return (...args: any[]) => {
const currentContext = di.context.at(-1);
if (isFunction(instance)) {
return (...args: any[]) => {
const currentContext = di.context.at(-1);
assert(currentContext);
assert(currentContext);
if (shouldEmitTelemetry(currentContext.injectable)) {
emitTelemetry({ action: currentContext.injectable.id, args });
}
const whiteListed = whitleListMap.get(
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,
});
const shouldEmitTelemetryFor =
(whiteList: string[]) => (injectable: Injectable<any, any, any>) =>
whiteList.includes(injectable.id);
const getWhitleListMap = (whiteList: WhiteListItem[]) =>
new Map(
whiteList.map((item) =>
typeof item === "string"
? [
item,
{
getParams: (...args: any[]) => undefined,
},
]
: [
item.id,
{
getParams: item.getParams,
},
]
)
);
export default telemetryDecoratorInjectable;

View File

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