diff --git a/extensions/telemetry/src/tracker.ts b/extensions/telemetry/src/tracker.ts index ed23253bd6..d5f16334b2 100644 --- a/extensions/telemetry/src/tracker.ts +++ b/extensions/telemetry/src/tracker.ts @@ -1,4 +1,4 @@ -import { EventBus, Util } from "@k8slens/extensions" +import { EventBus, Util, Store, App } from "@k8slens/extensions" import ua from "universal-analytics" import { machineIdSync } from "node-machine-id" import { telemetryPreferencesStore } from "./telemetry-preferences-store" @@ -15,6 +15,8 @@ export class Tracker extends Util.Singleton { protected locale: string; protected electronUA: string; + protected reportInterval: NodeJS.Timeout + private constructor() { super(); try { @@ -23,7 +25,7 @@ export class Tracker extends Util.Singleton { this.visitor = ua(Tracker.GA_ID) } this.visitor.set("dl", "https://telemetry.k8slens.dev") - + this.visitor.set("ua", `Lens ${App.version} (${this.getOS()})`) } start() { @@ -36,6 +38,8 @@ export class Tracker extends Util.Singleton { } this.eventHandlers.push(handler) EventBus.appEventBus.addListener(handler) + + this.reportInterval = setInterval(this.reportData, 60 * 60 * 1000) // report every 1h } stop() { @@ -46,12 +50,59 @@ export class Tracker extends Util.Singleton { for (const handler of this.eventHandlers) { EventBus.appEventBus.removeListener(handler) } + if (this.reportInterval) { + clearInterval(this.reportInterval) + } } protected async isTelemetryAllowed(): Promise { return telemetryPreferencesStore.enabled } + protected reportData() { + const clustersList = Store.clusterStore.clustersList + + this.event("generic-data", "report", { + appVersion: App.version, + clustersCount: clustersList.length, + workspacesCount: Store.workspaceStore.workspacesList.length + }) + + clustersList.forEach((cluster) => { + if (!cluster?.metadata.lastSeen) { return } + this.reportClusterData(cluster) + }) + } + + protected reportClusterData(cluster: Store.ClusterModel) { + this.event("cluster-data", "report", { + id: cluster.metadata.id, + kubernetesVersion: cluster.metadata.version, + distribution: cluster.metadata.distribution, + nodesCount: cluster.metadata.nodes, + lastSeen: cluster.metadata.lastSeen + }) + } + + protected getOS() { + let os = "" + if (App.isMac) { + os = "MacOS" + } else if(App.isWindows) { + os = "Windows" + } else if (App.isLinux) { + os = "Linux" + if (App.isSnap) { + os += "; Snap" + } else { + os += "; AppImage" + } + } else { + os = "Unknown" + } + return os + } + protected async event(eventCategory: string, eventAction: string, otherParams = {}) { try { const allowed = await this.isTelemetryAllowed(); diff --git a/src/common/vars.ts b/src/common/vars.ts index ca28a2f99a..206aa59ce2 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -5,7 +5,9 @@ import { defineGlobal } from "./utils/defineGlobal"; export const isMac = process.platform === "darwin" export const isWindows = process.platform === "win32" +export const isLinux = process.platform === "linux" export const isDebugging = process.env.DEBUG === "true"; +export const isSnap = !!process.env["SNAP"] export const isProduction = process.env.NODE_ENV === "production" export const isTestEnv = !!process.env.JEST_WORKER_ID; export const isDevelopment = !isTestEnv && !isProduction; diff --git a/src/common/workspace-store.ts b/src/common/workspace-store.ts index 752a53f41b..5cb01788f3 100644 --- a/src/common/workspace-store.ts +++ b/src/common/workspace-store.ts @@ -3,6 +3,7 @@ import { BaseStore } from "./base-store"; import { clusterStore } from "./cluster-store" import { landingURL } from "../renderer/components/+landing-page/landing-page.route"; import { navigate } from "../renderer/navigation"; +import { appEventBus } from "./event-bus"; export type WorkspaceId = string; @@ -79,6 +80,9 @@ export class WorkspaceStore extends BaseStore { } if (existingWorkspace) { Object.assign(existingWorkspace, workspace); + appEventBus.emit({name: "workspace", action: "update"}) + } else { + appEventBus.emit({name: "workspace", action: "add"}) } this.workspaces.set(id, workspace); return workspace; @@ -95,6 +99,7 @@ export class WorkspaceStore extends BaseStore { this.currentWorkspaceId = WorkspaceStore.defaultId; // reset to default } this.workspaces.delete(id); + appEventBus.emit({name: "workspace", action: "remove"}) clusterStore.removeByWorkspaceId(id) } diff --git a/src/extensions/core-api/app.ts b/src/extensions/core-api/app.ts new file mode 100644 index 0000000000..192a3222af --- /dev/null +++ b/src/extensions/core-api/app.ts @@ -0,0 +1,5 @@ +import { app } from "electron"; +import { getAppVersion } from "../../common/utils"; + +export const version = getAppVersion() +export { isSnap, isWindows, isMac, isLinux, appName } from "../../common/vars" \ No newline at end of file diff --git a/src/extensions/core-api/index.ts b/src/extensions/core-api/index.ts index c98266a2c5..16a989e7ac 100644 --- a/src/extensions/core-api/index.ts +++ b/src/extensions/core-api/index.ts @@ -5,6 +5,7 @@ export * from "../lens-renderer-extension" import type { WindowManager } from "../../main/window-manager"; // APIs +import * as App from "./app" import * as EventBus from "./event-bus" import * as Store from "./stores" import * as Util from "./utils" @@ -15,6 +16,7 @@ import * as ClusterFeature from "./cluster-feature" export let windowManager: WindowManager; export { + App, EventBus, ClusterFeature, Store, diff --git a/src/extensions/core-api/stores.ts b/src/extensions/core-api/stores.ts index 9ff2c66763..dfaae325af 100644 --- a/src/extensions/core-api/stores.ts +++ b/src/extensions/core-api/stores.ts @@ -1,2 +1,4 @@ export { ExtensionStore } from "../extension-store" +export { clusterStore, ClusterModel } from "../../common/cluster-store" +export { workspaceStore} from "../../common/workspace-store" export type { Cluster } from "../../main/cluster"