chore: add performance logger (#4896)

Add more performance log to debug loading problem
This commit is contained in:
LongYinan
2023-11-10 00:42:30 +08:00
committed by GitHub
10 changed files with 79 additions and 3 deletions

View File

@@ -58,4 +58,9 @@ export class DebugLogger {
this._debug.log = console[level].bind(console); this._debug.log = console[level].bind(console);
this._debug(`[${level.toUpperCase()}] ${message}`, ...args); this._debug(`[${level.toUpperCase()}] ${message}`, ...args);
} }
namespace(extra: string) {
const currentNamespace = this._debug.namespace;
return new DebugLogger(`${currentNamespace}:${extra}`);
}
} }

View File

@@ -14,8 +14,10 @@ import { RouterProvider } from 'react-router-dom';
import { CloudSessionProvider } from './providers/session-provider'; import { CloudSessionProvider } from './providers/session-provider';
import { router } from './router'; import { router } from './router';
import { performanceLogger, performanceRenderLogger } from './shared';
import createEmotionCache from './utils/create-emotion-cache'; import createEmotionCache from './utils/create-emotion-cache';
const performanceI18nLogger = performanceLogger.namespace('i18n');
const cache = createEmotionCache(); const cache = createEmotionCache();
const DevTools = lazy(() => const DevTools = lazy(() =>
@@ -37,16 +39,23 @@ const future = {
async function loadLanguage() { async function loadLanguage() {
if (environment.isBrowser) { if (environment.isBrowser) {
performanceI18nLogger.info('start');
const { createI18n, setUpLanguage } = await import('@affine/i18n'); const { createI18n, setUpLanguage } = await import('@affine/i18n');
const i18n = createI18n(); const i18n = createI18n();
document.documentElement.lang = i18n.language; document.documentElement.lang = i18n.language;
performanceI18nLogger.info('set up');
await setUpLanguage(i18n); await setUpLanguage(i18n);
performanceI18nLogger.info('done');
} }
} }
const languageLoadingPromise = loadLanguage().catch(console.error); const languageLoadingPromise = loadLanguage().catch(console.error);
export const App = memo(function App() { export const App = memo(function App() {
performanceRenderLogger.info('App');
use(languageLoadingPromise); use(languageLoadingPromise);
return ( return (
<CacheProvider value={cache}> <CacheProvider value={cache}>

View File

@@ -23,6 +23,9 @@ import { nanoid } from 'nanoid';
import { applyUpdate, Doc as YDoc, encodeStateAsUpdate } from 'yjs'; import { applyUpdate, Doc as YDoc, encodeStateAsUpdate } from 'yjs';
import { WorkspaceAdapters } from '../adapters/workspace'; import { WorkspaceAdapters } from '../adapters/workspace';
import { performanceLogger } from '../shared';
const performanceSetupLogger = performanceLogger.namespace('setup');
async function tryMigration() { async function tryMigration() {
const value = localStorage.getItem('jotai-workspaces'); const value = localStorage.getItem('jotai-workspaces');
@@ -148,6 +151,7 @@ export function createFirstAppData(store: ReturnType<typeof createStore>) {
} }
export async function setup(store: ReturnType<typeof createStore>) { export async function setup(store: ReturnType<typeof createStore>) {
performanceSetupLogger.info('start');
store.set( store.set(
workspaceAdaptersAtom, workspaceAdaptersAtom,
WorkspaceAdapters as Record< WorkspaceAdapters as Record<
@@ -156,11 +160,15 @@ export async function setup(store: ReturnType<typeof createStore>) {
> >
); );
console.log('setup global'); performanceSetupLogger.info('setup global');
setupGlobal(); setupGlobal();
performanceSetupLogger.info('try migration');
await tryMigration(); await tryMigration();
performanceSetupLogger.info('get root workspace meta');
// do not read `rootWorkspacesMetadataAtom` before migration // do not read `rootWorkspacesMetadataAtom` before migration
await store.get(rootWorkspacesMetadataAtom); await store.get(rootWorkspacesMetadataAtom);
console.log('setup done');
performanceSetupLogger.info('done');
} }

View File

@@ -5,18 +5,28 @@ import { StrictMode, Suspense } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import { bootstrapPluginSystem } from './bootstrap/register-plugins'; import { bootstrapPluginSystem } from './bootstrap/register-plugins';
import { performanceLogger } from './shared';
const performanceMainLogger = performanceLogger.namespace('main');
async function main() { async function main() {
performanceMainLogger.info('start');
const { setup } = await import('./bootstrap/setup'); const { setup } = await import('./bootstrap/setup');
const rootStore = getCurrentStore(); const rootStore = getCurrentStore();
performanceMainLogger.info('setup start');
await setup(rootStore); await setup(rootStore);
performanceMainLogger.info('setup done');
bootstrapPluginSystem(rootStore).catch(err => { bootstrapPluginSystem(rootStore).catch(err => {
console.error('Failed to bootstrap plugin system', err); console.error('Failed to bootstrap plugin system', err);
}); });
performanceMainLogger.info('import app');
const { App } = await import('./app'); const { App } = await import('./app');
const root = document.getElementById('app'); const root = document.getElementById('app');
assertExists(root); assertExists(root);
performanceMainLogger.info('render app');
createRoot(root).render( createRoot(root).render(
<StrictMode> <StrictMode>
<Suspense fallback={<WorkspaceFallback key="AppLoading" />}> <Suspense fallback={<WorkspaceFallback key="AppLoading" />}>

View File

@@ -40,6 +40,7 @@ import { WorkspaceHeader } from '../../components/workspace-header';
import { useBlockSuiteMetaHelper } from '../../hooks/affine/use-block-suite-meta-helper'; import { useBlockSuiteMetaHelper } from '../../hooks/affine/use-block-suite-meta-helper';
import { useTrashModalHelper } from '../../hooks/affine/use-trash-modal-helper'; import { useTrashModalHelper } from '../../hooks/affine/use-trash-modal-helper';
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace'; import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
import { performanceRenderLogger } from '../../shared';
import * as styles from './all-page.css'; import * as styles from './all-page.css';
import { EmptyPageList } from './page-list-empty'; import { EmptyPageList } from './page-list-empty';
import { useFilteredPageMetas } from './pages'; import { useFilteredPageMetas } from './pages';
@@ -302,5 +303,7 @@ export const AllPage = () => {
}; };
export const Component = () => { export const Component = () => {
performanceRenderLogger.info('AllPage');
return <AllPage />; return <AllPage />;
}; };

View File

@@ -29,6 +29,7 @@ import { WorkspaceHeader } from '../../components/workspace-header';
import { useRegisterBlocksuiteEditorCommands } from '../../hooks/affine/use-register-blocksuite-editor-commands'; import { useRegisterBlocksuiteEditorCommands } from '../../hooks/affine/use-register-blocksuite-editor-commands';
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace'; import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
import { useNavigateHelper } from '../../hooks/use-navigate-helper'; import { useNavigateHelper } from '../../hooks/use-navigate-helper';
import { performanceRenderLogger } from '../../shared';
const DetailPageImpl = (): ReactElement => { const DetailPageImpl = (): ReactElement => {
const { openPage, jumpToSubPath } = useNavigateHelper(); const { openPage, jumpToSubPath } = useNavigateHelper();
@@ -145,5 +146,7 @@ export const loader: LoaderFunction = async args => {
}; };
export const Component = () => { export const Component = () => {
performanceRenderLogger.info('DetailPage');
return <DetailPage />; return <DetailPage />;
}; };

View File

@@ -15,10 +15,17 @@ import {
} from 'react-router-dom'; } from 'react-router-dom';
import { WorkspaceLayout } from '../../layouts/workspace-layout'; import { WorkspaceLayout } from '../../layouts/workspace-layout';
import { performanceLogger, performanceRenderLogger } from '../../shared';
const workspaceLoaderLogger = performanceLogger.namespace('workspace_loader');
export const loader: LoaderFunction = async args => { export const loader: LoaderFunction = async args => {
workspaceLoaderLogger.info('start');
const rootStore = getCurrentStore(); const rootStore = getCurrentStore();
const meta = await rootStore.get(rootWorkspacesMetadataAtom); const meta = await rootStore.get(rootWorkspacesMetadataAtom);
workspaceLoaderLogger.info('meta loaded');
const currentMetadata = meta.find(({ id }) => id === args.params.workspaceId); const currentMetadata = meta.find(({ id }) => id === args.params.workspaceId);
if (!currentMetadata) { if (!currentMetadata) {
return redirect('/404'); return redirect('/404');
@@ -32,6 +39,8 @@ export const loader: LoaderFunction = async args => {
} }
if (currentMetadata.flavour === WorkspaceFlavour.AFFINE_CLOUD) { if (currentMetadata.flavour === WorkspaceFlavour.AFFINE_CLOUD) {
const [workspaceAtom] = getBlockSuiteWorkspaceAtom(currentMetadata.id); const [workspaceAtom] = getBlockSuiteWorkspaceAtom(currentMetadata.id);
workspaceLoaderLogger.info('get cloud workspace atom');
const workspace = await rootStore.get(workspaceAtom); const workspace = await rootStore.get(workspaceAtom);
return (() => { return (() => {
const blockVersions = workspace.meta.blockVersions; const blockVersions = workspace.meta.blockVersions;
@@ -46,10 +55,14 @@ export const loader: LoaderFunction = async args => {
return false; return false;
})(); })();
} }
workspaceLoaderLogger.info('done');
return null; return null;
}; };
export const Component = (): ReactElement => { export const Component = (): ReactElement => {
performanceRenderLogger.info('WorkspaceLayout');
const incompatible = useLoaderData(); const incompatible = useLoaderData();
return ( return (
<WorkspaceLayout incompatible={!!incompatible}> <WorkspaceLayout incompatible={!!incompatible}>

View File

@@ -1,3 +1,4 @@
import { DebugLogger } from '@affine/debug';
import type { WorkspaceRegistry } from '@affine/env/workspace'; import type { WorkspaceRegistry } from '@affine/env/workspace';
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store'; import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
@@ -26,3 +27,6 @@ export const pathGenerator = {
} satisfies { } satisfies {
[Path in WorkspaceSubPath]: (workspaceId: string) => string; [Path in WorkspaceSubPath]: (workspaceId: string) => string;
}; };
export const performanceLogger = new DebugLogger('performance');
export const performanceRenderLogger = performanceLogger.namespace('render');

View File

@@ -1,3 +1,4 @@
import { DebugLogger } from '@affine/debug';
import { createIndexeddbStorage } from '@blocksuite/store'; import { createIndexeddbStorage } from '@blocksuite/store';
import { import {
createIndexedDBDatasource, createIndexedDBDatasource,
@@ -12,6 +13,7 @@ import { createCloudBlobStorage } from '../blob/cloud-blob-storage';
import { createAffineDataSource } from '.'; import { createAffineDataSource } from '.';
import { CRUD } from './crud'; import { CRUD } from './crud';
const performanceLogger = new DebugLogger('performance:sync');
let abortController: AbortController | undefined; let abortController: AbortController | undefined;
const downloadRootFromIndexedDB = async ( const downloadRootFromIndexedDB = async (
@@ -29,9 +31,13 @@ const downloadRootFromIndexedDB = async (
}; };
export async function startSync() { export async function startSync() {
performanceLogger.info('start');
abortController = new AbortController(); abortController = new AbortController();
const signal = abortController.signal; const signal = abortController.signal;
const workspaces = await CRUD.list(); const workspaces = await CRUD.list();
performanceLogger.info('CRUD list');
const syncDocPromises = workspaces.map(workspace => const syncDocPromises = workspaces.map(workspace =>
downloadRootFromIndexedDB( downloadRootFromIndexedDB(
workspace.id, workspace.id,
@@ -40,6 +46,8 @@ export async function startSync() {
) )
); );
await Promise.all(syncDocPromises); await Promise.all(syncDocPromises);
performanceLogger.info('all sync promise');
const syncPromises = workspaces.map(workspace => { const syncPromises = workspaces.map(workspace => {
const remoteDataSource = createAffineDataSource( const remoteDataSource = createAffineDataSource(
workspace.id, workspace.id,
@@ -104,6 +112,7 @@ export async function startSync() {
}); });
}); });
await Promise.all([...syncPromises, ...syncBlobPromises]); await Promise.all([...syncPromises, ...syncBlobPromises]);
performanceLogger.info('sync done');
} }
export async function stopSync() { export async function stopSync() {

View File

@@ -1,3 +1,4 @@
import { DebugLogger } from '@affine/debug';
import type { WorkspaceAdapter } from '@affine/env/workspace'; import type { WorkspaceAdapter } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import type { BlockHub } from '@blocksuite/blocks'; import type { BlockHub } from '@blocksuite/blocks';
@@ -12,6 +13,8 @@ import { z } from 'zod';
import { getOrCreateWorkspace } from './manager'; import { getOrCreateWorkspace } from './manager';
const performanceJotaiLogger = new DebugLogger('performance:jotai');
const rootWorkspaceMetadataV1Schema = z.object({ const rootWorkspaceMetadataV1Schema = z.object({
id: z.string(), id: z.string(),
flavour: z.nativeEnum(WorkspaceFlavour), flavour: z.nativeEnum(WorkspaceFlavour),
@@ -80,6 +83,8 @@ type FetchMetadata = (
* @internal * @internal
*/ */
const fetchMetadata: FetchMetadata = async (get, { signal }) => { const fetchMetadata: FetchMetadata = async (get, { signal }) => {
performanceJotaiLogger.info('fetch metadata start');
const WorkspaceAdapters = get(workspaceAdaptersAtom); const WorkspaceAdapters = get(workspaceAdaptersAtom);
assertExists(WorkspaceAdapters, 'workspace adapter should be defined'); assertExists(WorkspaceAdapters, 'workspace adapter should be defined');
const metadata: RootWorkspaceMetadata[] = []; const metadata: RootWorkspaceMetadata[] = [];
@@ -120,6 +125,7 @@ const fetchMetadata: FetchMetadata = async (get, { signal }) => {
once: true, once: true,
}); });
}); });
performanceJotaiLogger.info('migration done');
} }
metadata.push(...loadFromLocalStorage()); metadata.push(...loadFromLocalStorage());
@@ -131,11 +137,15 @@ const fetchMetadata: FetchMetadata = async (get, { signal }) => {
); );
for (const Adapter of Adapters) { for (const Adapter of Adapters) {
performanceJotaiLogger.info('%s adapter', Adapter.flavour);
const { CRUD, flavour: currentFlavour } = Adapter; const { CRUD, flavour: currentFlavour } = Adapter;
if ( if (
Adapter.Events['app:access'] && Adapter.Events['app:access'] &&
!(await Adapter.Events['app:access']()) !(await Adapter.Events['app:access']())
) { ) {
performanceJotaiLogger.info('%s app:access', Adapter.flavour);
// skip the adapter if the user doesn't have access to it // skip the adapter if the user doesn't have access to it
const removed = metadata.filter( const removed = metadata.filter(
meta => meta.flavour === currentFlavour meta => meta.flavour === currentFlavour
@@ -148,6 +158,7 @@ const fetchMetadata: FetchMetadata = async (get, { signal }) => {
} }
try { try {
const item = await CRUD.list(); const item = await CRUD.list();
performanceJotaiLogger.info('%s CRUD list', Adapter.flavour);
// remove the metadata that is not in the list // remove the metadata that is not in the list
// because we treat the workspace adapter as the source of truth // because we treat the workspace adapter as the source of truth
{ {
@@ -179,6 +190,7 @@ const fetchMetadata: FetchMetadata = async (get, { signal }) => {
} catch (e) { } catch (e) {
console.error('list data error:', e); console.error('list data error:', e);
} }
performanceJotaiLogger.info('%s service:start', Adapter.flavour);
Adapter.Events['service:start']?.(); Adapter.Events['service:start']?.();
} }
} }
@@ -195,7 +207,7 @@ const fetchMetadata: FetchMetadata = async (get, { signal }) => {
} }
}); });
const result = Array.from(metadataMap.values()); const result = Array.from(metadataMap.values());
console.info('metadata', result); performanceJotaiLogger.info('fetch metadata done', result);
return result; return result;
}; };