From b3a198cae64b422706d3fc7d1049bb2cb0b79f29 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 8 Jan 2021 21:43:56 +0900 Subject: Sentry integration --- src/client/init.ts | 16 ++++++++++++- src/client/os.ts | 27 +++++++++++++++++----- .../pages/settings/experimental-features.vue | 8 ++++++- src/client/pages/settings/other.vue | 7 ++++++ src/client/store.ts | 4 ++++ 5 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src/client') diff --git a/src/client/init.ts b/src/client/init.ts index 7c3df68c34..f39f50eea6 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -36,13 +36,15 @@ if (localStorage.getItem('vuex') != null) { location.reload(); } +import * as Sentry from '@sentry/browser'; +import { Integrations } from '@sentry/tracing'; import { createApp, watch } from 'vue'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import widgets from '@/widgets'; import directives from '@/directives'; import components from '@/components'; -import { version, ui, lang } from '@/config'; +import { version, ui, lang, host } from '@/config'; import { router } from '@/router'; import { applyTheme } from '@/scripts/theme'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; @@ -88,6 +90,18 @@ if (_DEV_) { }); } +if (defaultStore.state.reportError && !_DEV_) { + Sentry.init({ + dsn: 'https://fd273254a07a4b61857607a9ea05d629@o501808.ingest.sentry.io/5583438', + tracesSampleRate: 1.0, + }); + + Sentry.setTag('misskey_version', version); + Sentry.setTag('ui', ui); + Sentry.setTag('lang', lang); + Sentry.setTag('host', host); +} + // タッチデバイスでCSSの:hoverを機能させる document.addEventListener('touchend', () => {}, { passive: true }); diff --git a/src/client/os.ts b/src/client/os.ts index f7d870cfdd..95dcd3eb65 100644 --- a/src/client/os.ts +++ b/src/client/os.ts @@ -1,11 +1,13 @@ import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vue'; import { EventEmitter } from 'eventemitter3'; +import * as Sentry from '@sentry/browser'; import Stream from '@/scripts/stream'; import { apiUrl, debug } from '@/config'; import MkPostFormDialog from '@/components/post-form-dialog.vue'; import MkWaitingDialog from '@/components/waiting-dialog.vue'; import { resolve } from '@/router'; -import { $i } from './account'; +import { $i } from '@/account'; +import { defaultStore } from '@/store'; const ua = navigator.userAgent.toLowerCase(); export const isMobile = /mobile|iphone|ipad|android/.test(ua); @@ -54,19 +56,32 @@ export function api(endpoint: string, data: Record = {}, token?: st if (res.status === 200) { resolve(body); if (debug) { - log.res = markRaw(body); - log.state = 'success'; + log!.res = markRaw(body); + log!.state = 'success'; } } else if (res.status === 204) { resolve(); if (debug) { - log.state = 'success'; + log!.state = 'success'; } } else { reject(body.error); if (debug) { - log.res = markRaw(body.error); - log.state = 'failed'; + log!.res = markRaw(body.error); + log!.state = 'failed'; + } + + if (defaultStore.state.reportError && !_DEV_) { + Sentry.withScope((scope) => { + scope.setTag('api_endpoint', endpoint); + scope.setContext('api params', data); + scope.setContext('api error info', body.info); + scope.setTag('api_error_id', body.id); + scope.setTag('api_error_code', body.code); + scope.setTag('api_error_kind', body.kind); + scope.setLevel(Sentry.Severity.Error); + Sentry.captureMessage('API error'); + }); } } }).catch(reject); diff --git a/src/client/pages/settings/experimental-features.vue b/src/client/pages/settings/experimental-features.vue index 01692154ea..39f1683af5 100644 --- a/src/client/pages/settings/experimental-features.vue +++ b/src/client/pages/settings/experimental-features.vue @@ -1,6 +1,6 @@ @@ -42,5 +42,11 @@ export default defineComponent({ mounted() { this.$emit('info', this.INFO); }, + + methods: { + error() { + throw new Error('Test error'); + } + } }); diff --git a/src/client/pages/settings/other.vue b/src/client/pages/settings/other.vue index 1f7c8f7df0..67edaf3faa 100644 --- a/src/client/pages/settings/other.vue +++ b/src/client/pages/settings/other.vue @@ -4,6 +4,8 @@ {{ $ts.showFeaturedNotesInTimeline }} + {{ $ts.sendErrorReports }} + {{ $ts.accountInfo }} {{ $ts.experimentalFeatures }} @@ -31,6 +33,7 @@ import FormGroup from '@/components/form/group.vue'; import FormButton from '@/components/form/button.vue'; import * as os from '@/os'; import { debug } from '@/config'; +import { defaultStore } from '@/store'; export default defineComponent({ components: { @@ -54,6 +57,10 @@ export default defineComponent({ } }, + computed: { + reportError: defaultStore.makeGetterSetter('reportError'), + }, + mounted() { this.$emit('info', this.INFO); }, diff --git a/src/client/store.ts b/src/client/store.ts index 2f134d8f48..f4f6091941 100644 --- a/src/client/store.ts +++ b/src/client/store.ts @@ -184,6 +184,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: true }, + reportError: { + where: 'device', + default: false + }, })); // TODO: 他のタブと永続化されたstateを同期 -- cgit v1.2.3-freya