phantasmal-world/src/quest_editor/stores/LogStore.ts

158 lines
5.1 KiB
TypeScript
Raw Normal View History

2019-12-19 03:04:57 +08:00
import { ListProperty } from "../../core/observable/property/list/ListProperty";
import { Property } from "../../core/observable/property/Property";
import { list_property, property } from "../../core/observable";
import { Disposable } from "../../core/observable/Disposable";
import { Disposer } from "../../core/observable/Disposer";
import Logger from "js-logger";
import { enum_values } from "../../core/enums";
export type QuestLogger = {
readonly debug: (message: string) => void;
readonly info: (message: string) => void;
readonly warning: (message: string) => void;
readonly error: (message: string) => void;
};
// Log level names in order of importance.
export enum LogLevel {
Debug,
Info,
Warning,
Error,
}
export const LogLevels = enum_values<LogLevel>(LogLevel);
export type LogMessage = {
readonly time: Date;
2019-12-19 03:04:57 +08:00
readonly message: string;
readonly level: LogLevel;
};
export class LogStore implements Disposable {
private readonly disposer = new Disposer();
private readonly default_log_level = LogLevel.Info;
private readonly message_buffer: LogMessage[] = [];
private readonly logger_name_buffer: string[] = [];
2019-12-19 03:04:57 +08:00
private readonly _log_messages = list_property<LogMessage>();
private readonly _log_level = property<LogLevel>(this.default_log_level);
readonly log_messages: ListProperty<LogMessage>;
readonly log_level: Property<LogLevel> = this._log_level;
constructor() {
this.log_messages = this._log_messages.filtered(
this.log_level.map(level => message => message.level >= level),
);
}
dispose(): void {
this.disposer.dispose();
}
set_log_level(log_level: LogLevel): void {
this._log_level.val = log_level;
}
/**
* @param name - js-logger logger name
*/
get_logger(name: string): QuestLogger {
return {
debug: (message: string): void => {
this.buffer_log_message(message, LogLevel.Debug, name);
2019-12-19 03:04:57 +08:00
},
info: (message: string): void => {
this.buffer_log_message(message, LogLevel.Info, name);
2019-12-19 03:04:57 +08:00
},
warning: (message: string): void => {
this.buffer_log_message(message, LogLevel.Warning, name);
2019-12-19 03:04:57 +08:00
},
error: (message: string): void => {
this.buffer_log_message(message, LogLevel.Error, name);
2019-12-19 03:04:57 +08:00
},
};
}
private buffer_log_message(message: string, level: LogLevel, logger_name: string): void {
this.message_buffer.push({
time: new Date(),
message,
level,
});
this.logger_name_buffer.push(logger_name);
this.add_buffered_log_messages();
}
private adding_log_messages?: number;
private add_buffered_log_messages(): void {
if (this.adding_log_messages != undefined) return;
this.adding_log_messages = requestAnimationFrame(() => {
const DROP_THRESHOLD = 500;
const DROP_THRESHOLD_HALF = DROP_THRESHOLD / 2;
const BATCH_SIZE = 200;
// Drop messages if there are too many.
if (this.message_buffer.length > DROP_THRESHOLD) {
const drop_len = this.message_buffer.length - DROP_THRESHOLD;
this.message_buffer.splice(DROP_THRESHOLD_HALF, drop_len, {
time: new Date(),
message: `...dropped ${drop_len} messages...`,
level: LogLevel.Warning,
});
this.logger_name_buffer.splice(
DROP_THRESHOLD_HALF,
drop_len,
"quest_editor/stores/LogStore",
);
}
const len = Math.min(BATCH_SIZE, this.message_buffer.length);
const buffered_messages = this.message_buffer.splice(0, len);
const buffered_logger_names = this.logger_name_buffer.splice(0, len);
this._log_messages.push(...buffered_messages);
for (let i = 0; i < len; i++) {
const { level, message } = buffered_messages[i];
const logger_name = buffered_logger_names[i];
switch (level) {
case LogLevel.Debug:
Logger.get(logger_name).debug(message);
break;
case LogLevel.Info:
Logger.get(logger_name).info(message);
break;
case LogLevel.Warning:
Logger.get(logger_name).warn(message);
break;
case LogLevel.Error:
Logger.get(logger_name).error(message);
break;
}
}
// Occasionally clean up old log messages if there are too many.
if (this._log_messages.length.val > 2000) {
this._log_messages.splice(0, 1000);
}
this.adding_log_messages = undefined;
if (this.message_buffer.length) {
this.add_buffered_log_messages();
}
});
}
2019-12-19 03:04:57 +08:00
}
export const log_store = new LogStore();