Sentry fixes (#1658)

This commit is contained in:
lucas lelievre
2025-12-11 02:26:10 +01:00
committed by GitHub
13 changed files with 72 additions and 57 deletions

View File

@@ -20,8 +20,8 @@
"@tauri-apps/plugin-dialog": "^2.0.0",
"@tauri-apps/plugin-fs": "2.4.1",
"@tauri-apps/plugin-http": "^2.5.0",
"@tauri-apps/plugin-opener": "^2.4.0",
"@tauri-apps/plugin-log": "~2",
"@tauri-apps/plugin-opener": "^2.4.0",
"@tauri-apps/plugin-os": "^2.0.0",
"@tauri-apps/plugin-shell": "^2.3.0",
"@tauri-apps/plugin-store": "^2.4.1",
@@ -52,6 +52,7 @@
"ts-pattern": "^5.4.0",
"typescript": "^5.6.3",
"use-double-tap": "^1.3.6",
"uuid": "^13.0.0",
"yup": "^1.4.0"
},
"scripts": {

View File

@@ -326,6 +326,14 @@ export function ScaledProportionsPage() {
}
);
useEffect(() => {
if (lastUsed !== null) {
Sentry.metrics.count('scaled_proportions', 1, {
attributes: { calibration: lastUsed },
});
}
}, [lastUsed]);
useEffect(() => {
sendRPCPacket(
RpcMessage.SkeletonConfigRequest,
@@ -334,11 +342,6 @@ export function ScaledProportionsPage() {
return () => {
cancel();
if (lastUsed !== null) {
Sentry.metrics.count('scaled_proportions', 1, {
attributes: { calibration: lastUsed },
});
}
};
}, []);

View File

@@ -1,30 +1,16 @@
import { ReactNode, useContext, useLayoutEffect } from 'react';
import { ReactNode } from 'react';
import { ConfigContextC, loadConfig, useConfigProvider } from '@/hooks/config';
import { DEFAULT_LOCALE, LangContext } from '@/i18n/config';
import { getSentryOrCompute } from '@/utils/sentry';
const config = await loadConfig();
if (config?.errorTracking !== undefined) {
// load sentry ASAP to catch early errors
getSentryOrCompute(config.errorTracking ?? false);
getSentryOrCompute(config.errorTracking ?? false, config.uuid);
}
export function ConfigContextProvider({ children }: { children: ReactNode }) {
const context = useConfigProvider(config);
const { changeLocales } = useContext(LangContext);
useLayoutEffect(() => {
changeLocales([config?.lang || DEFAULT_LOCALE]);
}, []);
useLayoutEffect(() => {
if (config?.errorTracking !== undefined) {
// Alows for sentry to refresh if user change the setting once the gui
// is initialized
getSentryOrCompute(config.errorTracking ?? false);
}
}, [config?.errorTracking]);
return (
<ConfigContextC.Provider value={context}>

View File

@@ -55,16 +55,10 @@ export function TrackingChecklistSettings({
// that prevent sending a packet for steps that didnt change
if (!value && !ignoredSteps.includes(stepId)) {
ignoreStep(stepId, true);
Sentry.metrics.count('mute_checklist_step', 1, {
attributes: { step: TrackingChecklistStepId[stepId] },
});
}
if (value && ignoredSteps.includes(stepId)) {
ignoreStep(stepId, false);
Sentry.metrics.count('unmute_checklist_step', 1, {
attributes: { step: TrackingChecklistStepId[stepId] },
});
}
}
};

View File

@@ -1,4 +1,4 @@
import { createContext, useContext, useEffect, useState } from 'react';
import { createContext, useContext, useEffect, useLayoutEffect, useState } from 'react';
import {
DataFeedMessage,
DataFeedUpdateT,
@@ -12,8 +12,9 @@ import { useBonesDataFeedConfig, useDataFeedConfig } from './datafeed-config';
import { useWebsocketAPI } from './websocket-api';
import { useAtomValue, useSetAtom } from 'jotai';
import { bonesAtom, datafeedAtom, devicesAtom } from '@/store/app-store';
import { updateSentryContext } from '@/utils/sentry';
import { getSentryOrCompute, updateSentryContext } from '@/utils/sentry';
import { fetchCurrentFirmwareRelease, FirmwareRelease } from './firmware-update';
import { DEFAULT_LOCALE, LangContext } from '@/i18n/config';
export interface AppContext {
currentFirmwareRelease: FirmwareRelease | null;
@@ -22,6 +23,7 @@ export interface AppContext {
export function useProvideAppContext(): AppContext {
const { useRPCPacket, sendDataFeedPacket, useDataFeedPacket, isConnected } =
useWebsocketAPI();
const { changeLocales } = useContext(LangContext);
const { config } = useConfig();
const { dataFeedConfig } = useDataFeedConfig();
const bonesDataFeedConfig = useBonesDataFeedConfig();
@@ -58,14 +60,30 @@ export function useProvideAppContext(): AppContext {
});
useEffect(() => {
if (!config) return;
const interval = setInterval(() => {
fetchCurrentFirmwareRelease().then((res) => setCurrentFirmwareRelease(res));
fetchCurrentFirmwareRelease(config.uuid).then(setCurrentFirmwareRelease);
}, 1000);
return () => {
clearInterval(interval);
};
}, [config?.uuid]);
useLayoutEffect(() => {
changeLocales([config?.lang || DEFAULT_LOCALE]);
}, []);
useLayoutEffect(() => {
if (!config) return;
if (config.errorTracking !== undefined) {
console.log('change');
// Alows for sentry to refresh if user change the setting once the gui
// is initialized
getSentryOrCompute(config.errorTracking ?? false, config.uuid);
}
}, [config]);
return {
currentFirmwareRelease,
};

View File

@@ -9,6 +9,7 @@ import { load, Store } from '@tauri-apps/plugin-store';
import { useIsTauri } from './breakpoint';
import { waitUntil } from '@/utils/a11y';
import { isTauri } from '@tauri-apps/api/core';
import { v4 as uuidv4 } from 'uuid';
export interface WindowConfig {
width: number;
@@ -26,6 +27,7 @@ export enum AssignMode {
}
export interface Config {
uuid: string;
debug: boolean;
lang: string;
doneOnboarding: boolean;
@@ -57,6 +59,7 @@ export interface ConfigContext {
}
export const defaultConfig: Config = {
uuid: uuidv4(),
lang: 'en',
debug: false,
doneOnboarding: false,
@@ -117,13 +120,16 @@ export const loadConfig = async () => {
if (!json) throw new Error('Config has ceased existing for some reason');
const loadedConfig = fallbackToDefaults(JSON.parse(json));
// set(loadedConfig);
// setLoading(false);
if (!loadedConfig.uuid) {
// Make sure the config always has a uuid
loadedConfig.uuid = uuidv4();
await store.set('config.json', JSON.stringify(loadedConfig));
}
return loadedConfig;
} catch (e) {
error(e);
// setConfig(defaultConfig);
// setLoading(false);
return null;
}
};

View File

@@ -1,5 +1,5 @@
// implemetation of https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
export function hash(str: string) {
export function normalizedHash(str: string) {
let hash = 2166136261;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);

View File

@@ -2,8 +2,7 @@ import { BoardType, DeviceDataT } from 'solarxr-protocol';
import { fetch as tauriFetch } from '@tauri-apps/plugin-http';
import { cacheWrap } from './cache';
import semver from 'semver';
import { hash } from './crypto';
import { getUserID } from './user';
import { normalizedHash } from './crypto';
export interface FirmwareRelease {
name: string;
@@ -24,7 +23,7 @@ const todaysRange = (deployData: [number, Date][]): number => {
return maxRange;
};
const checkUserCanUpdate = async (url: string, fwVersion: string) => {
const checkUserCanUpdate = async (uuid: string, url: string, fwVersion: string) => {
const deployDataJson = JSON.parse(
(await cacheWrap(
`firmware-${fwVersion}-deploy`,
@@ -56,12 +55,13 @@ const checkUserCanUpdate = async (url: string, fwVersion: string) => {
const todayUpdateRange = todaysRange(deployData);
if (!todayUpdateRange) return false;
const uniqueUserKey = await getUserID();
// Make it so the hash change every version. Prevent the same user from getting the same delay
return hash(`${uniqueUserKey}-${fwVersion}`) <= todayUpdateRange;
return normalizedHash(`${uuid}-${fwVersion}`) <= todayUpdateRange;
};
export async function fetchCurrentFirmwareRelease(): Promise<FirmwareRelease | null> {
export async function fetchCurrentFirmwareRelease(
uuid: string
): Promise<FirmwareRelease | null> {
const releases: any[] | null = JSON.parse(
(await cacheWrap(
'firmware-releases',
@@ -93,6 +93,7 @@ export async function fetchCurrentFirmwareRelease(): Promise<FirmwareRelease | n
}
const userCanUpdate = await checkUserCanUpdate(
uuid,
deployAsset.browser_download_url,
version
);

View File

@@ -47,7 +47,12 @@ export function useReset(options: UseResetOptions, onReseted?: () => void) {
req.bodyParts = parts;
sendRPCPacket(RpcMessage.ResetRequest, req);
Sentry.metrics.count('reset_click', 1, { attributes: options });
Sentry.metrics.count('reset_click', 1, {
attributes: {
resetType: ResetType[options.type],
group: options.type === ResetType.Mounting ? options.group : undefined,
},
});
};
const onResetFinished = () => {

View File

@@ -10,6 +10,7 @@ import {
} from 'solarxr-protocol';
import { useWebsocketAPI } from './websocket-api';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import * as Sentry from '@sentry/react';
export const trackingchecklistIdtoLabel: Record<TrackingChecklistStepId, string> = {
[TrackingChecklistStepId.UNKNOWN]: '',
@@ -165,6 +166,9 @@ export function provideTrackingChecklist() {
res.stepId = step;
res.ignore = ignore;
sendRPCPacket(RpcMessage.IgnoreTrackingChecklistStepRequest, res);
Sentry.metrics.count(ignore ? 'mute_checklist_step' : 'unmute_checklist_step', 1, {
attributes: { step: TrackingChecklistStepId[step] },
});
};
return {

View File

@@ -1,8 +0,0 @@
import { locale, hostname, platform, version } from '@tauri-apps/plugin-os';
import { hash } from './crypto';
export async function getUserID() {
// FIXME: This does not support android. It currently return the same id for all android users
return hash(`${await hostname()}-${await locale()}-${platform()}-${version()}`);
}

View File

@@ -8,9 +8,9 @@ import {
useNavigationType,
} from 'react-router-dom';
import { DeviceDataT } from 'solarxr-protocol';
import { getUserID } from '@/hooks/user';
export function getSentryOrCompute(enabled = false) {
export function getSentryOrCompute(enabled = false, uuid: string) {
Sentry.setUser({ id: uuid });
// if sentry is already initialized - SKIP
if (enabled && Sentry.isInitialized()) return;
@@ -63,10 +63,6 @@ export function getSentryOrCompute(enabled = false) {
log('Initialized the Sentry client');
}
getUserID().then((id) => {
Sentry.setUser({ id });
});
return newClient;
}

9
pnpm-lock.yaml generated
View File

@@ -161,6 +161,9 @@ importers:
use-double-tap:
specifier: ^1.3.6
version: 1.3.6(react@18.3.1)
uuid:
specifier: ^13.0.0
version: 13.0.0
yup:
specifier: ^1.4.0
version: 1.4.0
@@ -4534,6 +4537,10 @@ packages:
resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
engines: {node: '>= 4'}
uuid@13.0.0:
resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==}
hasBin: true
uuid@9.0.1:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
@@ -9720,6 +9727,8 @@ snapshots:
utility-types@3.11.0: {}
uuid@13.0.0: {}
uuid@9.0.1: {}
vfile-message@4.0.2: