refactor: logger

This commit is contained in:
unanmed 2024-09-26 22:58:42 +08:00
parent bd432af00a
commit b06c346b56
22 changed files with 130 additions and 290 deletions

View File

@ -1,4 +1,5 @@
import { debounce } from 'lodash-es';
import logInfo from '@/data/logger.json';
// todo: 使用格式化输出?
@ -7,8 +8,6 @@ export const enum LogLevel {
LOG,
/** 报错、严重警告和警告 */
WARNING,
/** 报错和严重警告 */
SEVERE_WARNING,
/** 仅报错 */
ERROR
}
@ -47,6 +46,11 @@ const hideTipText = debounce(() => {
logTip.style.display = 'none';
}, 5000);
const nums = new Set(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']);
const logError = logInfo.error as Record<number, string>;
const logWarn = logInfo.warn as Record<number, string>;
export class Logger {
level: LogLevel = LogLevel.LOG;
enabled: boolean = true;
@ -58,6 +62,37 @@ export class Logger {
this.level = logLevel;
}
private parseInfo(text: string, ...params: string[]) {
let pointer = -1;
let str = '';
let inParam = false;
let paramNum = '';
while (++pointer < text.length) {
const char = text[pointer];
if (char === '$' && text[pointer - 1] !== '\\') {
inParam = true;
continue;
}
if (inParam) {
if (nums.has(char)) {
paramNum += char;
} else {
inParam = false;
const num = Number(paramNum);
str += params[num] ?? '[not delivered]';
}
continue;
}
str += char;
}
return str;
}
/**
*
* @param level
@ -69,9 +104,10 @@ export class Logger {
/**
*
* @param code 使
* @param text
* @param params
*/
error(code: number, text: string) {
error(code: number, ...params: string[]) {
const text = this.parseInfo(logError[code], ...params);
if (this.catching) {
this.catchedInfo.push({
level: LogLevel.ERROR,
@ -90,36 +126,13 @@ export class Logger {
}
}
/**
*
* @param code
* @param text
*/
severe(code: number, text: string) {
if (this.catching) {
this.catchedInfo.push({
level: LogLevel.ERROR,
message: text,
code
});
}
if (this.level <= LogLevel.SEVERE_WARNING && this.enabled) {
console.warn(`[SEVERE WARNING Code ${code}] ${text}`);
if (!main.replayChecking) {
logTip.style.color = 'goldenrod';
logTip.style.display = 'block';
logTip.textContent = `Severe warning thrown, please check in console.`;
hideTipText();
}
}
}
/**
*
* @param code
* @param text
*/
warn(code: number, text: string) {
warn(code: number, ...params: string[]) {
const text = this.parseInfo(logWarn[code], ...params);
if (this.catching) {
this.catchedInfo.push({
level: LogLevel.ERROR,

View File

@ -67,7 +67,7 @@ export abstract class Resource<T = any> extends Disposable<string> {
this.uri = uri;
if (this.type === 'none') {
logger.warn(1, `Resource with type of 'none' is loaded.`);
logger.warn(1);
}
}
@ -367,10 +367,7 @@ export class LoadTask<
*/
async load(): Promise<ResourceType[T]> {
if (this.loadingStarted) {
logger.warn(
2,
`Repeat load of resource '${this.resource.type}/${this.resource.uri}'`
);
logger.warn(2, this.resource.type, this.resource.uri);
return new Promise<void>(res => res());
}
this.loadingStarted = true;
@ -388,10 +385,7 @@ export class LoadTask<
})
.catch(reason => {
LoadTask.errorTask++;
logger.error(
2,
`Unexpected loading error in loading resource '${this.resource.type}/${this.resource.uri}'. Error info: ${reason}`
);
logger.error(2, this.resource.type, this.resource.uri);
});
this.emit('loadStart', this.resource);
const value = await load;

View File

@ -481,7 +481,7 @@ export class Shadow {
*/
addLight(info: LightInfo) {
if (this.originLightInfo[info.id]) {
logger.warn(7, `Repeated light id.`);
logger.warn(19, info.id);
return;
}
this.originLightInfo[info.id] = info;
@ -1338,7 +1338,7 @@ export class LayerShadowExtends implements ILayerRenderExtends {
const ex = layer.getExtends('floor-hero');
if (!(ex instanceof HeroRenderer)) {
layer.removeExtends('shadow');
logger.error(1101, `Shadow extends needs 'floor-hero' extends as dependency.`);
logger.error(1101);
return;
}
this.hero = ex;

View File

@ -184,12 +184,7 @@ abstract class WebGLBase {
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
logger.error(
9,
`Cannot initialize shader program. Error info: ${gl.getProgramInfoLog(
program
)}`
);
logger.error(9, gl.getProgramInfoLog(program) ?? '');
}
return program;
@ -263,9 +258,8 @@ export function loadShader(
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
logger.error(
10,
`Cannot compile ${
type === gl.VERTEX_SHADER ? 'vertex' : 'fragment'
} shader. Error info: ${gl.getShaderInfoLog(shader)}`
type === gl.VERTEX_SHADER ? 'vertex' : 'fragment',
gl.getShaderInfoLog(shader) ?? ''
);
}
@ -286,12 +280,7 @@ export function createProgram(
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
logger.error(
9,
`Cannot initialize shader program. Error info: ${gl.getProgramInfoLog(
program
)}`
);
logger.error(9, gl.getProgramInfoLog(program) ?? '');
}
return program;

View File

@ -123,7 +123,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
*/
async post(): Promise<AxiosResponse<PostDanmakuResponse>> {
if (this.posted || this.posting) {
logger.warn(5, `Repeat post danmaku.`);
logger.warn(5);
return Promise.reject();
}
@ -159,10 +159,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
} catch (e) {
this.posted = false;
this.posting = false;
logger.error(
1,
`Unexpected error when posting danmaku. Error info: ${e}`
);
logger.error(1, String(e));
return Promise.reject();
}
}
@ -197,7 +194,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
this.y = parseInt(y);
this.floor = f as FloorIds;
} else {
logger.warn(3, `Unknown danmaku tag: ${v}`);
logger.warn(3, v);
}
});
}
@ -249,10 +246,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
this.style = { ...this.style, ...res };
}
} else {
logger.error(
8,
`Post danmaku with not allowed css. Info: ${allow.join(',')}`
);
logger.error(8, allow.join(','));
}
}
@ -305,7 +299,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
if (char === ']') {
if (!spec) {
logger.warn(4, `Ignored a mismatched ']' in danmaku.`);
logger.warn(4);
str += char;
} else {
spec = false;
@ -390,10 +384,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
const res = await axios.post<PostLikeResponse>(Danmaku.backend, form);
if (res.data.code !== 0) {
logger.severe(
2,
`Uncaught error in posting like info for danmaku. Danmaku id: ${this.id}.`
);
logger.warn(18, this.id.toString());
tip('error', `Error ${res.data.code}. ${res.data.message}`);
} else {
tip('success', res.data.message);
@ -429,7 +420,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
if (Danmaku.specList[type]) {
return Danmaku.specList[type](content, type);
} else {
logger.severe(1, `Unknown special danmaku element: ${type}.`);
logger.warn(7, type);
}
return h('span');
@ -496,7 +487,7 @@ export class Danmaku extends EventEmitter<DanmakuEvent> {
*/
static registerSpecContent(type: string, fn: SpecContentFn) {
if (this.specList[type]) {
logger.warn(6, `Registered special danmaku element: ${type}`);
logger.warn(6, type);
}
this.specList[type] = fn;
}

View File

@ -175,10 +175,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
if (bigImage) {
const image = core.material.images.images[bigImage];
if (!image) {
logger.warn(
10,
`Cannot resolve big image of enemy '${id}'.`
);
logger.warn(10, id);
return null;
}
let line = 0;
@ -296,10 +293,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
return data;
}
} else {
logger.warn(
11,
`Cannot resolve material ${num}. Material not exists.`
);
logger.warn(11, num.toString());
return null;
}
}

View File

@ -64,10 +64,7 @@ export class LayerGroupAnimate implements ILayerGroupRenderExtends {
LayerGroupAnimate.animateList.add(this);
this.listen();
} else {
logger.error(
14,
`Animate extends needs 'floor-hero' extends as dependency.`
);
logger.error(14);
group.removeExtends('animate');
}
}

View File

@ -81,7 +81,7 @@ export class BlockCacher<T> extends EventEmitter<BlockCacherEvent> {
*/
setCacheDepth(depth: number) {
if (depth > 31) {
logger.error(11, `Cache depth cannot larger than 31.`);
logger.error(11);
return;
}
const old = this.cache;

View File

@ -97,10 +97,7 @@ export class FloorDamageExtends
this.create();
this.listen();
} else {
logger.warn(
17,
`Floor-damage extends needs 'floor-binder' extends as dependency.`
);
logger.warn(17);
group.removeExtends('floor-damage');
}
}

View File

@ -238,10 +238,7 @@ export class HeroRenderer
*/
move(dir: Dir2): Promise<void> {
if (!this.moving) {
logger.error(
12,
`Cannot move while status is not 'moving'. Call 'readyMove' first.`
);
logger.error(12);
return Promise.reject();
}

View File

@ -872,18 +872,12 @@ export class Layer extends Container {
calAutotile: boolean = true
) {
if (data.length % width !== 0) {
logger.warn(
8,
`Incomplete render data is put. None will be filled to the lacked data.`
);
logger.warn(8);
data.push(...Array(width - (data.length % width)).fill(0));
}
const height = Math.round(data.length / width);
if (!this.containsRect(x, y, width, height)) {
logger.warn(
9,
`Data transfered is partially (or totally) out of range. Overflowed data will be ignored.`
);
logger.warn(9);
if (this.isRectOutside(x, y, width, height)) return;
}
// 特判特殊情况-全地图更新

View File

@ -351,10 +351,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
this.create();
adapter.add(this);
} else {
logger.error(
15,
`Viewport extends needs 'floor-hero' extends as dependency.`
);
logger.error(15);
group.removeExtends('viewport');
}
}

View File

@ -505,9 +505,8 @@ export class Shader extends Container<EShaderEvent> {
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
logger.error(
13,
`Cannot compile ${
type === gl.VERTEX_SHADER ? 'vertex' : 'fragment'
} shader. Error info: ${gl.getShaderInfoLog(shader)}`
type === gl.VERTEX_SHADER ? 'vertex' : 'fragment',
gl.getShaderInfoLog(shader) ?? ''
);
}

45
src/data/logger.json Normal file
View File

@ -0,0 +1,45 @@
{
"error": {
"1": "Unexpected error when posting danmaku. Error info: $1",
"2": "Unexpected loading error in loading resource '$1/$2''. Error info: $3",
"3": "Syntax error in parsing CSS: Unexpected ':'. Col: $1. CSS string: '$2'",
"4": "Syntax error in parsing CSS: Unexpected ';'. Col: $1. CSS string: '$2'",
"5": "Syntax error in parsing CSS: Missing property name after '-'. Col: $1. CSS string: '$2'",
"6": "Syntax error in parsing CSS: Unexpected end of css, expecting ':'. Col: $1. CSS string: '$2'",
"7": "Syntax error in parsing CSS: Unexpected end of css, expecting property value. Col: $1. CSS string: '$2'",
"8": "Post danmaku with not allowed css. Info: $1",
"9": "Cannot initialize shader program. Error info: $1",
"10": "Cannot compile $1 shader. Error info: $2",
"11": "Cache depth cannot larger than 31.",
"12": "Cannot move while status is not 'moving'. Call 'readyMove' first.",
"13": "Cannot compile $1 shader. Error info: $2",
"14": "Animate extension needs 'floor-hero' extension as dependency.",
"15": "Viewport extension needs 'floor-hero' extension as dependency.",
"1101": "Shadow extension needs 'floor-hero' extension as dependency.",
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency.",
"1301": "Portal extension need 'floor-binder' extension as dependency.",
"1401": "Halo extension needs 'floor-binder' extension as dependency."
},
"warn": {
"1": "Resource with type of 'none' is loaded.",
"2": "Repeat load of resource '$1/$2'.",
"3": "Unknown danmaku tag: $1",
"4": "Ignored a mismatched ']' in danmaku.",
"5": "Repeat post danmaku.",
"6": "Registered special danmaku element: $1.",
"7": "Unknown special danmaku element: '$1'.",
"8": "Incomplete render data is put. None will be filled to the lacked data.",
"9": "Data transfered is partially (or totally) out of range. Overflowed data will be ignored.",
"10": "Cannot resolve big image of enemy '$1;.",
"11": "Cannot resolve material $1. Material not exists.",
"12": "Cannot mark buffable with a non-number status. Key: '$1'.",
"13": "Cannot set buff of non-number status. Key: '$1'.",
"14": "Cannot add status of non-number status. Key: '$1'.",
"15": "Cannot get item of a non-item block on loc: $1,$2,$3.",
"16": "Override repeated state key: '$1'.",
"17": "Floor-damage extension needs 'floor-binder' extension as dependency.",
"18": "Uncaught error in posting like info for danmaku. Danmaku id: $1.",
"19": "Repeat light id: '$1'.",
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency."
}
}

View File

@ -1,123 +0,0 @@
[
"bgms.beforeBoss.mp3",
"bgms.cave.mp3",
"bgms.escape.mp3",
"bgms.grass.mp3",
"bgms.mount.mp3",
"bgms.plot1.mp3",
"bgms.road.mp3",
"bgms.title.mp3",
"bgms.tower.mp3",
"bgms.towerBoss.mp3",
"bgms.towerBoss2.mp3",
"bgms.towerBoss3.mp3",
"bgms.winter.mp3",
"bgms.winterTown.mp3",
"fonts.normal.ttf",
"images.IQ.png",
"images.arrow.png",
"images.atk.png",
"images.bg.jpg",
"images.boom.png",
"images.botton.png",
"images.cave2.jpg",
"images.def.png",
"images.exp.png",
"images.hero1.png",
"images.hero2.png",
"images.hp.png",
"images.money.png",
"images.skill.png",
"images.skill0.png",
"images.skill1.png",
"images.skill10.png",
"images.skill11.png",
"images.skill12.png",
"images.skill13.png",
"images.skill14.png",
"images.skill2.png",
"images.skill3.png",
"images.skill4.png",
"images.skill5.png",
"images.skill6.png",
"images.skill7.png",
"images.skill8.png",
"images.skill9.png",
"images.title.jpg",
"images.tower.jpg",
"images.tower7.jpeg",
"images.winskin.png",
"images.winskin2.png",
"images.winskin3.png",
"sounds.008-System08.ogg",
"sounds.015-Jump01.ogg",
"sounds.050-Explosion03.ogg",
"sounds.051-Explosion04.ogg",
"sounds.087-Action02.ogg",
"sounds.094-Attack06.ogg",
"sounds.118-Fire02.ogg",
"sounds.119-Fire03.ogg",
"sounds.120-Ice01.ogg",
"sounds.arrow.mp3",
"sounds.attack.mp3",
"sounds.bomb.mp3",
"sounds.cancel.mp3",
"sounds.centerFly.mp3",
"sounds.chapter.mp3",
"sounds.confirm.mp3",
"sounds.cursor.mp3",
"sounds.danger.mp3",
"sounds.door.mp3",
"sounds.drink.mp3",
"sounds.electron.mp3",
"sounds.equip.mp3",
"sounds.error.mp3",
"sounds.floor.mp3",
"sounds.item.mp3",
"sounds.jump.mp3",
"sounds.load.mp3",
"sounds.open_ui.mp3",
"sounds.paper.mp3",
"sounds.pickaxe.mp3",
"sounds.quake.mp3",
"sounds.recovery.mp3",
"sounds.save.mp3",
"sounds.shake.mp3",
"sounds.shop.mp3",
"sounds.thunder.mp3",
"sounds.tree.mp3",
"sounds.zone.mp3",
"tilesets.magictower.png",
"tilesets.043-Cave01.png",
"tilesets.004-Mountain01.png",
"tilesets.Map-Tower01.png",
"tilesets.Caverna1.png",
"tilesets.map-tower.png",
"tilesets.winter1.png",
"tilesets.snowTown.png",
"tilesets.room.png",
"autotiles.autotile.png",
"autotiles.autotile1.png",
"autotiles.autotile2.png",
"autotiles.autotile3.png",
"autotiles.autotile4.png",
"autotiles.autotile5.png",
"autotiles.autotile6.png",
"autotiles.autotile7.png",
"autotiles.autotile8.png",
"autotiles.autotile9.png",
"autotiles.autotile10.png",
"autotiles.autotile11.png",
"materials.animates.png",
"materials.cloud.png",
"materials.enemy48.png",
"materials.enemys.png",
"materials.fog.png",
"materials.icons.png",
"materials.items.png",
"materials.keyboard.png",
"materials.npc48.png",
"materials.npcs.png",
"materials.sun.png",
"materials.terrains.png"
]

View File

@ -170,10 +170,7 @@ export class HeroState<
*/
addStatus<K extends SelectKey<T, number>>(key: K, value: number): boolean {
if (typeof this.status[key] !== 'number') {
logger.warn(
14,
`Cannot add status of non-number status. Key: ${String(key)}`
);
logger.warn(14, String(key));
return false;
}
return this.setStatus<K>(key, (this.status[key] + value) as T[K]);
@ -201,12 +198,7 @@ export class HeroState<
*/
markBuffable(key: SelectKey<T, number>): void {
if (typeof this.status[key] !== 'number') {
logger.warn(
12,
`Cannot mark buffable with a non-number status. Key: ${String(
key
)}.`
);
logger.warn(12, String(key));
return;
}
this.buffable.add(key);
@ -221,10 +213,7 @@ export class HeroState<
*/
setBuff(key: SelectKey<T, number>, value: number): boolean {
if (!this.buffable.has(key) || typeof this.status[key] !== 'number') {
logger.warn(
13,
`Cannot set buff of non-number status. Key: ${String(key)}.`
);
logger.warn(13, String(key));
return false;
}
this.buffMap.set(key, value);
@ -239,10 +228,7 @@ export class HeroState<
*/
addBuff(key: SelectKey<T, number>, value: number): boolean {
if (!this.buffable.has(key) || typeof this.status[key] !== 'number') {
logger.warn(
13,
`Cannot set buff of non-number status. Key: ${String(key)}.`
);
logger.warn(13, String(key));
return false;
}
return this.setBuff(key, this.buffMap.get(key)! + value);
@ -452,10 +438,7 @@ export class Hero<T extends object = IHeroStatusDefault>
const id = block.event.id as AllIdsOf<'items'>;
const cls = core.material.items[id]?.cls;
if (cls === void 0) {
logger.warn(
15,
`Cannot get item of a non-item block on loc: ${item},${y},${floorId}`
);
logger.warn(15, item.toString(), y.toString(), floorId);
return false;
}
return this.addItem(id, num!);

View File

@ -56,7 +56,7 @@ export class GameState {
fromJSON?: FromJSONFunction<T>
) {
if (this.states.has(key)) {
logger.warn(16, `Override repeated state key: ${key}.`);
logger.warn(16, key);
}
if (toJSON) {

View File

@ -48,10 +48,7 @@ export class LayerGroupFilter implements ILayerGroupRenderExtends {
this.binder = ex;
this.listen();
} else {
logger.error(
1201,
`Floor-damage extends needs 'floor-binder' extends as dependency.`
);
logger.error(1201);
group.removeExtends('floor-damage');
}
}

View File

@ -28,10 +28,7 @@ export class LayerGroupHalo implements ILayerGroupRenderExtends {
this.halo.binder = ex;
group.appendChild(this.halo);
} else {
logger.error(
1401,
`Halo extends needs 'floor-binder' extends as dependency.`
);
logger.error(1401);
group.removeExtends('halo');
}
}

View File

@ -257,10 +257,7 @@ export class FloorItemDetail implements ILayerGroupRenderExtends {
this.listen();
FloorItemDetail.listened.add(this);
} else {
logger.warn(
1001,
`Item-detail extends needs 'floor-binder' and 'floor-damage' as dependency`
);
logger.warn(1001);
group.removeExtends('item-detail');
}
}

View File

@ -44,10 +44,7 @@ export class LayerGroupPortal implements ILayerGroupRenderExtends {
group.appendChild(this.portal);
this.listen();
} else {
logger.error(
1301,
`Portal extends need 'floor-binder' extends as dependency.`
);
logger.error(1301);
group.removeExtends('portal');
}
}

View File

@ -108,10 +108,7 @@ export function parseCss(css: string): Partial<Record<CanParseCss, string>> {
if (char === ':') {
if (!inProp) {
logger.error(
3,
`Syntax error in parsing CSS: Unexpected ':'. Col: ${pointer}. CSS string: '${css}'`
);
logger.error(3, pointer.toString(), css);
return res;
}
inProp = false;
@ -121,10 +118,7 @@ export function parseCss(css: string): Partial<Record<CanParseCss, string>> {
if (char === ';') {
if (prop.length === 0) continue;
if (inProp) {
logger.error(
4,
`Syntax error in parsing CSS: Unexpected ';'. Col: ${pointer}. CSS string: '${css}'`
);
logger.error(4, pointer.toString(), css);
return res;
}
res[prop as CanParseCss] = value.trim();
@ -136,10 +130,7 @@ export function parseCss(css: string): Partial<Record<CanParseCss, string>> {
if (upper) {
if (!inProp) {
logger.error(
5,
`Syntax error in parsing CSS: Missing property name after '-'. Col: ${pointer}. CSS string: '${css}'`
);
logger.error(5, pointer.toString(), css);
}
prop += char.toUpperCase();
upper = false;
@ -149,17 +140,11 @@ export function parseCss(css: string): Partial<Record<CanParseCss, string>> {
}
}
if (inProp && prop.length > 0) {
logger.error(
6,
`Syntax error in parsing CSS: Unexpected end of css, expecting ':'. Col: ${pointer}. CSS string: '${css}'`
);
logger.error(6, pointer.toString(), css);
return res;
}
if (!inProp && value.trim().length === 0) {
logger.error(
7,
`Syntax error in parsing CSS: Unexpected end of css, expecting property value. Col: ${pointer}. CSS string: '${css}'`
);
logger.error(7, pointer.toString(), css);
return res;
}
if (prop.length > 0) res[prop as CanParseCss] = value.trim();