Add optional telemetry

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
Marcel Klehr 2024-05-09 08:47:10 +02:00
parent d439d11815
commit 91133f6c9a
13 changed files with 982 additions and 175 deletions

3
.gitignore vendored
View File

@ -5,3 +5,6 @@ builds
key.pem
.idea
.DS_STORE
# Sentry Config File
.env.sentry-build-plugin

View File

@ -704,5 +704,17 @@
},
"LabelGitbranch": {
"message": "Git branch"
},
"LabelTelemetry": {
"message": "Automated Error Reporting"
},
"DescriptionTelemetry": {
"message": "Floccus can automatically send error data to me, the developer. This is a tremendous help for discovering and resolving bugs in floccus more quickly and will help improve your experience with floccus in the long run. Even when error reporting is enabled, the floccus developers will never be able to see your bookmarks."
},
"LabelTelemetryenable": {
"message": "Automatically send error data to floccus developers"
},
"LabelTelemetrydisable": {
"message": "Do not send error data to floccus developers"
}
}

View File

@ -77,6 +77,22 @@ const icons = function() {
return gulp.src(paths.icons).pipe(gulp.dest('./dist/icons/'))
}
const devjs = function() {
return new Promise((resolve) =>
webpack(devConfig, (err, stats) => {
if (err) console.log('Webpack', err)
console.log(
stats.toString({
/* stats options */
})
)
resolve()
})
)
}
const js = function() {
return new Promise((resolve) =>
webpack(config, (err, stats) => {
@ -214,7 +230,7 @@ exports.js = js
exports.mocha = mocha
exports.watch = watch
exports.release = release
exports.watch = gulp.series(main, watch)
exports.watch = gulp.series(gulp.parallel(assets, devjs), native, watch)
exports.publish = publish
exports.build = build
exports.native = native

View File

@ -1,5 +1,5 @@
{
"manifest_version": 3,
"manifest_version": 2,
"name": "floccus bookmarks sync",
"short_name": "floccus",
"version": "5.1.0",
@ -10,23 +10,27 @@
"128": "icons/logo_128.png"
},
"applications": {
"gecko": {
"id": "floccus@handmadeideas.org",
"strict_min_version": "57.0"
}
},
"default_locale": "en",
"permissions": ["alarms", "bookmarks", "storage", "unlimitedStorage", "tabs", "identity"],
"host_permissions": [
"*://*/*"
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self';"
},
"permissions": ["*://*/*", "alarms", "bookmarks", "storage", "unlimitedStorage", "tabs", "identity"],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';",
"options_ui": {
"page": "dist/html/options.html",
"browser_style": false
"browser_style": false,
"chrome_style": false
},
"action": {
"browser_action": {
"browser_style": false,
"chrome_style": false,
"default_icon": {
"48": "icons/logo.png"
},
@ -35,6 +39,6 @@
},
"background": {
"service_worker": "dist/js/background-script.js"
"page": "dist/html/background.html"
}
}

922
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,8 @@
"@capacitor/share": "^5.0.0",
"@capacitor/splash-screen": "^5.0.0",
"@isomorphic-git/lightning-fs": "^4.6.0",
"@sentry/vue": "^7.113.0",
"@sentry/webpack-plugin": "^2.16.1",
"async-lock": "^1.2.8",
"async-parallel": "^1.2.3",
"batching-toposort": "^1.2.0",

View File

@ -1,3 +1,4 @@
/* global DEBUG */
import AdapterFactory from './AdapterFactory'
import Logger from './Logger'
import { Folder, ItemLocation, TItemLocation } from './Tree'
@ -12,6 +13,7 @@ import IAccount from './interfaces/Account'
import Mappings from './Mappings'
import { isTest } from './isTest'
import CachingAdapter from './adapters/Caching'
import * as Sentry from '@sentry/vue'
// register Adapters
AdapterFactory.register('nextcloud-folders', async() => (await import('./adapters/NextcloudBookmarks')).default)
@ -148,6 +150,7 @@ export default class Account {
if (!(await this.server.isAvailable()) || !(await localResource.isAvailable())) return
Logger.log('Starting sync process for account ' + this.getLabel())
Sentry.setUser({ id: this.id })
this.syncing = true
await this.setData({ ...this.getData(), syncing: 0.05, scheduled: false, error: null })
@ -163,6 +166,7 @@ export default class Account {
} catch (e) {
// Resource locked
if (e.code === 37) {
Sentry.captureException(e)
// We got a resource locked error
if (this.getData().lastSync < Date.now() - LOCK_TIMEOUT) {
// but if we've been waiting for the lock for more than 2h
@ -310,6 +314,25 @@ export default class Account {
const message = await Account.stringifyError(e)
console.error('Syncing failed with', message)
Logger.log('Syncing failed with', message)
// send error to sentry
const logData = await Logger.anonymizeLogs(Logger.messages)
Sentry.setContext('accountData', {
...this.getData(),
username: 'SENSITIVEVALUEHIDDEN',
password: 'SENSITIVEVALUVALUEHIDDEN',
passphrase: 'SENSITIVEVALUVALUEHIDDEN'
})
if (!(window || self)['DEBUG']) {
Sentry.getCurrentScope().addAttachment({
filename: 'floccus-log.txt',
data: logData.slice(-200000).join('\n'),
})
}
if (e.list) {
Sentry.captureException(message)
} else {
Sentry.captureException(e)
}
await this.setData({
...this.getData(),

View File

@ -8,6 +8,7 @@ import BrowserAccountStorage from './BrowserAccountStorage'
import uniqBy from 'lodash/uniqBy'
import Account from '../Account'
import { STATUS_ALLGOOD, STATUS_DISABLED, STATUS_ERROR, STATUS_SYNCING } from '../interfaces/Controller'
import * as Sentry from '@sentry/browser'
const INACTIVITY_TIMEOUT = 7 * 1000 // 7 seconds
const DEFAULT_SYNC_INTERVAL = 15 // 15 minutes
@ -379,5 +380,17 @@ export default class BrowserController {
}
})
)
browser.storage.local.get('telemetryEnabled').then(async d => {
if (!d.telemetryEnabled) {
return
}
Sentry.init({
dsn: 'https://836f0f772fbf2e12b9dd651b8e6b6338@o4507214911307776.ingest.de.sentry.io/4507216408870992',
integrations: [],
release: packageJson.version,
debug: true,
})
})
}
}

View File

@ -33,6 +33,21 @@
</template>
<span>{{ t('LabelFunddevelopment') }}</span>
</v-tooltip>
<v-tooltip top>
<template #activator="{ on, attrs }">
<v-btn
x-small
text
class="white--text"
v-bind="attrs"
:to="{name: routes.TELEMETRY}"
target="_blank"
v-on="on">
<v-icon>{{ telemetryEnabled ? 'mdi-bug-play-outline' : 'mdi-bug-pause-outline' }}</v-icon>
</v-btn>
</template>
<span>{{ t('LabelTelemetry') }}</span>
</v-tooltip>
</v-col>
</v-row>
</v-footer>
@ -74,6 +89,7 @@ import { version as VERSION } from '../../package.json'
import { actions } from './store'
import { routes } from './router'
import Controller from '../lib/Controller'
import browser from '../lib/browser-api'
export default {
name: 'App',
data() {
@ -81,6 +97,7 @@ export default {
VERSION,
key: '',
unlockError: null,
telemetryEnabled: false,
}
},
computed: {
@ -109,6 +126,8 @@ export default {
window.addEventListener('beforeunload', unregister)
window.addEventListener('unload', unregister)
window.addEventListener('close', unregister)
const {telemetryEnabled} = await browser.storage.local.get({'telemetryEnabled': false})
this.telemetryEnabled = telemetryEnabled
},
methods: {
async onUnlock() {

View File

@ -6,6 +6,7 @@ import Update from './views/Update'
import ImportExport from './views/ImportExport'
import Donate from './views/Donate'
import About from './views/native/About'
import Telemetry from './views/Telemetry.vue'
Vue.use(Router)
@ -18,6 +19,8 @@ export const routes = {
UPDATE: 'UPDATE',
IMPORTEXPORT: 'IMPORTEXPORT',
DONATE: 'DONATE',
TELEMETRY: 'TELEMETRY',
}
export const router = new Router({
@ -59,5 +62,10 @@ export const router = new Router({
name: routes.DONATE,
component: Donate,
},
{
path: '/telemetry',
name: routes.TELEMETRY,
component: Telemetry,
},
],
})

View File

@ -0,0 +1,63 @@
<template>
<v-container>
<v-card
class="options mt-3">
<v-container class="pa-5">
<v-card-title>
{{ t("LabelTelemetry") }}
</v-card-title>
<v-card-text>
<div class="body-1">
{{ t("DescriptionTelemetry") }}
</div>
<v-radio-group v-model="telemetry" class="mt-4">
<v-radio :value="true">
<template #label>
<div class="heading">
{{ t("LabelTelemetryenable") }}
</div>
</template>
</v-radio>
<v-radio :value="false">
<template #label>
<div class="heading">
{{ t("LabelTelemetrydisable") }}
</div>
</template>
</v-radio>
</v-radio-group>
</v-card-text>
</v-container>
</v-card>
</v-container>
</template>
<script>
import browser from '../../lib/browser-api'
export default {
name: 'Telemetry',
components: {},
data() {
return {
telemetry: false,
}
},
watch: {
telemetry(enabled) {
browser.storage.local.set({'telemetryEnabled': enabled})
},
},
async created() {
const {telemetryEnabled} = await browser.storage.local.get({'telemetryEnabled': false})
this.telemetry = telemetryEnabled
},
}
</script>
<style scoped>
.options {
max-width: 600px;
margin: 0 auto;
}
</style>

View File

@ -17,6 +17,30 @@
{{ t('LabelReleaseNotes') }}
</v-btn>
</v-card-text>
<v-card-title>
{{ t("LabelTelemetry") }}
</v-card-title>
<v-card-text>
<div class="body-1">
{{ t("DescriptionTelemetry") }}
</div>
<v-radio-group v-model="telemetry" class="mt-4">
<v-radio :value="true">
<template #label>
<div class="heading">
{{ t("LabelTelemetryenable") }}
</div>
</template>
</v-radio>
<v-radio :value="false">
<template #label>
<div class="heading">
{{ t("LabelTelemetrydisable") }}
</div>
</template>
</v-radio>
</v-radio-group>
</v-card-text>
<v-card-title>
{{ t("LabelFunddevelopment") }}
</v-card-title>
@ -59,12 +83,14 @@
<script>
import {version as VERSION} from '../../../package.json'
import { routes } from '../NativeRouter'
import browser from '../../lib/browser-api'
export default {
name: 'Update',
components: {},
data() {
return {
telemetry: false,
paymentOptions: [
{
href: 'https://www.paypal.me/marcelklehr1',
@ -107,8 +133,15 @@ export default {
return routes
}
},
methods: {
}
watch: {
telemetry(enabled) {
browser.storage.local.set({'telemetryEnabled': enabled})
}
},
async created() {
const {telemetryEnabled} = await browser.storage.local.get({'telemetryEnabled': false})
this.telemetry = telemetryEnabled
},
}
</script>

View File

@ -1,12 +1,21 @@
const {
sentryWebpackPlugin
} = require("@sentry/webpack-plugin")
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
const webpack = require('webpack')
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
plugins: [
new webpack.DefinePlugin({
DEBUG: JSON.stringify(!process.env['CI'])
})
}),
sentryWebpackPlugin({
authToken: process.env.SENTRY_AUTH_TOKEN,
org: "marcel-klehr",
project: "floccus"
}),
]
})