summaryrefslogtreecommitdiff
path: root/logger.ts
diff options
context:
space:
mode:
Diffstat (limited to 'logger.ts')
-rw-r--r--logger.ts141
1 files changed, 134 insertions, 7 deletions
diff --git a/logger.ts b/logger.ts
index 5fbafa3..56192a1 100644
--- a/logger.ts
+++ b/logger.ts
@@ -1,27 +1,154 @@
type LogLevel = "INFO" | "WARN" | "ERROR" | "DEBUG";
+type LogDomain = "server" | "upload" | "download" | "security" | "cleanup" | "request";
+
+interface LogEntry {
+ timestamp: string;
+ level: LogLevel;
+ domain: LogDomain;
+ message: string;
+ meta?: Record<string, unknown>;
+}
class Logger {
- private log(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ private logDir = "./logs";
+ private currentDate = "";
+ private logBuffer: string[] = [];
+ private flushInterval: number;
+
+ constructor() {
+ this.ensureLogDir();
+ // Flush logs every 5 seconds
+ this.flushInterval = setInterval(() => this.flush(), 5000);
+ }
+
+ private async ensureLogDir() {
+ try {
+ await Deno.mkdir(this.logDir, { recursive: true });
+ } catch (error) {
+ if (!(error instanceof Deno.errors.AlreadyExists)) {
+ console.error("Failed to create log directory:", error);
+ }
+ }
+ }
+
+ private getDateString(): string {
+ const now = new Date();
+ return now.toISOString().split('T')[0]; // YYYY-MM-DD
+ }
+
+ private formatLogEntry(entry: LogEntry): string {
+ const metaStr = entry.meta ? ` ${JSON.stringify(entry.meta)}` : "";
+ return `[${entry.timestamp}] [${entry.level}] [${entry.domain}] ${entry.message}${metaStr}\n`;
+ }
+
+ private async writeToFile(domain: LogDomain, content: string) {
+ const date = this.getDateString();
+ const filename = `${this.logDir}/${domain}-${date}.log`;
+
+ try {
+ await Deno.writeTextFile(filename, content, { append: true });
+ } catch (error) {
+ console.error(`Failed to write to log file ${filename}:`, error);
+ }
+ }
+
+ private log(level: LogLevel, domain: LogDomain, message: string, meta?: Record<string, unknown>) {
const timestamp = new Date().toISOString();
- const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
- console.log(`[${timestamp}] [${level}] ${message}${metaStr}`);
+ const entry: LogEntry = { timestamp, level, domain, message, meta };
+
+ // Write to console
+ const formatted = this.formatLogEntry(entry);
+ console.log(formatted.trim());
+
+ // Buffer for file writing
+ this.logBuffer.push(JSON.stringify({ ...entry, file: domain }));
}
+ private async flush() {
+ if (this.logBuffer.length === 0) return;
+
+ const entries = [...this.logBuffer];
+ this.logBuffer = [];
+
+ // Group entries by domain
+ const byDomain = new Map<LogDomain, LogEntry[]>();
+
+ for (const entryStr of entries) {
+ try {
+ const entry = JSON.parse(entryStr);
+ const domain = entry.file as LogDomain;
+ if (!byDomain.has(domain)) {
+ byDomain.set(domain, []);
+ }
+ byDomain.get(domain)!.push(entry);
+ } catch (error) {
+ console.error("Failed to parse log entry:", error);
+ }
+ }
+
+ // Write to files
+ for (const [domain, domainEntries] of byDomain) {
+ const content = domainEntries.map(e => this.formatLogEntry(e)).join('');
+ await this.writeToFile(domain, content);
+ }
+ }
+
+ // Server domain logs
+ server(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "server", message, meta);
+ }
+
+ // Upload domain logs
+ upload(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "upload", message, meta);
+ }
+
+ // Download domain logs
+ download(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "download", message, meta);
+ }
+
+ // Security domain logs (rate limiting, IP tracking)
+ security(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "security", message, meta);
+ }
+
+ // Cleanup domain logs
+ cleanup(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "cleanup", message, meta);
+ }
+
+ // Request domain logs (HTTP requests)
+ request(level: LogLevel, message: string, meta?: Record<string, unknown>) {
+ this.log(level, "request", message, meta);
+ }
+
+ // Legacy methods for backward compatibility
info(message: string, meta?: Record<string, unknown>) {
- this.log("INFO", message, meta);
+ this.log("INFO", "server", message, meta);
}
warn(message: string, meta?: Record<string, unknown>) {
- this.log("WARN", message, meta);
+ this.log("WARN", "server", message, meta);
}
error(message: string, meta?: Record<string, unknown>) {
- this.log("ERROR", message, meta);
+ this.log("ERROR", "server", message, meta);
}
debug(message: string, meta?: Record<string, unknown>) {
- this.log("DEBUG", message, meta);
+ this.log("DEBUG", "server", message, meta);
+ }
+
+ async shutdown() {
+ clearInterval(this.flushInterval);
+ await this.flush();
}
}
export const logger = new Logger();
+
+// Ensure logs are flushed on exit
+addEventListener("unload", () => {
+ logger.shutdown();
+});