1
0
mirror of https://github.com/MisskeyIO/misskey synced 2024-11-27 06:18:40 +09:00

feat(analytics): デッキUIのページ移動とAPIの応答時間のイベント実装 (MisskeyIO#793)

This commit is contained in:
あわわわとーにゅ 2024-11-07 16:24:13 +09:00 committed by GitHub
parent 9559fbefe0
commit 122ed3c82d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 63 additions and 2 deletions

View File

@ -14,7 +14,7 @@ import { apiUrl } from '@/config.js';
import { waiting, popup, popupMenu, success, alert } from '@/os.js'; import { waiting, popup, popupMenu, success, alert } from '@/os.js';
import { generateClientTransactionId, misskeyApi } from '@/scripts/misskey-api.js'; import { generateClientTransactionId, misskeyApi } from '@/scripts/misskey-api.js';
import { unisonReload, reloadChannel } from '@/scripts/unison-reload.js'; import { unisonReload, reloadChannel } from '@/scripts/unison-reload.js';
import { set as gtagSet } from 'vue-gtag'; import { set as gtagSet, time as gtagTime } from 'vue-gtag';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
@ -53,6 +53,7 @@ export async function signout() {
const registration = await navigator.serviceWorker.ready; const registration = await navigator.serviceWorker.ready;
const push = await registration.pushManager.getSubscription(); const push = await registration.pushManager.getSubscription();
if (push) { if (push) {
const initiateTime = Date.now();
await window.fetch(`${apiUrl}/sw/unregister`, { await window.fetch(`${apiUrl}/sw/unregister`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
@ -63,6 +64,14 @@ export async function signout() {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Client-Transaction-Id': generateClientTransactionId('misskey'), 'X-Client-Transaction-Id': generateClientTransactionId('misskey'),
}, },
}).then(() => {
if (instance.googleAnalyticsId) {
gtagTime({
name: 'api',
event_category: '/sw/unregister',
value: Date.now() - initiateTime,
});
}
}); });
} }
} }
@ -105,6 +114,7 @@ export async function removeAccount(idOrToken: Account['id']) {
function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise<Account> { function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise<Account> {
return new Promise((done, fail) => { return new Promise((done, fail) => {
const initiateTime = Date.now();
window.fetch(`${apiUrl}/i`, { window.fetch(`${apiUrl}/i`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
@ -115,6 +125,16 @@ function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Pr
'X-Client-Transaction-Id': generateClientTransactionId('misskey'), 'X-Client-Transaction-Id': generateClientTransactionId('misskey'),
}, },
}) })
.then(res => {
if (instance.googleAnalyticsId) {
gtagTime({
name: 'api',
event_category: '/i',
value: Date.now() - initiateTime,
});
}
return res;
})
.then(res => new Promise<Account | { error: Record<string, any> }>((done2, fail2) => { .then(res => new Promise<Account | { error: Record<string, any> }>((done2, fail2) => {
if (res.status >= 500 && res.status < 600) { if (res.status >= 500 && res.status < 600) {
// サーバーエラー(5xx)の場合をrejectとする // サーバーエラー(5xx)の場合をrejectとする

View File

@ -270,6 +270,8 @@ export async function common(createVue: () => App<Element>) {
app.use(VueGtag, { app.use(VueGtag, {
bootstrap: false, bootstrap: false,
appName: `Misskey v${version}`, appName: `Misskey v${version}`,
pageTrackerEnabled: true,
pageTrackerScreenviewEnabled: true,
config: { config: {
id: instance.googleAnalyticsId, id: instance.googleAnalyticsId,
params: { params: {

View File

@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue'; import { computed, nextTick, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue';
import RouterView from '@/components/global/RouterView.vue'; import RouterView from '@/components/global/RouterView.vue';
import MkWindow from '@/components/MkWindow.vue'; import MkWindow from '@/components/MkWindow.vue';
import { popout as _popout } from '@/scripts/popout.js'; import { popout as _popout } from '@/scripts/popout.js';
@ -43,6 +43,8 @@ import { claimAchievement } from '@/scripts/achievements.js';
import { getScrollContainer } from '@/scripts/scroll.js'; import { getScrollContainer } from '@/scripts/scroll.js';
import { useRouterFactory } from '@/router/supplier.js'; import { useRouterFactory } from '@/router/supplier.js';
import { mainRouter } from '@/router/main.js'; import { mainRouter } from '@/router/main.js';
import { instance } from '@/instance.js';
import { pageview } from 'vue-gtag';
const props = defineProps<{ const props = defineProps<{
initialPath: string; initialPath: string;
@ -110,6 +112,21 @@ provide('shouldOmitHeaderTitle', true);
provide('shouldHeaderThin', true); provide('shouldHeaderThin', true);
provide('forceSpacerMin', true); provide('forceSpacerMin', true);
if (instance.googleAnalyticsId) {
pageview({
page_title: pageMetadata.value?.title,
page_path: windowRouter.getCurrentPath(),
});
windowRouter.afterEach(() =>
nextTick(() =>
pageview({
page_title: pageMetadata.value?.title,
page_path: windowRouter.getCurrentPath(),
}),
),
);
}
const contextmenu = computed(() => ([{ const contextmenu = computed(() => ([{
icon: 'ti ti-player-eject', icon: 'ti ti-player-eject',
text: i18n.ts.showInPage, text: i18n.ts.showInPage,

View File

@ -8,6 +8,8 @@ import { ref } from 'vue';
import { apiUrl } from '@/config.js'; import { apiUrl } from '@/config.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { time as gtagTime } from 'vue-gtag';
import { instance } from '@/instance.js';
export const pendingApiRequestsCount = ref(0); export const pendingApiRequestsCount = ref(0);
let id: string | null = miLocalStorage.getItem('id'); let id: string | null = miLocalStorage.getItem('id');
@ -66,6 +68,7 @@ export function misskeyApi<
if (token !== undefined) (data as any).i = token; if (token !== undefined) (data as any).i = token;
// Send request // Send request
const initiateTime = Date.now();
window.fetch(`${apiUrl}/${endpoint}`, { window.fetch(`${apiUrl}/${endpoint}`, {
method: 'POST', method: 'POST',
body: JSON.stringify(data), body: JSON.stringify(data),
@ -76,6 +79,15 @@ export function misskeyApi<
'X-Client-Transaction-Id': generateClientTransactionId(initiator), 'X-Client-Transaction-Id': generateClientTransactionId(initiator),
}, },
signal, signal,
}).then(res => {
if (instance.googleAnalyticsId) {
gtagTime({
name: 'api',
event_category: `/${endpoint}`,
value: Date.now() - initiateTime,
});
}
return res;
}).then(handleResponse(resolve, reject)).catch(reject); }).then(handleResponse(resolve, reject)).catch(reject);
}); });
@ -105,6 +117,7 @@ export function misskeyApiGet<
const promise = new Promise<_ResT>((resolve, reject) => { const promise = new Promise<_ResT>((resolve, reject) => {
// Send request // Send request
const initiateTime = Date.now();
window.fetch(`${apiUrl}/${endpoint}?${query}`, { window.fetch(`${apiUrl}/${endpoint}?${query}`, {
method: 'GET', method: 'GET',
credentials: 'omit', credentials: 'omit',
@ -112,6 +125,15 @@ export function misskeyApiGet<
headers: { headers: {
'X-Client-Transaction-Id': generateClientTransactionId(initiator), 'X-Client-Transaction-Id': generateClientTransactionId(initiator),
}, },
}).then(res => {
if (instance.googleAnalyticsId) {
gtagTime({
name: 'api-get',
event_category: `/${endpoint}?${query}`,
value: Date.now() - initiateTime,
});
}
return res;
}).then(handleResponse(resolve, reject)).catch(reject); }).then(handleResponse(resolve, reject)).catch(reject);
}); });