diff --git a/database.go b/database.go index 03470b8..83862f7 100644 --- a/database.go +++ b/database.go @@ -6,12 +6,18 @@ import ( "fmt" "strconv" "strings" + "super-frpc/postLog" "time" _ "modernc.org/sqlite" ) var db *sql.DB +var logsDB *sql.DB + +func GetLogsDatabase() *sql.DB { + return logsDB +} type User struct { UserID int @@ -35,15 +41,23 @@ type FrpcInstance struct { CreatedBy string } -func InitDatabase(dbPath string) error { - InitUserDatabase(dbPath) - InitFrpcDatabase(dbPath) +func InitDatabase(dbPath_data string, dbPath_log string) error { + InitUserDatabase(dbPath_data) + InitFrpcDatabase(dbPath_data) + postLog.InitLogsDatabase(dbPath_log) return nil } func CloseDatabase() error { if db != nil { - return db.Close() + if err := db.Close(); err != nil { + return err + } + } + if logsDB != nil { + if err := logsDB.Close(); err != nil { + return err + } } return nil } diff --git a/main.go b/main.go index 8a9052a..8798f7f 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,8 @@ func main() { } postLog.Info(fmt.Sprintf("%s %s (Build %d.%s) by %s", softwareInfo.Name, softwareInfo.Version, softwareInfo.BuildVer, softwareInfo.BuildType, softwareInfo.Developer)) configPath := flag.String("config", "./config.json", "path to config file") - dbPath := flag.String("db", "./database.db", "path to database file") + dbPath_data := flag.String("db", "./database.db", "path to database file") + dbPath_log := flag.String("log", "./logs.db", "path to logs database file") flag.Parse() if _, err := os.Stat(*configPath); os.IsNotExist(err) { @@ -63,12 +64,12 @@ func main() { postLog.SetDebugMode(config.Debug) isDebug = config.Debug - if err := InitDatabase(*dbPath); err != nil { + if err := InitDatabase(*dbPath_data, *dbPath_log); err != nil { postLog.Fatal(fmt.Sprintf("Failed to initialize database: %v", err)) } postLog.Info("Database initialized successfully") - if err := InitFrpcDatabase(*dbPath); err != nil { + if err := InitFrpcDatabase(*dbPath_data); err != nil { postLog.Warning(fmt.Sprintf("Failed to initialize frpc database: %v", err)) } diff --git a/postLog/database.go b/postLog/database.go new file mode 100644 index 0000000..8b14db4 --- /dev/null +++ b/postLog/database.go @@ -0,0 +1,60 @@ +package postLog + +import ( + "database/sql" + "fmt" + "os" + "time" +) + +var ( + logsDB *sql.DB + tableName string +) + +func InitLogsDatabase(dbPath string) error { + var err error + logsDB, err = sql.Open("sqlite", dbPath) + if err != nil { + return fmt.Errorf("failed to open logs database: %w", err) + } + + if err = logsDB.Ping(); err != nil { + return fmt.Errorf("failed to ping logs database: %w", err) + } + + timestamp := time.Now().Format("20060102_150405") + tableName = fmt.Sprintf("logs_%s", timestamp) + + createTableSQL := fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + level INTEGER NOT NULL, + content TEXT NOT NULL, + timestamp TEXT NOT NULL DEFAULT (datetime('now')) + );`, tableName) + + _, err = logsDB.Exec(createTableSQL) + if err != nil { + return fmt.Errorf("failed to create logs table %s: %w", tableName, err) + } + + return nil +} + +func insertLogToDB(db *sql.DB, level int, content string, timestamp string) { + if db != nil { + _, err := db.Exec(fmt.Sprintf(`INSERT INTO %s (level, content, timestamp) VALUES (%d, '%s', '%s')`, tableName, + level, content, timestamp)) + // fmt.Fprintf(os.Stderr, `INSERT INTO %s (level, content, timestamp) VALUES (%d, '%s', '%s')`, tableName, level, content, timestamp) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write log to database: %v\n", err) + } + } +} + +func SetLogsDatabase(db *sql.DB) { + loggerMutex.Lock() + defer loggerMutex.Unlock() + logsDB = db +} diff --git a/postLog/postLog.go b/postLog/postLog.go index 9c9e36a..c4fba38 100644 --- a/postLog/postLog.go +++ b/postLog/postLog.go @@ -48,28 +48,23 @@ func PostLog(message string, level int) { // Lock to make reading debug flag and all output atomic across threads loggerMutex.Lock() - defer loggerMutex.Unlock() // Skip DEBUG when debug is off if idx == DEBUG && !isDebug { + loggerMutex.Unlock() return } // Colored output levelDisplay := colorOut_256(levelNames[idx], levelColors[idx]) - switch idx { - case DEBUG: - fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) - case INFO: - fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) - case WARNING: - fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) - case ERROR: - fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) - case FATAL: - fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) - } + // Copy logsDB to avoid holding the lock during DB operation + db := logsDB + + loggerMutex.Unlock() + + fmt.Printf("[%s - %s] %s\n", timeNow, levelDisplay, message) + insertLogToDB(db, level, message, timeNow) } // Helper functions for different log levels diff --git a/userAct.go b/userAct.go index ecd65fd..bee1a83 100644 --- a/userAct.go +++ b/userAct.go @@ -357,6 +357,7 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) { "username": user.Username, "type": user.Type, }) + postLog.Info(fmt.Sprintf("[CreateUserHandler] User \"%s\" created successfully with ID: %d", req.Username, userID)) } func RemoveUserHandler(w http.ResponseWriter, r *http.Request) {