feat(telemetry): Implement structured telemetry logging and reporting
Adds comprehensive client-side telemetry capabilities for usage, errors, and performance metrics. This includes integrating OpenTelemetry standards into both the frontend (Svelte) and backend (Tauri/Rust) layers to capture events, spans, and system resource utilization. The implementation ensures that all collected data is privacy-filtered by design, explicitly excluding sensitive information like repository paths, credentials, source code, or email addresses from being logged. - Updates README with detailed SigNoz telemetry guide - Adds process metrics collection (CPU/Memory) in Rust backend - Exposes `setTelemetryEnabled` state management to the frontend
This commit is contained in:
+10
-5
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount, tick } from "svelte";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { open as openDialog } from "@tauri-apps/plugin-dialog";
|
||||
import { check, type DownloadEvent, type Update } from "@tauri-apps/plugin-updater";
|
||||
import { AlertCircle, Cherry, Download, FolderOpen, GitBranch, GitMerge, LoaderCircle, Plus, Search, Star, X } from "@lucide/svelte";
|
||||
@@ -160,6 +159,7 @@
|
||||
summarizeGitError,
|
||||
} from "./lib/credentials";
|
||||
import { trackAnalyticsEvent, type AnalyticsEventProperties } from "./lib/analytics";
|
||||
import { setTelemetryEnabled, tracedInvoke } from "./lib/telemetry";
|
||||
|
||||
type UpdateToastState = "available" | "downloading" | "installed" | "error";
|
||||
type AppView = "management" | "repository";
|
||||
@@ -503,7 +503,7 @@
|
||||
|
||||
async function closeStartupSplashscreen() {
|
||||
try {
|
||||
await invoke("close_splashscreen");
|
||||
await tracedInvoke("close_splashscreen");
|
||||
} catch {
|
||||
// Browser preview and failed startup paths should keep working without Tauri.
|
||||
}
|
||||
@@ -815,6 +815,7 @@
|
||||
|
||||
function initAnalytics() {
|
||||
analyticsSettings = loadAnalyticsSettings();
|
||||
setTelemetryEnabled(analyticsSettings.noticeSeen && analyticsSettings.enabled);
|
||||
if (!analyticsSettings.noticeSeen) {
|
||||
analyticsNoticeOpen = true;
|
||||
return;
|
||||
@@ -831,6 +832,7 @@
|
||||
analyticsSettings = { enabled, noticeSeen: true };
|
||||
persistAnalyticsSettings(analyticsSettings);
|
||||
analyticsNoticeOpen = false;
|
||||
setTelemetryEnabled(enabled);
|
||||
trackEvent("app_started", { first_run: 1 });
|
||||
}
|
||||
|
||||
@@ -900,6 +902,7 @@
|
||||
persistThemePreference(nextTheme);
|
||||
persistLanguagePreference(nextLanguage);
|
||||
persistStoredBoolean(AUTO_REFRESH_ENABLED_KEY, nextAutoRefresh);
|
||||
setTelemetryEnabled(next.enabled);
|
||||
appSettingsOpen = false;
|
||||
if (nextAutoRefresh && !autoRefreshWasEnabled) void autoRefreshTick();
|
||||
if (next.enabled) trackEvent("settings_saved", { analytics_enabled: 1, theme: nextTheme, language: nextLanguage, auto_refresh: nextAutoRefresh ? 1 : 0 });
|
||||
@@ -1746,9 +1749,11 @@
|
||||
}
|
||||
|
||||
function errorToMessage(error: unknown): string {
|
||||
if (error instanceof Error) return error.message;
|
||||
if (typeof error === "string") return error;
|
||||
try { return JSON.stringify(error) ?? "Unknown error"; } catch { return "Unknown error"; }
|
||||
let message: string;
|
||||
if (error instanceof Error) message = error.message;
|
||||
else if (typeof error === "string") message = error;
|
||||
else try { message = JSON.stringify(error) ?? "Unknown error"; } catch { message = "Unknown error"; }
|
||||
return message;
|
||||
}
|
||||
|
||||
function isNonFastForwardPushError(message: string): boolean {
|
||||
|
||||
Reference in New Issue
Block a user