Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(simulator): integrate Sentry error tracking (#4962) #391

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CURRENT_UID=1000
CURRENT_GID=1000
OPERATING_SYSTEM=windows
NON_ROOT_USERNAME=circuitverse
NON_ROOT_GROUPNAME=circuitverse
SENTRY_DSN=https://20a3411a988862503af74d4d8e7ec450@o4508321713684480.ingest.us.sentry.io/4508321717747712
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Sentry Configuration
SENTRY_AUTH_TOKEN=
VITE_SENTRY_DSN=

# Environment
NODE_ENV=development
1,016 changes: 910 additions & 106 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.1",
"@mdi/font": "5.9.55",
"@sentry/tracing": "^8.40.0",
"@sentry/vue": "^8.40.0",
"@tiptap/core": "^2.0.3",
"@tiptap/extension-character-count": "^2.0.3",
"@tiptap/extension-subscript": "^2.0.3",
Expand Down Expand Up @@ -44,6 +46,8 @@
"@commitlint/cli": "^17.0.2",
"@commitlint/config-conventional": "^17.0.2",
"@intlify/vite-plugin-vue-i18n": "^3.4.0",
"@sentry/cli": "^2.39.0",
"@sentry/vite-plugin": "^2.22.6",
"@types/jquery": "^3.5.14",
"@types/webfontloader": "^1.0.0",
"@vitejs/plugin-vue": "^2.3.3",
Expand Down
5 changes: 5 additions & 0 deletions sentry.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defaults.url=https://sentry.io/
defaults.org=circuitverse
defaults.project=javascript-vue
auth.token=${SENTRY_AUTH_TOKEN}
cli.executable=node_modules/@sentry/cli/bin/sentry-cli
32 changes: 29 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import router from './router/index'
import { createPinia } from 'pinia'
import { loadFonts } from './plugins/webfontloader'
import i18n from './locales/i18n'

import * as Sentry from "@sentry/vue"
import 'bootstrap'

import './globalVariables'

import './styles/css/main.stylesheet.css'
import '../node_modules/bootstrap/scss/bootstrap.scss'
import './styles/color_theme.scss'
Expand All @@ -20,9 +19,36 @@ import '@fortawesome/fontawesome-free/css/all.css'
loadFonts()

const app = createApp(App)
const isProd = import.meta.env.MODE === 'production'

Sentry.init({
app,
dsn: "https://20a3411a988862503af74d4d8e7ec450@o4508321713684480.ingest.us.sentry.io/4508321717747712",
AdityaP700 marked this conversation as resolved.
Show resolved Hide resolved
integrations: [],
tracesSampleRate: isProd ? 0.2 : 1.0,
replaysSessionSampleRate: isProd ? 0.1 : 1.0,
replaysOnErrorSampleRate: 1.0,
trackComponents: true,
attachProps: true,
logErrors: true,
environment: import.meta.env.MODE,
release: import.meta.env.VITE_APP_VERSION || '1.0.0',
beforeSend(event) {
if (!isProd) {
console.error('Sentry error:', event);
return null;
}
return event;
},
tracingOptions: {
trackComponents: true,
timeout: 2000,
hooks: ['mount', 'update'],
},
});

app.use(createPinia())
app.use(vuetify)
app.use(router)
app.use(i18n)
app.mount('#app')
app.mount('#app')
45 changes: 31 additions & 14 deletions src/pages/simulator.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
<template>
<Navbar />
<ContextMenu />
<Extra />
<Helper />
<div id="simulatorContainer">
<Navbar />
<ContextMenu />
<Extra />
<Helper />
<canvas
id="simulationArea"
ref="simulationCanvas"
class="simulation-canvas"
></canvas>
</div>
</template>

<script setup lang="ts">
import Navbar from '@/Navbar/Navbar.vue'
import ContextMenu from '@/ContextMenu/ContextMenu.vue'
import Extra from '@/Extra.vue'
import { defineComponent, onMounted } from 'vue'
import { defineComponent, onMounted, nextTick, ref } from 'vue'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused defineComponent import

The defineComponent import is not needed when using <script setup> syntax.

-import { defineComponent, onMounted, nextTick, ref } from 'vue'
+import { onMounted, nextTick, ref } from 'vue'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { defineComponent, onMounted, nextTick, ref } from 'vue'
import { onMounted, nextTick, ref } from 'vue'
🧰 Tools
🪛 eslint

[error] 19-19: 'defineComponent' is defined but never used.

(no-unused-vars)

import { setup as setupSimulator } from '../simulator/src/setup'
import Helper from '#/components/helpers/Helper.vue'

defineComponent({
components: {
Navbar,
ContextMenu,
Extra,
},
})
const simulationCanvas = ref<HTMLCanvasElement | null>(null)

onMounted(() => {
setupSimulator()
onMounted(async () => {
await nextTick()
if (simulationCanvas.value) {
const ctx = simulationCanvas.value.getContext('2d')
if (ctx) {
setupSimulator()
}
}
Comment on lines +25 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add error handling for canvas initialization with Sentry tracking

The canvas initialization code needs error handling as Sentry is available but not utilized. Add try-catch blocks around the canvas operations:

  • src/pages/simulator.vue: Add error handling for both canvas context acquisition and simulator setup:
onMounted(async () => {
    await nextTick()
    try {
        if (!simulationCanvas.value) {
            throw new Error('Canvas element not found');
        }
        const ctx = simulationCanvas.value.getContext('2d')
        if (!ctx) {
            throw new Error('Failed to get canvas context');
        }
        setupSimulator()
    } catch (error) {
        Sentry.captureException(error);
        // Handle UI feedback here
    }
})
🔗 Analysis chain

Verify Sentry error capture for canvas initialization failures

Since this is part of the Sentry integration PR, let's verify that initialization failures are properly captured.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if Sentry initialization and error handling are properly set up

# Look for Sentry.captureException or similar error handling
rg -l "Sentry\.(captureException|captureError)" 

# Check for any existing error boundary components
fd -e vue -e ts "ErrorBoundary"

# Look for other canvas initialization error handling
ast-grep --pattern 'catch (error) {
  $$$
}'

Length of output: 128


Script:

#!/bin/bash
# Let's check for Sentry initialization and error handling with broader patterns

# Check for Sentry imports and setup
rg -l "import.*Sentry" 

# Look for any error handling patterns in simulator.vue
rg -A 5 "catch|error" src/pages/simulator.vue

# Check for any try-catch blocks around canvas operations
rg -A 5 "getContext|setupSimulator" src/pages/simulator.vue

# Look for any error tracking or monitoring setup
rg -l "errorHandler|captureError|reportError"

Length of output: 540


Script:

#!/bin/bash
# Let's check the Sentry setup in main.ts and look for any error handling in the simulator setup

# Check Sentry initialization in main.ts
rg -A 5 "import.*Sentry" src/main.ts

# Look into simulator setup implementation
rg -A 10 "export.*setup" src/simulator/src/setup.ts

# Check for any error handling in the simulator module
rg "try|catch|throw" src/simulator/src/

Length of output: 3061

})
</script>

<style scoped>
.simulation-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
54 changes: 28 additions & 26 deletions src/simulator/src/simulationArea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SimulationArea } from './interface/simulationArea'
import { clockTick } from './utils'

const simulationArea: SimulationArea = {
canvas: document.getElementById('simulationArea') as HTMLCanvasElement,
canvas: null,
context: null,
selected: false,
hover: false,
Expand All @@ -29,42 +29,44 @@ const simulationArea: SimulationArea = {
mouseDownX: 0,
mouseDownY: 0,
simulationQueue: new EventQueue(10000),
clickCount: 0,
lock: 'unlocked',
mouseDown: false,
ClockInterval: null,
touch: false,

timer() {
const clickTimer = setTimeout(() => {
simulationArea.clickCount = 0
}, 600)
if (this.clockEnabled) {
clockTick();
}
setTimeout(() => this.timer(), this.timePeriod);
},

setup() {
this.canvas = document.getElementById('simulationArea') as HTMLCanvasElement;
this.canvas.width = width;
this.canvas.height = height;
this.simulationQueue = new EventQueue(10000);
this.context = this.canvas.getContext('2d')!;
simulationArea.changeClockTime(simulationArea.timePeriod);
this.mouseDown = false;
},
changeClockTime(t: number) {
if (t < 50) {
if (!this.canvas) {
console.error('Simulation canvas not found');
return;
}
if (simulationArea.ClockInterval != null) {
clearInterval(simulationArea.ClockInterval);
}
simulationArea.timePeriod = t;
simulationArea.ClockInterval = setInterval(clockTick, t);
},
clear() {

this.context = this.canvas.getContext('2d');
if (!this.context) {
console.error('Could not get 2D context');
return;
}
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.timer();
AdityaP700 marked this conversation as resolved.
Show resolved Hide resolved
},

changeClockTime(t: number) {
if (t < 50) return;
this.timePeriod = t;
this.clockEnabled = true;
},

clear() {
if (this.context && this.canvas) {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
};

export { simulationArea }
export const { changeClockTime } = simulationArea
10 changes: 10 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'
import vueI18n from '@intlify/vite-plugin-vue-i18n'
import { sentryVitePlugin } from "@sentry/vite-plugin"

// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
import vuetify from 'vite-plugin-vuetify'
Expand All @@ -23,6 +24,14 @@ export default defineConfig(() => ({
new URL('./src/locales/**', import.meta.url)
),
}),
sentryVitePlugin({
org: "circuitverse",
project: "javascript-vue",
authToken: process.env.SENTRY_AUTH_TOKEN,
enabled: process.env.NODE_ENV === 'production',
telemetry: false,
debug: process.env.NODE_ENV === 'development'
}),
AdityaP700 marked this conversation as resolved.
Show resolved Hide resolved
],
resolve: {
alias: {
Expand All @@ -35,6 +44,7 @@ export default defineConfig(() => ({
outDir: '../public/simulatorvue',
assetsDir: 'assets',
chunkSizeWarningLimit: 1600,
sourcemap: process.env.NODE_ENV === 'development', // Enable source maps only in development
},
test:{
globals: true,
Expand Down