Initial commit
This commit is contained in:
148
lib/utils/logger.ts
Normal file
148
lib/utils/logger.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import { config } from "../config";
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 0,
|
||||
INFO = 1,
|
||||
WARN = 2,
|
||||
ERROR = 3,
|
||||
}
|
||||
|
||||
export interface LogEntry {
|
||||
timestamp: string;
|
||||
level: LogLevel;
|
||||
message: string;
|
||||
context?: Record<string, unknown>;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
class Logger {
|
||||
private logLevel: LogLevel;
|
||||
|
||||
constructor() {
|
||||
this.logLevel =
|
||||
process.env.NODE_ENV === "development" ? LogLevel.DEBUG : LogLevel.INFO;
|
||||
}
|
||||
|
||||
private formatMessage(entry: LogEntry): string {
|
||||
const { timestamp, level, message, context, error } = entry;
|
||||
const levelName = LogLevel[level];
|
||||
const contextStr = context ? ` ${JSON.stringify(context)}` : "";
|
||||
const errorStr = error ? `\n${error.stack}` : "";
|
||||
|
||||
return `[${timestamp}] ${levelName}: ${message}${contextStr}${errorStr}`;
|
||||
}
|
||||
|
||||
private shouldLog(level: LogLevel): boolean {
|
||||
return level >= this.logLevel;
|
||||
}
|
||||
|
||||
private log(
|
||||
level: LogLevel,
|
||||
message: string,
|
||||
context?: Record<string, unknown>,
|
||||
error?: Error
|
||||
): void {
|
||||
if (!this.shouldLog(level)) return;
|
||||
|
||||
const entry: LogEntry = {
|
||||
timestamp: new Date().toISOString(),
|
||||
level,
|
||||
message,
|
||||
context,
|
||||
error,
|
||||
};
|
||||
|
||||
const formattedMessage = this.formatMessage(entry);
|
||||
|
||||
switch (level) {
|
||||
case LogLevel.DEBUG:
|
||||
console.debug(formattedMessage);
|
||||
break;
|
||||
case LogLevel.INFO:
|
||||
console.info(formattedMessage);
|
||||
break;
|
||||
case LogLevel.WARN:
|
||||
console.warn(formattedMessage);
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
console.error(formattedMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
// 在生产环境中,可以发送到外部日志服务
|
||||
if (process.env.NODE_ENV === "production" && level >= LogLevel.ERROR) {
|
||||
this.sendToExternalService(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private sendToExternalService(entry: LogEntry): void {
|
||||
// 这里可以集成 Sentry, LogRocket 等外部日志服务
|
||||
// 示例:发送到 Sentry
|
||||
if (process.env.SENTRY_DSN) {
|
||||
// Sentry.captureException(entry.error || new Error(entry.message))
|
||||
}
|
||||
}
|
||||
|
||||
debug(message: string, context?: Record<string, unknown>): void {
|
||||
this.log(LogLevel.DEBUG, message, context);
|
||||
}
|
||||
|
||||
info(message: string, context?: Record<string, unknown>): void {
|
||||
this.log(LogLevel.INFO, message, context);
|
||||
}
|
||||
|
||||
warn(
|
||||
message: string,
|
||||
context?: Record<string, unknown>,
|
||||
error?: Error
|
||||
): void {
|
||||
this.log(LogLevel.WARN, message, context, error);
|
||||
}
|
||||
|
||||
error(
|
||||
message: string,
|
||||
context?: Record<string, unknown>,
|
||||
error?: Error
|
||||
): void {
|
||||
this.log(LogLevel.ERROR, message, context, error);
|
||||
}
|
||||
|
||||
// 记录 API 请求
|
||||
logApiRequest(
|
||||
method: string,
|
||||
url: string,
|
||||
statusCode: number,
|
||||
duration: number
|
||||
): void {
|
||||
this.info("API Request", {
|
||||
method,
|
||||
url,
|
||||
statusCode,
|
||||
duration: `${duration}ms`,
|
||||
});
|
||||
}
|
||||
|
||||
// 记录数据库操作
|
||||
logDbOperation(operation: string, table: string, duration: number): void {
|
||||
this.debug("Database Operation", {
|
||||
operation,
|
||||
table,
|
||||
duration: `${duration}ms`,
|
||||
});
|
||||
}
|
||||
|
||||
// 记录用户操作
|
||||
logUserAction(
|
||||
userId: string,
|
||||
action: string,
|
||||
details?: Record<string, unknown>
|
||||
): void {
|
||||
this.info("User Action", {
|
||||
userId,
|
||||
action,
|
||||
...details,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const logger = new Logger();
|
||||
Reference in New Issue
Block a user