mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-06 05:38:44 +08:00
feat: Add log query functionality and enhance logging system
This commit is contained in:
3
db.ts
3
db.ts
@@ -136,7 +136,8 @@ export enum UserPermission {
|
|||||||
DeleteGallery = 1 << 2,
|
DeleteGallery = 1 << 2,
|
||||||
ManageTasks = 1 << 3,
|
ManageTasks = 1 << 3,
|
||||||
ShareGallery = 1 << 4,
|
ShareGallery = 1 << 4,
|
||||||
All = ~(~0 << 5),
|
QueryLog = 1 << 5,
|
||||||
|
All = ~(~0 << 6),
|
||||||
}
|
}
|
||||||
export type User = {
|
export type User = {
|
||||||
id: number | bigint;
|
id: number | bigint;
|
||||||
|
|||||||
43
routes/api/log.ts
Normal file
43
routes/api/log.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { Handlers } from "$fresh/server.ts";
|
||||||
|
import { return_data, return_error } from "../../server/utils.ts";
|
||||||
|
import { User, UserPermission } from "../../db.ts";
|
||||||
|
import { parse_int } from "../../server/parse_form.ts";
|
||||||
|
import { base_logger, LogLevel } from "../../utils/logger.ts";
|
||||||
|
|
||||||
|
export const handler: Handlers = {
|
||||||
|
async GET(req, ctx) {
|
||||||
|
const user = <User | undefined> ctx.state.user;
|
||||||
|
if (
|
||||||
|
user && !user.is_admin &&
|
||||||
|
!(Number(user.permissions) & UserPermission.QueryLog)
|
||||||
|
) {
|
||||||
|
return return_error(403, "Permission denied.");
|
||||||
|
}
|
||||||
|
const u = new URL(req.url);
|
||||||
|
const params = u.searchParams;
|
||||||
|
const page = await parse_int(params.get("page"), null);
|
||||||
|
const limit = await parse_int(params.get("limit"), 50);
|
||||||
|
const offset = await parse_int(params.get("offset"), 0);
|
||||||
|
const type = params.get("type");
|
||||||
|
const min_level = await parse_int(
|
||||||
|
params.get("min_level"),
|
||||||
|
LogLevel.Log,
|
||||||
|
);
|
||||||
|
const allowed_level = params.get("allowed_level")?.split(",").map((x) =>
|
||||||
|
parseInt(x)
|
||||||
|
).filter((x) => !isNaN(x));
|
||||||
|
const datas = page === null
|
||||||
|
? base_logger.list(offset, limit, type, min_level, allowed_level)
|
||||||
|
: base_logger.list_page(
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
type,
|
||||||
|
min_level,
|
||||||
|
allowed_level,
|
||||||
|
);
|
||||||
|
const count = page === null
|
||||||
|
? undefined
|
||||||
|
: base_logger.count(type, min_level, allowed_level);
|
||||||
|
return return_data({ datas, count });
|
||||||
|
},
|
||||||
|
};
|
||||||
194
utils/logger.ts
194
utils/logger.ts
@@ -1,7 +1,7 @@
|
|||||||
import { join } from "@std/path";
|
import { join } from "@std/path";
|
||||||
import { format as format_ver, parse as parse_ver } from "@std/semver";
|
import { format as format_ver, parse as parse_ver } from "@std/semver";
|
||||||
import { parse_bool, stackTrace } from "../utils.ts";
|
import { parse_bool, stackTrace } from "../utils.ts";
|
||||||
import { Db, SqliteMaster } from "./db_interface.ts";
|
import { Db, QueryParameterSet, SqliteMaster } from "./db_interface.ts";
|
||||||
|
|
||||||
const ALL_TABLES = [
|
const ALL_TABLES = [
|
||||||
"version",
|
"version",
|
||||||
@@ -21,12 +21,32 @@ const LOG_TABLE = `CREATE TABLE log (
|
|||||||
stack TEXT
|
stack TEXT
|
||||||
);`;
|
);`;
|
||||||
|
|
||||||
export const TRACE_LEVEL = 1;
|
export type LogEntry = {
|
||||||
export const DEBUG_LEVEL = 2;
|
id: number | bigint;
|
||||||
export const LOG_LEVEL = 3;
|
time: Date;
|
||||||
export const INFO_LEVEL = 4;
|
message: string;
|
||||||
export const WARN_LEVEL = 5;
|
level: LogLevel;
|
||||||
export const ERROR_LEVEL = 6;
|
type: string;
|
||||||
|
stack?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogEntryRaw = {
|
||||||
|
id: number | bigint;
|
||||||
|
time: number | bigint;
|
||||||
|
message: string;
|
||||||
|
level: number | bigint;
|
||||||
|
type: string;
|
||||||
|
stack: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enum LogLevel {
|
||||||
|
Trace = 1,
|
||||||
|
Debug = 2,
|
||||||
|
Log = 3,
|
||||||
|
Info = 4,
|
||||||
|
Warn = 5,
|
||||||
|
Error = 6,
|
||||||
|
}
|
||||||
|
|
||||||
export function format_message(
|
export function format_message(
|
||||||
message: unknown[],
|
message: unknown[],
|
||||||
@@ -115,10 +135,10 @@ class BaseLogger {
|
|||||||
this.#fallback(type, level, ...messages);
|
this.#fallback(type, level, ...messages);
|
||||||
if (!this.db) return;
|
if (!this.db) return;
|
||||||
const message = format_message(messages);
|
const message = format_message(messages);
|
||||||
const stack =
|
const stack = (level >= LogLevel.Trace && level < LogLevel.Debug) ||
|
||||||
(level >= TRACE_LEVEL && level < DEBUG_LEVEL) || level >= WARN_LEVEL
|
level >= LogLevel.Warn
|
||||||
? stackTrace(2)
|
? stackTrace(2)
|
||||||
: undefined;
|
: undefined;
|
||||||
this.db.query(
|
this.db.query(
|
||||||
"INSERT INTO log (time, message, level, type, stack) VALUES (?, ?, ?, ?, ?);",
|
"INSERT INTO log (time, message, level, type, stack) VALUES (?, ?, ?, ?, ?);",
|
||||||
[
|
[
|
||||||
@@ -134,40 +154,80 @@ class BaseLogger {
|
|||||||
this.db?.close();
|
this.db?.close();
|
||||||
this.db = undefined;
|
this.db = undefined;
|
||||||
}
|
}
|
||||||
|
#convert(d: LogEntryRaw[]): LogEntry[] {
|
||||||
|
return d.map((x) => {
|
||||||
|
return {
|
||||||
|
id: x.id,
|
||||||
|
time: new Date(Number(x.time)),
|
||||||
|
message: x.message,
|
||||||
|
level: Number(x.level),
|
||||||
|
type: x.type,
|
||||||
|
stack: x.stack === null ? undefined : x.stack,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
count(type?: string | null, min_level?: number, allowed_level?: number[]) {
|
||||||
|
if (!this.db) return 0;
|
||||||
|
const where = [];
|
||||||
|
const args: QueryParameterSet = [];
|
||||||
|
if (type) {
|
||||||
|
where.push("type = ?");
|
||||||
|
args.push(type);
|
||||||
|
}
|
||||||
|
if (min_level) {
|
||||||
|
where.push("level >= ?");
|
||||||
|
args.push(min_level);
|
||||||
|
}
|
||||||
|
if (allowed_level) {
|
||||||
|
where.push(
|
||||||
|
"level IN (" + allowed_level.map(() => "?").join(",") + ")",
|
||||||
|
);
|
||||||
|
args.push(...allowed_level);
|
||||||
|
}
|
||||||
|
const where_str = where.length ? " WHERE " + where.join(" AND ") : "";
|
||||||
|
const cur = this.db.query<[number | bigint]>(
|
||||||
|
`SELECT COUNT(*) FROM log${where_str};`,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
for (const i of cur) {
|
||||||
|
return i[0];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
debug(type: string, ...messages: unknown[]) {
|
debug(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, DEBUG_LEVEL, ...messages);
|
this.add(type, LogLevel.Debug, ...messages);
|
||||||
}
|
}
|
||||||
error(type: string, ...messages: unknown[]) {
|
error(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, ERROR_LEVEL, ...messages);
|
this.add(type, LogLevel.Error, ...messages);
|
||||||
}
|
}
|
||||||
#fallback(type: string, level: number, ...messages: unknown[]) {
|
#fallback(type: string, level: number, ...messages: unknown[]) {
|
||||||
if (type === "default") {
|
if (type === "default") {
|
||||||
if (level >= ERROR_LEVEL) {
|
if (level >= LogLevel.Error) {
|
||||||
console.error(...messages, "\n" + stackTrace(3));
|
console.error(...messages, "\n" + stackTrace(3));
|
||||||
} else if (level >= WARN_LEVEL) {
|
} else if (level >= LogLevel.Warn) {
|
||||||
console.warn(...messages, "\n" + stackTrace(3));
|
console.warn(...messages, "\n" + stackTrace(3));
|
||||||
} else if (level >= INFO_LEVEL) {
|
} else if (level >= LogLevel.Info) {
|
||||||
console.info(...messages);
|
console.info(...messages);
|
||||||
} else if (level >= LOG_LEVEL) {
|
} else if (level >= LogLevel.Log) {
|
||||||
console.log(...messages);
|
console.log(...messages);
|
||||||
} else if (level >= DEBUG_LEVEL) {
|
} else if (level >= LogLevel.Debug) {
|
||||||
console.debug(...messages);
|
console.debug(...messages);
|
||||||
} else if (level >= TRACE_LEVEL) {
|
} else if (level >= LogLevel.Trace) {
|
||||||
console.log("Trace:", ...messages, "\n" + stackTrace(3));
|
console.log("Trace:", ...messages, "\n" + stackTrace(3));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (level >= ERROR_LEVEL) {
|
if (level >= LogLevel.Error) {
|
||||||
console.error(type + ":", ...messages, "\n" + stackTrace(3));
|
console.error(type + ":", ...messages, "\n" + stackTrace(3));
|
||||||
} else if (level >= WARN_LEVEL) {
|
} else if (level >= LogLevel.Warn) {
|
||||||
console.warn(type + ":", ...messages, "\n" + stackTrace(3));
|
console.warn(type + ":", ...messages, "\n" + stackTrace(3));
|
||||||
} else if (level >= INFO_LEVEL) {
|
} else if (level >= LogLevel.Info) {
|
||||||
console.info(type + ":", ...messages);
|
console.info(type + ":", ...messages);
|
||||||
} else if (level >= LOG_LEVEL) {
|
} else if (level >= LogLevel.Log) {
|
||||||
console.log(type + ":", ...messages);
|
console.log(type + ":", ...messages);
|
||||||
} else if (level >= DEBUG_LEVEL) {
|
} else if (level >= LogLevel.Debug) {
|
||||||
console.debug(type + ":", ...messages);
|
console.debug(type + ":", ...messages);
|
||||||
} else if (level >= TRACE_LEVEL) {
|
} else if (level >= LogLevel.Trace) {
|
||||||
console.log(
|
console.log(
|
||||||
"Trace:",
|
"Trace:",
|
||||||
type + ":",
|
type + ":",
|
||||||
@@ -180,16 +240,80 @@ class BaseLogger {
|
|||||||
return new Logger(this, type);
|
return new Logger(this, type);
|
||||||
}
|
}
|
||||||
info(type: string, ...messages: unknown[]) {
|
info(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, INFO_LEVEL, ...messages);
|
this.add(type, LogLevel.Info, ...messages);
|
||||||
|
}
|
||||||
|
list(
|
||||||
|
offset: number = 0,
|
||||||
|
limit: number = 50,
|
||||||
|
type?: string | null,
|
||||||
|
min_level?: number,
|
||||||
|
allowed_level?: number[],
|
||||||
|
) {
|
||||||
|
if (!this.db) return [];
|
||||||
|
const where = [];
|
||||||
|
const args: QueryParameterSet = [];
|
||||||
|
if (type) {
|
||||||
|
where.push("type = ?");
|
||||||
|
args.push(type);
|
||||||
|
}
|
||||||
|
if (min_level) {
|
||||||
|
where.push("level >= ?");
|
||||||
|
args.push(min_level);
|
||||||
|
}
|
||||||
|
if (allowed_level) {
|
||||||
|
where.push(
|
||||||
|
"level IN (" + allowed_level.map(() => "?").join(",") + ")",
|
||||||
|
);
|
||||||
|
args.push(...allowed_level);
|
||||||
|
}
|
||||||
|
args.push(limit, offset);
|
||||||
|
const where_str = where.length ? " WHERE " + where.join(" AND ") : "";
|
||||||
|
const cur = this.db.queryEntries<LogEntryRaw>(
|
||||||
|
`SELECT * FROM log${where_str} ORDER BY id DESC LIMIT ? OFFSET ?;`,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
return this.#convert(cur);
|
||||||
|
}
|
||||||
|
list_page(
|
||||||
|
page: number = 0,
|
||||||
|
page_size: number = 50,
|
||||||
|
type?: string | null,
|
||||||
|
min_level?: number,
|
||||||
|
allowed_level?: number[],
|
||||||
|
) {
|
||||||
|
if (!this.db) return [];
|
||||||
|
const where = [];
|
||||||
|
const args: QueryParameterSet = [];
|
||||||
|
if (type) {
|
||||||
|
where.push("type = ?");
|
||||||
|
args.push(type);
|
||||||
|
}
|
||||||
|
if (min_level) {
|
||||||
|
where.push("level >= ?");
|
||||||
|
args.push(min_level);
|
||||||
|
}
|
||||||
|
if (allowed_level) {
|
||||||
|
where.push(
|
||||||
|
"level IN (" + allowed_level.map(() => "?").join(",") + ")",
|
||||||
|
);
|
||||||
|
args.push(...allowed_level);
|
||||||
|
}
|
||||||
|
args.push(page_size, (page - 1) * page_size);
|
||||||
|
const where_str = where.length ? " WHERE " + where.join(" AND ") : "";
|
||||||
|
const cur = this.db.queryEntries<LogEntryRaw>(
|
||||||
|
`SELECT * FROM log${where_str} ORDER BY id DESC LIMIT ? OFFSET ?;`,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
return this.#convert(cur);
|
||||||
}
|
}
|
||||||
log(type: string, ...messages: unknown[]) {
|
log(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, LOG_LEVEL, ...messages);
|
this.add(type, LogLevel.Log, ...messages);
|
||||||
}
|
}
|
||||||
trace(type: string, ...messages: unknown[]) {
|
trace(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, TRACE_LEVEL, ...messages);
|
this.add(type, LogLevel.Trace, ...messages);
|
||||||
}
|
}
|
||||||
warn(type: string, ...messages: unknown[]) {
|
warn(type: string, ...messages: unknown[]) {
|
||||||
this.add(type, WARN_LEVEL, ...messages);
|
this.add(type, LogLevel.Warn, ...messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,22 +325,22 @@ class Logger {
|
|||||||
this.#type = type;
|
this.#type = type;
|
||||||
}
|
}
|
||||||
debug(...messages: unknown[]) {
|
debug(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, DEBUG_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Debug, ...messages);
|
||||||
}
|
}
|
||||||
error(...messages: unknown[]) {
|
error(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, ERROR_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Error, ...messages);
|
||||||
}
|
}
|
||||||
info(...messages: unknown[]) {
|
info(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, INFO_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Info, ...messages);
|
||||||
}
|
}
|
||||||
log(...messages: unknown[]) {
|
log(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, LOG_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Log, ...messages);
|
||||||
}
|
}
|
||||||
trace(...messages: unknown[]) {
|
trace(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, TRACE_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Trace, ...messages);
|
||||||
}
|
}
|
||||||
warn(...messages: unknown[]) {
|
warn(...messages: unknown[]) {
|
||||||
this.#base.add(this.#type, WARN_LEVEL, ...messages);
|
this.#base.add(this.#type, LogLevel.Warn, ...messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user