feat: debug logger with levels (#1165)

This commit is contained in:
Peng Xiao
2023-02-21 19:23:53 +08:00
committed by GitHub
parent 11ade8aeaf
commit 86346b284e
21 changed files with 155 additions and 75 deletions
+1
View File
@@ -13,6 +13,7 @@
"@affine/datacenter": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/store": "workspace:*",
"@affine/debug": "workspace:*",
"@blocksuite/blocks": "0.4.1",
"@blocksuite/editor": "0.4.1",
"@blocksuite/global": "0.4.1",
+1
View File
@@ -9,6 +9,7 @@
},
"dependencies": {
"@affine/i18n": "workspace:*",
"@affine/debug": "workspace:*",
"@blocksuite/blocks": "0.4.1",
"@blocksuite/editor": "0.4.1",
"@blocksuite/global": "0.4.1",
+1 -2
View File
@@ -9,7 +9,6 @@
"url": "git+https://github.com/toeverything/AFFiNE.git"
},
"devDependencies": {
"@types/debug": "^4.1.7",
"fake-indexeddb": "4.0.1",
"typescript": "^4.9.5"
},
@@ -17,7 +16,7 @@
"@blocksuite/blocks": "0.4.1",
"@blocksuite/store": "0.4.1",
"@tauri-apps/api": "^1.2.0",
"debug": "^4.3.4",
"@affine/debug": "workspace:*",
"encoding": "^0.1.13",
"firebase": "^9.17.1",
"idb-keyval": "^6.2.0",
+10 -14
View File
@@ -1,7 +1,7 @@
import { DebugLogger } from '@affine/debug';
import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store';
import assert from 'assert';
import { getLogger } from './logger';
import { MessageCenter } from './message';
import { AffineProvider } from './provider';
import type {
@@ -23,7 +23,7 @@ import { WorkspaceUnitCollection } from './workspace-unit-collection';
export class DataCenter {
private readonly _workspaceUnitCollection = new WorkspaceUnitCollection();
private readonly _logger = getLogger('dc');
private readonly _logger = new DebugLogger('datacenter');
private _workspaceInstances: Map<string, BlocksuiteWorkspace> = new Map();
private _messageCenter = MessageCenter.getInstance();
@@ -33,19 +33,12 @@ export class DataCenter {
private _mainProvider?: BaseProvider;
providerMap: Map<string, BaseProvider> = new Map();
private constructor(debug: boolean) {
this._logger.enabled = debug;
}
static initEmpty() {
return new DataCenter(false);
return new DataCenter();
}
static async init(
debug: boolean,
exclude: 'affine'[] = []
): Promise<DataCenter> {
const dc = new DataCenter(debug);
static async init(exclude: 'affine'[] = []): Promise<DataCenter> {
const dc = new DataCenter();
const getInitParams = () => {
return {
logger: dc._logger,
@@ -182,7 +175,10 @@ export class DataCenter {
}
const provider = this.providerMap.get(workspaceUnit.provider);
assert(provider, `provide '${workspaceUnit.provider}' is not registered`);
this._logger(`Loading ${workspaceUnit.provider} workspace: `, workspaceId);
this._logger.debug(
`Loading ${workspaceUnit.provider} workspace: `,
workspaceId
);
const workspace = this._getBlocksuiteWorkspace(workspaceId);
this._workspaceInstances.set(workspaceId, workspace);
@@ -350,7 +346,7 @@ export class DataCenter {
providerId = 'affine'
) {
if (workspaceUnit.provider === providerId) {
this._logger('Workspace provider is same');
this._logger.error('Workspace provider is same');
return;
}
const provider = this.providerMap.get(providerId);
+2 -3
View File
@@ -3,9 +3,9 @@ import { DataCenter } from './datacenter';
const _initializeDataCenter = () => {
let _dataCenterInstance: Promise<DataCenter>;
return (debug = true) => {
return () => {
if (!_dataCenterInstance) {
_dataCenterInstance = DataCenter.init(debug);
_dataCenterInstance = DataCenter.init();
}
return _dataCenterInstance;
@@ -15,7 +15,6 @@ const _initializeDataCenter = () => {
export const getDataCenter = _initializeDataCenter();
export { DataCenter };
export { getLogger } from './logger';
export * from './message';
export { AffineProvider } from './provider/affine';
export * from './provider/affine/apis';
-7
View File
@@ -1,7 +0,0 @@
import debug from 'debug';
export function getLogger(namespace: string) {
const logger = debug(namespace);
logger.log = console.log.bind(console);
return logger;
}
@@ -86,7 +86,6 @@ export class AffineProvider extends BaseProvider {
`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${
window.location.host
}/api/global/sync/`,
this._logger,
this._apis.auth,
{
params: {
@@ -115,7 +114,7 @@ export class AffineProvider extends BaseProvider {
ws_details,
metadata,
}: ChannelMessage) {
this._logger('receive server message');
this._logger.debug('receive server message');
const newlyCreatedWorkspaces: WorkspaceUnit[] = [];
const currentWorkspaceIds = this._workspaces.list().map(w => w.id);
const newlyRemovedWorkspaceIds = currentWorkspaceIds;
@@ -331,7 +330,7 @@ export class AffineProvider extends BaseProvider {
await this.deleteWorkspace(w.id);
this._workspaces.remove(w.id);
} catch (e) {
this._logger('has a problem of delete workspace ', e);
this._logger.error('has a problem of delete workspace ', e);
}
}
}
@@ -1,3 +1,4 @@
import { DebugLogger } from '@affine/debug';
import { initializeApp } from 'firebase/app';
import type { User } from 'firebase/auth';
import {
@@ -10,7 +11,6 @@ import {
import { decode } from 'js-base64';
import { KyInstance } from 'ky/distribution/types/ky';
import { getLogger } from '../../../logger';
import { storage } from '../storage';
export interface AccessTokenMessage {
@@ -58,7 +58,7 @@ export class GoogleAuth {
private readonly _doLogin: ReturnType<typeof createDoLogin>;
constructor(bareClient: KyInstance) {
this._logger = getLogger('token');
this._logger = new DebugLogger('token');
this._logger.enabled = true;
this._doLogin = createDoLogin(bareClient);
@@ -93,7 +93,7 @@ export class GoogleAuth {
const login: LoginResponse = JSON.parse(loginStr);
this.setLogin(login);
} catch (err) {
this._logger('Failed to parse login info', err);
this._logger.warn('Failed to parse login info', err);
}
}
@@ -118,7 +118,7 @@ export class GoogleAuth {
}
return true;
} catch {
this._logger('Failed to refresh token');
this._logger.warn('Failed to refresh token');
} finally {
// clear on settled
this._padding = undefined;
@@ -191,7 +191,7 @@ export function createGoogleAuth(bareAuth: KyInstance): GoogleAuth {
export const getAuthorizer = (googleAuth: GoogleAuth) => {
let _firebaseAuth: FirebaseAuth | null = null;
const logger = getLogger('authorizer');
const logger = new DebugLogger('authorizer');
// getAuth will send requests on calling thus we can lazy init it
const getAuth = () => {
@@ -211,7 +211,7 @@ export const getAuthorizer = (googleAuth: GoogleAuth) => {
}
return _firebaseAuth;
} catch (error) {
logger(error);
logger.error('Failed to initialize firebase', error);
return null;
}
};
@@ -1,7 +1,7 @@
import { DebugLogger } from '@affine/debug';
import * as url from 'lib0/url';
import * as websocket from 'lib0/websocket';
import { Logger } from '../../types';
import { GoogleAuth } from './apis/google';
const RECONNECT_INTERVAL_TIME = 500;
@@ -9,12 +9,11 @@ const MAX_RECONNECT_TIMES = 50;
export class WebsocketClient extends websocket.WebsocketClient {
public shouldReconnect = false;
private _logger: Logger;
private _retryTimes = 0;
private _auth: GoogleAuth;
private _logger = new DebugLogger('affine:channel');
constructor(
serverUrl: string,
logger: Logger,
auth: GoogleAuth,
options?: ConstructorParameters<typeof websocket.WebsocketClient>[1] & {
params: Record<string, string>;
@@ -30,13 +29,12 @@ export class WebsocketClient extends websocket.WebsocketClient {
serverUrl + '/' + (encodedParams.length === 0 ? '' : '?' + encodedParams);
super(newUrl, options);
this._auth = auth;
this._logger = logger;
this._setupChannel();
}
private _setupChannel() {
this.on('connect', () => {
this._logger('Affine channel connected');
this._logger.debug('Affine channel connected');
this.shouldReconnect = true;
this._retryTimes = 0;
});
@@ -49,15 +47,17 @@ export class WebsocketClient extends websocket.WebsocketClient {
setTimeout(() => {
if (this._retryTimes <= MAX_RECONNECT_TIMES) {
this.connect();
this._logger(
this._logger.info(
`try reconnect channel ${++this._retryTimes} times`
);
} else {
this._logger('reconnect failed, max reconnect times reached');
this._logger.error(
'reconnect failed, max reconnect times reached'
);
}
}, RECONNECT_INTERVAL_TIME);
} catch (e) {
this._logger('reconnect failed', e);
this._logger.error('reconnect failed', e);
}
}
}
+6 -14
View File
@@ -1,18 +1,14 @@
import { DebugLogger } from '@affine/debug';
import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store';
import { MessageCenter } from '../message';
import { Logger, User } from '../types';
import { User } from '../types';
import type { WorkspaceUnit, WorkspaceUnitCtorParams } from '../workspace-unit';
import type { WorkspaceUnitCollectionScope } from '../workspace-unit-collection';
import { Member } from './affine/apis';
import { Permission } from './affine/apis/workspace';
const defaultLogger = () => {
return;
};
export interface ProviderConstructorParams {
logger?: Logger;
workspaces: WorkspaceUnitCollectionScope;
messageCenter: MessageCenter;
}
@@ -23,25 +19,21 @@ export type UpdateWorkspaceMetaParams = Partial<
Pick<WorkspaceUnitCtorParams, 'name' | 'avatar'>
>;
export class BaseProvider {
export abstract class BaseProvider {
/** provider id */
public readonly id: string = 'base';
/** workspace unit collection */
protected _workspaces!: WorkspaceUnitCollectionScope;
protected _logger!: Logger;
protected _logger: DebugLogger;
/** send message with message center */
protected _sendMessage!: ReturnType<
InstanceType<typeof MessageCenter>['getMessageSender']
>;
public constructor({
logger,
workspaces,
messageCenter,
}: ProviderConstructorParams) {
this._logger = (logger || defaultLogger) as Logger;
public constructor({ workspaces, messageCenter }: ProviderConstructorParams) {
this._workspaces = workspaces;
this._sendMessage = messageCenter.getMessageSender(this.id);
this._logger = new DebugLogger(`provider:${this.id}`);
}
/**
@@ -42,7 +42,7 @@ export class LocalProvider extends BaseProvider {
idb = new IndexedDBProvider(workspace.room, workspace.doc);
}
this._idbMap.set(workspace, idb);
this._logger('Local data loaded');
this._logger.debug('Local data loaded');
return workspace;
}
@@ -68,7 +68,7 @@ export class LocalProvider extends BaseProvider {
this._workspaces.add(workspaceUnits);
return workspaceUnits;
} catch (error) {
this._logger(`Failed to parse workspaces from storage`);
this._logger.error(`Failed to parse workspaces from storage`);
}
}
return [];
@@ -84,7 +84,7 @@ export class LocalProvider extends BaseProvider {
this._idbMap.delete(workspace.blocksuiteWorkspace);
}
} else {
this._logger(`Failed to delete workspace ${id}`);
this._logger.error(`Failed to delete workspace ${id}`);
}
}
@@ -21,6 +21,7 @@ import { createWorkspaceUnit } from './utils';
export class TauriIPCProvider extends LocalProvider {
public id = 'tauri-ipc';
static defaultUserEmail = 'xxx@xx.xx';
/**
* // TODO: We only have one user in this version of app client. But may support switch user later.
*/
@@ -79,7 +80,7 @@ export class TauriIPCProvider extends LocalProvider {
workspaceID: string,
blocksuiteWorkspace: BlocksuiteWorkspace
) {
this._logger(`Loading ${workspaceID}...`);
this._logger.debug(`Loading ${workspaceID}...`);
const result = await this.#ipc?.getYDocument({ id: workspaceID });
if (result) {
const updates = result.updates.map(
@@ -88,7 +89,7 @@ export class TauriIPCProvider extends LocalProvider {
const mergedUpdate = Y.mergeUpdates(updates);
await applyUpdate(blocksuiteWorkspace, mergedUpdate);
this._logger(`Loaded: ${workspaceID}`);
this._logger.debug(`Loaded: ${workspaceID}`);
}
}
@@ -96,7 +97,7 @@ export class TauriIPCProvider extends LocalProvider {
workspaceID: string,
blocksuiteWorkspace: BlocksuiteWorkspace
) {
this._logger(`Connecting yDoc for ${workspaceID}...`);
this._logger.debug(`Connecting yDoc for ${workspaceID}...`);
blocksuiteWorkspace.doc.on('update', async (update: Uint8Array) => {
try {
const binary = Y.encodeStateAsUpdate(blocksuiteWorkspace.doc);
@@ -109,7 +110,7 @@ export class TauriIPCProvider extends LocalProvider {
}
} catch (error) {
// TODO: write error log to disk, and add button to open them in settings panel
console.error("#yDocument.on('update'", error);
this._logger.error("#yDocument.on('update'", error);
}
});
}
@@ -134,7 +135,7 @@ export class TauriIPCProvider extends LocalProvider {
public override async createWorkspace(
meta: CreateWorkspaceInfoParams
): Promise<WorkspaceUnit | undefined> {
this._logger('Creating client app workspace');
this._logger.debug('Creating client app workspace');
assert(this.#ipc);
assert(this.#userID);
const { id } = await this.#ipc.createWorkspace({
+1 -3
View File
@@ -1,5 +1,3 @@
import { getLogger } from '../logger';
// export type WorkspaceInfo = {
// name: string;
// id: string;
@@ -27,7 +25,7 @@ export type User = {
// export type WorkspaceMeta = Pick<WorkspaceInfo, 'name' | 'avatar'>;
export type Logger = ReturnType<typeof getLogger>;
export type Logger = typeof import('@affine/debug').DebugLogger;
export type Message = {
code: number;
+3
View File
@@ -0,0 +1,3 @@
# @affine/debug
A common debug interface for packages in this repository.
+14
View File
@@ -0,0 +1,14 @@
{
"name": "@affine/debug",
"private": true,
"main": "./src/index.ts",
"keywords": [],
"repository": {
"type": "git",
"url": "git+https://github.com/toeverything/AFFiNE.git"
},
"dependencies": {
"@types/debug": "^4.1.7",
"debug": "^4.3.4"
}
}
+59
View File
@@ -0,0 +1,59 @@
import debug from 'debug';
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
const SESSION_KEY = 'affine:debug';
const development = process.env.NODE_ENV === 'development';
if (typeof window !== 'undefined') {
// enable debug logs if the URL search string contains `debug`
// e.g. http://localhost:3000/?debug
if (window.location.search.includes('debug')) {
// enable debug logs for the current session
// since the query string may be removed by the browser after navigations,
// we need to store the debug flag in sessionStorage
sessionStorage.setItem(SESSION_KEY, 'true');
}
if (sessionStorage.getItem(SESSION_KEY) === 'true' || development) {
// enable all debug logs by default
debug.enable('*');
console.warn('Debug logs enabled');
}
}
export class DebugLogger {
private _debug: debug.Debugger;
constructor(namespace: string) {
this._debug = debug(namespace);
}
set enabled(enabled: boolean) {
this._debug.enabled = enabled;
}
get enabled() {
return this._debug.enabled;
}
debug(message: string, ...args: any[]) {
this.log('debug', message, ...args);
}
info(message: string, ...args: any[]) {
this.log('info', message, ...args);
}
warn(message: string, ...args: any[]) {
this.log('warn', message, ...args);
}
error(message: string, ...args: any[]) {
this.log('error', message, ...args);
}
log(level: LogLevel, message: string, ...args: any[]) {
this._debug.log = console[level].bind(console);
this._debug(`[${level.toUpperCase()}] ${message}`, ...args);
}
}
+1
View File
@@ -26,6 +26,7 @@
"url": "git+https://github.com/toeverything/AFFiNE.git"
},
"dependencies": {
"@affine/debug": "workspace:*",
"react": "^18.2.0",
"i18next": "^22.4.10",
"react-i18next": "^12.1.5"
+1
View File
@@ -4,6 +4,7 @@
"main": "./src/index.ts",
"dependencies": {
"@affine/datacenter": "workspace:*",
"@affine/debug": "workspace:*",
"@blocksuite/blocks": "0.4.1",
"@blocksuite/editor": "0.4.1",
"@blocksuite/global": "0.4.1",
+8
View File
@@ -1,4 +1,5 @@
import { User } from '@affine/datacenter';
import { DebugLogger } from '@affine/debug';
import { GlobalActionsCreator } from '..';
import { dataCenterPromise } from '../datacenter';
@@ -19,6 +20,8 @@ export const createUserState = (): UserState => ({
isOwner: false,
});
const logger = new DebugLogger('store:user');
export const createUserActions: GlobalActionsCreator<UserActions> = (
set,
get
@@ -45,14 +48,19 @@ export const createUserActions: GlobalActionsCreator<UserActions> = (
}
set({ user, isOwner });
logger.debug('login success', user);
return user;
} catch (error) {
logger.error('login failed', error);
return null; // login failed
}
},
logout: async () => {
const dataCenter = await dataCenterPromise;
await dataCenter.logout();
logger.debug('logout success');
set({ user: null });
},
};
+20 -6
View File
@@ -145,6 +145,7 @@ importers:
specifiers:
'@affine/component': workspace:*
'@affine/datacenter': workspace:*
'@affine/debug': workspace:*
'@affine/i18n': workspace:*
'@affine/store': workspace:*
'@blocksuite/blocks': 0.4.1
@@ -188,6 +189,7 @@ importers:
dependencies:
'@affine/component': link:../../packages/component
'@affine/datacenter': link:../../packages/data-center
'@affine/debug': link:../../packages/debug
'@affine/i18n': link:../../packages/i18n
'@affine/store': link:../../packages/store
'@blocksuite/blocks': 0.4.1_tdlxw56kpoc45go7l7gsdk5hjm
@@ -232,6 +234,7 @@ importers:
packages/component:
specifiers:
'@affine/debug': workspace:*
'@affine/i18n': workspace:*
'@blocksuite/blocks': 0.4.1
'@blocksuite/editor': 0.4.1
@@ -265,6 +268,7 @@ importers:
webpack: ^5.75.0
yjs: ^13.5.46
dependencies:
'@affine/debug': link:../debug
'@affine/i18n': link:../i18n
'@blocksuite/blocks': 0.4.1_tdlxw56kpoc45go7l7gsdk5hjm
'@blocksuite/editor': 0.4.1_e5cdg6aldwc4hxgrfphufwkeea
@@ -301,11 +305,10 @@ importers:
packages/data-center:
specifiers:
'@affine/debug': workspace:*
'@blocksuite/blocks': 0.4.1
'@blocksuite/store': 0.4.1
'@tauri-apps/api': ^1.2.0
'@types/debug': ^4.1.7
debug: ^4.3.4
encoding: ^0.1.13
fake-indexeddb: 4.0.1
firebase: ^9.17.1
@@ -319,10 +322,10 @@ importers:
y-protocols: ^1.0.5
yjs: ^13.5.46
dependencies:
'@affine/debug': link:../debug
'@blocksuite/blocks': 0.4.1_tdlxw56kpoc45go7l7gsdk5hjm
'@blocksuite/store': 0.4.1_lit@2.6.1+yjs@13.5.46
'@tauri-apps/api': 1.2.0_nb4isgkwd3sres4g7j7rgtldsu
debug: 4.3.4
encoding: 0.1.13
firebase: 9.17.1_encoding@0.1.13
idb-keyval: 6.2.0
@@ -334,12 +337,20 @@ importers:
y-protocols: 1.0.5
yjs: 13.5.46
devDependencies:
'@types/debug': 4.1.7
fake-indexeddb: 4.0.1
typescript: 4.9.5
packages/debug:
specifiers:
'@types/debug': ^4.1.7
debug: ^4.3.4
dependencies:
'@types/debug': 4.1.7
debug: 4.3.4
packages/i18n:
specifiers:
'@affine/debug': workspace:*
'@types/node': ^18.14.0
'@types/prettier': ^2.7.2
i18next: ^22.4.10
@@ -349,6 +360,7 @@ importers:
ts-node: ^10.9.1
typescript: ^4.9.5
dependencies:
'@affine/debug': link:../debug
i18next: 22.4.10
react: 18.2.0
react-i18next: 12.1.5_dxv7ampvtjrtnimevxnrn5rvga
@@ -377,6 +389,7 @@ importers:
packages/store:
specifiers:
'@affine/datacenter': workspace:*
'@affine/debug': workspace:*
'@blocksuite/blocks': 0.4.1
'@blocksuite/editor': 0.4.1
'@blocksuite/global': 0.4.1
@@ -392,6 +405,7 @@ importers:
zustand: ^4.3.3
dependencies:
'@affine/datacenter': link:../data-center
'@affine/debug': link:../debug
'@blocksuite/blocks': 0.4.1_tdlxw56kpoc45go7l7gsdk5hjm
'@blocksuite/editor': 0.4.1_e5cdg6aldwc4hxgrfphufwkeea
'@blocksuite/global': 0.4.1_lit@2.6.1
@@ -6157,7 +6171,7 @@ packages:
resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
dependencies:
'@types/ms': 0.7.31
dev: true
dev: false
/@types/detect-port/1.3.2:
resolution: {integrity: sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==}
@@ -6314,7 +6328,7 @@ packages:
/@types/ms/0.7.31:
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
dev: true
dev: false
/@types/node-fetch/2.6.2:
resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==}
+2 -1
View File
@@ -21,7 +21,8 @@
"@affine/datacenter": ["./packages/datacenter/src"],
"@affine/i18n": ["./packages/i18n/src"],
"@affine/logger": ["./packages/logger/src"],
"@affine/store": ["packages/store/src"],
"@affine/store": ["./packages/store/src"],
"@affine/debug": ["./packages/store/debug"],
"@toeverything/pathfinder-logger": ["./packages/logger"]
}
},