feat: add monitoring

This commit is contained in:
Leafd 2025-10-08 19:05:44 -04:00 committed by Leafd
parent 5bf8fa1f32
commit ad2b79367c
4 changed files with 118 additions and 7 deletions

View file

@ -153,7 +153,11 @@ onMounted(async () => {
}
});
// Check for updates automatically on startup
if (authState.value.is_authenticated) {
await loadPresenceData();
startPresenceRefresh();
}
checkForUpdatesAndInstall();
});
@ -292,24 +296,22 @@ async function loadHackatimeInfo() {
}
async function loadPresenceData() {
const now = Date.now();
if (presenceFetchInProgress.value) {
return;
}
const now = Date.now();
if (now < nextPresenceFetchAllowedAt.value) {
return;
}
if (now - lastPresenceFetchAt.value < 60_000) {
return;
}
presenceFetchInProgress.value = true;
try {
await api.initialize();
presenceData.value = await invoke("get_latest_heartbeat", {
apiConfig: apiConfig.value
});
lastPresenceFetchAt.value = Date.now();
console.log("Heartbeat data fetched from backend:", presenceData.value);
} catch (error: any) {
console.error("Failed to load presence data:", error);
const message = error?.message || "";
@ -328,6 +330,7 @@ function startPresenceRefresh() {
presenceRefreshInterval.value = null;
}
presenceRefreshInterval.value = setInterval(loadPresenceData, 60000);
console.log("Started heartbeat refresh interval (every 60 seconds)");
}
function stopPresenceRefresh() {

View file

@ -0,0 +1,70 @@
import posthog from 'posthog-js'
export function usePostHog() {
posthog.init('phc_xwC3ygQBfstlwaJ3i1lRtz6bON6CR5lHFz7UhlSW6SZ', {
api_host: 'https://at.leafd.dev',
ui_host: 'https://at.leafd.dev',
person_profiles: 'identified_only',
session_recording: {
maskAllInputs: true,
maskInputOptions: {
password: true,
email: true,
},
maskTextSelector: '*',
maskTextFn: (text, element) => {
if (text.trim().length === 0) {
return text
}
if (element?.dataset?.['record'] === 'true') {
return text
}
const emailRegex = /(\S+)@(\S+\.\S+)/g
if (emailRegex.test(text)) {
return text.replace(emailRegex, (_match, g1, g2) => {
return '*'.repeat(g1.length) + '@' + '*'.repeat(g2.length)
})
}
const tokenRegex = /[a-zA-Z0-9_-]{20,}/g
if (tokenRegex.test(text)) {
return text.replace(tokenRegex, (match) => '*'.repeat(match.length))
}
return text
},
maskInputFn: (text, element) => {
const passwordRelated = ['password', 'pwd', 'pass']
const elementId = (element?.attributes?.['id' as any]?.value as string)?.toLowerCase() || ''
const elementName = (element?.attributes?.['name' as any]?.value as string)?.toLowerCase() || ''
if (
passwordRelated.some(p => elementId.includes(p) || elementName.includes(p))
) {
return '*'.repeat(text.length)
}
if (element?.attributes?.['type' as any]?.value === 'search') {
return text
}
return '*'.repeat(text.length)
},
},
})
return { posthog }
}

View file

@ -0,0 +1,13 @@
import { inject } from 'vue'
import type { PostHog } from 'posthog-js'
export function usePostHogInstance() {
const posthog = inject<PostHog>('posthog')
if (!posthog) {
throw new Error('PostHog is not initialized')
}
return posthog
}

View file

@ -1,5 +1,30 @@
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'
import * as Sentry from '@sentry/vue'
import { usePostHog } from './composables/usePostHog'
createApp(App).mount('#app')
const app = createApp(App)
const { posthog } = usePostHog()
app.provide('posthog', posthog)
Sentry.init({
app,
dsn: "https://d67e5cceba1b80139ca09c806efc616a@o4509680631087104.ingest.us.sentry.io/4510156240060417",
sendDefaultPii: true,
integrations: [
Sentry.browserTracingIntegration()
],
tracesSampleRate: 1.0,
tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
enableLogs: true
})
app.mount('#app')