mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Implement a decorator to emit telemetry for any specified function-injectable
Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
parent
e5df27389e
commit
7e9e48e631
@ -8,6 +8,7 @@ import appEventBusInjectable from "./app-event-bus.injectable";
|
|||||||
const emitEventInjectable = getInjectable({
|
const emitEventInjectable = getInjectable({
|
||||||
id: "emit-event",
|
id: "emit-event",
|
||||||
instantiate: (di) => di.inject(appEventBusInjectable).emit,
|
instantiate: (di) => di.inject(appEventBusInjectable).emit,
|
||||||
|
decorable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default emitEventInjectable;
|
export default emitEventInjectable;
|
||||||
|
|||||||
@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting";
|
||||||
|
import telemetryWhiteListForFunctionsInjectable from "./renderer/telemetry-white-list-for-functions.injectable";
|
||||||
|
import { runInAction } from "mobx";
|
||||||
|
import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||||
|
|
||||||
|
describe("sending-telemetry-from-white-listed-function-calls", () => {
|
||||||
|
let di: DiContainer;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given a telemetry white-list for injectables which instantiate a function", () => {
|
||||||
|
let emitEventMock: jest.Mock;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
di.override(telemetryWhiteListForFunctionsInjectable, () => [
|
||||||
|
"some-white-listed-function",
|
||||||
|
]);
|
||||||
|
|
||||||
|
emitEventMock = jest.fn();
|
||||||
|
di.override(emitEventInjectable, () => emitEventMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("given instances of white-listed, non-white-listed and tagged functions", () => {
|
||||||
|
let whiteListedFunctionMock: jest.Mock;
|
||||||
|
let nonWhiteListedFunctionMock: jest.Mock;
|
||||||
|
let taggedFunctionMock: jest.Mock;
|
||||||
|
let injectedWhiteListedFunction: jest.Mock;
|
||||||
|
let injectedNonWhiteListedFunction: jest.Mock;
|
||||||
|
let injectedTaggedFunction: jest.Mock;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
whiteListedFunctionMock = jest.fn();
|
||||||
|
nonWhiteListedFunctionMock = jest.fn();
|
||||||
|
taggedFunctionMock = jest.fn();
|
||||||
|
|
||||||
|
const whiteListedInjectable = getInjectable({
|
||||||
|
id: "some-white-listed-function",
|
||||||
|
instantiate: () => whiteListedFunctionMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
const nonWhiteListedInjectable = getInjectable({
|
||||||
|
id: "some-non-white-listed-function",
|
||||||
|
instantiate: () => nonWhiteListedFunctionMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
const taggedInjectable = getInjectable({
|
||||||
|
id: "some-tagged-function",
|
||||||
|
instantiate: () => taggedFunctionMock,
|
||||||
|
tags: ["emit-telemetry"],
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
di.register(whiteListedInjectable);
|
||||||
|
di.register(nonWhiteListedInjectable);
|
||||||
|
di.register(taggedInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
|
injectedWhiteListedFunction = di.inject(whiteListedInjectable);
|
||||||
|
injectedNonWhiteListedFunction = di.inject(nonWhiteListedInjectable);
|
||||||
|
injectedTaggedFunction = di.inject(taggedInjectable);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("telemetry is not emitted yet", () => {
|
||||||
|
expect(emitEventMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the white-listed function is called", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
injectedWhiteListedFunction("some-arg", "some-other-arg");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("telemetry is emitted in event bus", () => {
|
||||||
|
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 non-white-listed function is called", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
injectedNonWhiteListedFunction();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("telemetry is not emitted", () => {
|
||||||
|
expect(emitEventMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the tagged, but not white-listed function is called", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
injectedTaggedFunction("some-arg", "some-other-arg");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("telemetry is emitted in event bus", () => {
|
||||||
|
expect(emitEventMock).toHaveBeenCalledWith({
|
||||||
|
destination: "auto-capture",
|
||||||
|
action: "telemetry-from-business-action",
|
||||||
|
name: "some-tagged-function",
|
||||||
|
params: { args: ["some-arg", "some-other-arg"] },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
27
src/features/telemetry/renderer/emit-telemetry.injectable.ts
Normal file
27
src/features/telemetry/renderer/emit-telemetry.injectable.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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 emitEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||||
|
|
||||||
|
const emitTelemetryInjectable = getInjectable({
|
||||||
|
id: "emit-telemetry",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const emitEvent = di.inject(emitEventInjectable);
|
||||||
|
|
||||||
|
return ({ action, args }: { action: string; args: any[] }) => {
|
||||||
|
emitEvent({
|
||||||
|
destination: "auto-capture",
|
||||||
|
action: "telemetry-from-business-action",
|
||||||
|
name: action,
|
||||||
|
params: { args },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
decorable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default emitTelemetryInjectable;
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { DiContainerForInjection } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
import {
|
||||||
|
lifecycleEnum,
|
||||||
|
getInjectable,
|
||||||
|
instantiationDecoratorToken,
|
||||||
|
} from "@ogre-tools/injectable";
|
||||||
|
import assert from "assert";
|
||||||
|
|
||||||
|
|
||||||
|
import { isFunction } from "lodash/fp";
|
||||||
|
import emitTelemetryInjectable from "./emit-telemetry.injectable";
|
||||||
|
import telemetryWhiteListForFunctionsInjectable from "./telemetry-white-list-for-functions.injectable";
|
||||||
|
|
||||||
|
const telemetryDecoratorInjectable = getInjectable({
|
||||||
|
id: "telemetry-decorator",
|
||||||
|
|
||||||
|
instantiate: (diForDecorator) => {
|
||||||
|
const emitTelemetry = diForDecorator.inject(emitTelemetryInjectable);
|
||||||
|
|
||||||
|
const whiteList = diForDecorator.inject(
|
||||||
|
telemetryWhiteListForFunctionsInjectable,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
decorate:
|
||||||
|
(instantiateToBeDecorated: any) =>
|
||||||
|
(di: DiContainerForInjection, instantiationParameter: any) => {
|
||||||
|
const instance = instantiateToBeDecorated(di, instantiationParameter);
|
||||||
|
|
||||||
|
if (isFunction(instance)) {
|
||||||
|
return (...args: any[]) => {
|
||||||
|
const currentContext = di.context.at(-1);
|
||||||
|
|
||||||
|
assert(currentContext);
|
||||||
|
|
||||||
|
if (shouldEmitTelemetry(currentContext, whiteList)) {
|
||||||
|
emitTelemetry({ action: currentContext.injectable.id, args });
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance(...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
decorable: false,
|
||||||
|
// Todo: this is required because of imperfect typing in injectable.
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
injectionToken: instantiationDecoratorToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldEmitTelemetry = (currentContext: any, whiteList: any) => (
|
||||||
|
currentContext.injectable.tags?.includes("emit-telemetry") ||
|
||||||
|
whiteList.includes(currentContext.injectable.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
export default telemetryDecoratorInjectable;
|
||||||
@ -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";
|
||||||
|
|
||||||
|
const telemetryWhiteListForFunctionsInjectable = getInjectable({
|
||||||
|
id: "telemetry-white-list-for-functions",
|
||||||
|
instantiate: () => ["some-placeholder-injectable-id"],
|
||||||
|
decorable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default telemetryWhiteListForFunctionsInjectable;
|
||||||
Loading…
Reference in New Issue
Block a user