From aa90f6c3b5ed6126a1f967abcaf0bd0c8a0f5680 Mon Sep 17 00:00:00 2001 From: Mahmoud Zalt Date: Tue, 23 Jul 2024 05:26:46 +0200 Subject: [PATCH] integrate error reporting --- package.json | 1 + src/core/AiAssistantEngine.ts | 42 +++++++---- src/core/ErrorReporter.ts | 41 +++++++++++ src/core/config.ts | 2 + yarn.lock | 131 +++++++++++++++++++++++++--------- 5 files changed, 169 insertions(+), 48 deletions(-) create mode 100644 src/core/ErrorReporter.ts diff --git a/package.json b/package.json index 758c8ce..d7359c9 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "dist" ], "dependencies": { + "@sentry/react": "^8.19.0", "howler": "^2.2.4", "react-icons": "^5.0.1", "uuid": "^9.0.1" diff --git a/src/core/AiAssistantEngine.ts b/src/core/AiAssistantEngine.ts index 66e7584..d7777ae 100644 --- a/src/core/AiAssistantEngine.ts +++ b/src/core/AiAssistantEngine.ts @@ -11,6 +11,7 @@ import config from './config'; import { VoiceFunction } from './commonTypes'; import User from './User'; import SpeechRecognizer from './SpeechRecognizer'; +import ErrorReporter from './ErrorReporter'; interface ApiResponse { data: { @@ -99,22 +100,23 @@ class AiAssistantEngine extends EventEmitter { startProcessing = async (): Promise => { Logger.log('F: startProcessing'); - // Lower the volume of any currently playing audio - this.audioPlayer.setVolume(0.15); + let inputUserCommand: string | Blob; - // Reset the assistant before starting processing - this._resetEngine(); + try { + // Lower the volume of any currently playing audio + this.audioPlayer.setVolume(0.15); - this.emitStateChange(EventEmitter.STATE_LISTENING_START); - this.audioPlayer.playStartTone(); + // Reset the assistant before starting processing + this._resetEngine(); - let inputUserCommand: string | Blob; + this.emitStateChange(EventEmitter.STATE_LISTENING_START); + this.audioPlayer.playStartTone(); - try { inputUserCommand = await this._getUserAudioInput(); Logger.log(`Used "User Input Method" = ${this.userInputMethod}`); - } catch (err) { - Logger.error('Error getting user input:', err); + } catch (error) { + Logger.error('Error getting user input:', error); + ErrorReporter.captureException(error); this.emitStateChange(EventEmitter.STATE_IDLE); return; } @@ -124,6 +126,7 @@ class AiAssistantEngine extends EventEmitter { await this._makeApiCall(inputUserCommand); } catch (err) { Logger.error('Error making API request:', err); + ErrorReporter.captureException(err); this.emitStateChange(EventEmitter.STATE_IDLE); } } @@ -140,8 +143,10 @@ class AiAssistantEngine extends EventEmitter { return this.userInputMethod === UserInputMethod.AUDIO_RECORDER ? await this.audioRecorder.startRecording() : await this.speechToText.startListening(); - } catch (err) { - Logger.error(err); + } catch (error) { + Logger.error(error); + ErrorReporter.captureException(error); + if (retries >= 3) { Logger.log( 'Both methods to getUserAudioInput failed. Stopping further attempts.', @@ -227,11 +232,17 @@ class AiAssistantEngine extends EventEmitter { // --------[ Handle the API Response ]-------- - this.makingAPIRequest = false; - const data: ApiResponse = await response.json(); - this._handleApiResponse(data); + try { + const data: ApiResponse = await response.json(); + this._handleApiResponse(data); + } catch (error) { + Logger.error('Error Handling API Response:', error); + ErrorReporter.captureException(error); + } } catch (error) { Logger.error('Error Calling Sista API:', error); + ErrorReporter.captureException(error); + } finally { this.emitStateChange(EventEmitter.STATE_IDLE); this.makingAPIRequest = false; } @@ -382,6 +393,7 @@ class AiAssistantEngine extends EventEmitter { reader.read().then(playChunk); } catch (error) { Logger.error('Error Calling Sista API:', error); + ErrorReporter.captureException(error); this.emitStateChange(EventEmitter.STATE_IDLE); } }; diff --git a/src/core/ErrorReporter.ts b/src/core/ErrorReporter.ts new file mode 100644 index 0000000..dff6323 --- /dev/null +++ b/src/core/ErrorReporter.ts @@ -0,0 +1,41 @@ +// src/core/ErrorReporter.ts + +import * as Sentry from '@sentry/react'; +import config from './config'; + +class ErrorReporter { + constructor() { + Sentry.init({ + dsn: config.sentryDNS, + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration(), + ], + tracePropagationTargets: [ + 'localhost', + new RegExp(`^${config.apiUrl}`), + ], + // TODO: reduce from 0.5 to 0.1 after Sep 2024 + tracesSampleRate: 0.5, // 50% of traces will be captured. Be cautious with a high number in production + replaysSessionSampleRate: 0.5, // 50% of sessions will be replayed + replaysOnErrorSampleRate: 1.0, // 100% of errors will be replayed + }); + } + + captureException(error: unknown) { + if (error instanceof Error) { + Sentry.captureException(error); + } else { + Sentry.captureMessage( + `Non-error exception captured: ${String(error)}`, + ); + } + } + + captureMessage(message: string) { + Sentry.captureMessage(message); + } +} + +const errorReporter = new ErrorReporter(); +export default errorReporter; diff --git a/src/core/config.ts b/src/core/config.ts index 9b95b9c..2c2ddce 100644 --- a/src/core/config.ts +++ b/src/core/config.ts @@ -6,6 +6,8 @@ const config = { 'https://vuic-assets.s3.us-west-1.amazonaws.com/sdk-assets/audio/start.mp3', endSoundFileUrl: 'https://vuic-assets.s3.us-west-1.amazonaws.com/sdk-assets/audio/end.mp3', + sentryDNS: + 'https://8f7451c4c2591e662104bc1df19be784@o4507648657653760.ingest.de.sentry.io/4507648699138128', }; export default config; diff --git a/yarn.lock b/yarn.lock index 2da4589..19d9751 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,88 @@ # yarn lockfile v1 +"@sentry-internal/browser-utils@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.19.0.tgz#7a25111c5c3430c07b881d5fc83d1598af6d5676" + integrity sha512-kM/2KlikKuBR63nFi2q7MGS3V9K9hakjvUknhr/jHZqDVfEuBKmp1ZlHFAdJtglKHHJy07gPj/XqDH7BbYh5yg== + dependencies: + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry-internal/feedback@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.19.0.tgz#7efef695fd4a058b36ef5c98145c4a990bbe877c" + integrity sha512-Jc77H8fEaGcBhERc2U/o7Q8CZHvlZLT9vAlzq0ZZR20v/1vwYcJW1ysKfTuvmw22hCR6ukhFNl6pqJocXFVhvA== + dependencies: + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry-internal/replay-canvas@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.19.0.tgz#4afe06acadf14a709e36efe5ad7da350e3ce0815" + integrity sha512-l4pKJDHrXEctxrK7Xme/+fKToXpGwr/G2t77BzeE1WEw9LwSwADz/hi8HoMdZzuKWriM2BNbz20tpVS84sODxA== + dependencies: + "@sentry-internal/replay" "8.19.0" + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry-internal/replay@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.19.0.tgz#7b290b19d6ba5c0ab742c4c48839cce329129b3f" + integrity sha512-EW9e1J6XbqXUXQST1AfSIzT9O8OwPyeFOkhkn9/gqOQv08TJvQEIBtWJEoJS+XFMEUuB8IqIzVWNVko/DnGt9A== + dependencies: + "@sentry-internal/browser-utils" "8.19.0" + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry/browser@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.19.0.tgz#64551150cda979728297035f9a367ed344c7d586" + integrity sha512-ZC1HxIFm4TIGONyy9MkPG6Dw8IAhzq43t5mq9PqrB1ehuWj8GX6Vk3E26kuc2sydAm4AXbj0562OmvZHsAJpUA== + dependencies: + "@sentry-internal/browser-utils" "8.19.0" + "@sentry-internal/feedback" "8.19.0" + "@sentry-internal/replay" "8.19.0" + "@sentry-internal/replay-canvas" "8.19.0" + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry/core@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.19.0.tgz#427d09ca27557ddc7c1bfa5e810b7f802836e0b4" + integrity sha512-MrgjsZCEjOJgQjIznnDSrLEy7qL+4LVpNieAvr49cV1rzBNSwGmWRnt/puVaPsLyCUgupVx/43BPUHB/HtKNUw== + dependencies: + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + +"@sentry/react@^8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.19.0.tgz#fad9909f25a379778904a6822ce0c44f8ce4b358" + integrity sha512-MzuMy4AEdSuIrBEyp3W7c4+v215+2MiU9ba7Y0KBKcC/Nrf1cGfRFRbjl9OYm/JIuxkaop7kgYs6sPMrVJVlrQ== + dependencies: + "@sentry/browser" "8.19.0" + "@sentry/core" "8.19.0" + "@sentry/types" "8.19.0" + "@sentry/utils" "8.19.0" + hoist-non-react-statics "^3.3.2" + +"@sentry/types@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.19.0.tgz#26a5d56c823c5eabbb7d6f53112da335b6d96dcb" + integrity sha512-52C8X5V7mK2KIxMJt8MV5TxXAFHqrQR1RKm1oPTwKVWm8hKr1ZYJXINymNrWvpAc3oVIKLC/sa9WFYgXQh+YlA== + +"@sentry/utils@8.19.0": + version "8.19.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.19.0.tgz#f22df2a38327b1cff1e04ba7f11fdf1a32d3ba22" + integrity sha512-8dWJJKaUN6Hf92Oxw2TBmHchGua2W3ZmonrZTTwLvl06jcAigbiQD0MGuF5ytZP8PHx860orV+SbTGKFzfU3Pg== + dependencies: + "@sentry/types" "8.19.0" + "@types/howler@^2.2.11": version "2.2.11" resolved "https://registry.npmjs.org/@types/howler/-/howler-2.2.11.tgz" @@ -109,6 +191,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -121,6 +208,13 @@ has-flag@^3.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + howler@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz" @@ -155,18 +249,6 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" @@ -224,25 +306,15 @@ pstree.remy@^1.1.8: resolved "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz" integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== -react-dom@>=16.11.0: - version "18.3.1" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - react-icons@^5.0.1: version "5.1.0" resolved "https://registry.npmjs.org/react-icons/-/react-icons-5.1.0.tgz" integrity sha512-D3zug1270S4hbSlIRJ0CUS97QE1yNNKDjzQe3HqY0aefp2CBn9VgzgES27sRR2gOvFK+0CNx/BW0ggOESp6fqQ== -react@*, react@^18.3.1, react@>=16.11.0: - version "18.3.1" - resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" +react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== readdirp@~3.6.0: version "3.6.0" @@ -251,13 +323,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - semver@^7.5.3: version "7.6.0" resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"