Update Database
Database is more usable now. All pages have been updated to use the database, and share an application configuration. Page Stack has been removed, no more pages hanging around in memory. Replaced with a 'Router' which uses an Enum to determine which page should be displayed, destroys the old page and initializes the new page all in one go. No more push, pop, rollback, etc. No more holding instances of pages. Logger has been updated with proper timestamps and sorting now works as expected."
This commit is contained in:
+22
-59
@@ -4,10 +4,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"rhemawavetech.com/rhemawave/internal/db"
|
||||
)
|
||||
|
||||
type Level int
|
||||
@@ -24,78 +24,34 @@ func (l Level) String() string {
|
||||
return [...]string{"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"}[l]
|
||||
}
|
||||
|
||||
type logEntry struct {
|
||||
timestamp string
|
||||
level string
|
||||
message string
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
db *gorm.DB
|
||||
DB *gorm.DB
|
||||
file *os.File
|
||||
console = log.New(os.Stderr, "", 0)
|
||||
|
||||
dbChan chan logEntry
|
||||
dbChanOnce sync.Once
|
||||
)
|
||||
|
||||
// startDBWriter starts a single background goroutine to drain log entries to the database.
|
||||
func startDBWriter() {
|
||||
dbChan = make(chan logEntry, 256)
|
||||
go func() {
|
||||
for entry := range dbChan {
|
||||
row := map[string]any{
|
||||
"timestamp": entry.timestamp,
|
||||
"level": entry.level,
|
||||
"message": entry.message,
|
||||
}
|
||||
if err := db.Table("log_entries").Create(row).Error; err != nil {
|
||||
mu.Lock()
|
||||
console.Printf("Failed to write log to database: %v", err)
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// AddFile attaches or replaces the file backend
|
||||
func AddFile(path string) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
if file != nil {
|
||||
file.Close()
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
_, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file = f
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDatabase attaches or replaces the database backend
|
||||
func AddDatabase(d *gorm.DB) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
db = d
|
||||
dbChanOnce.Do(startDBWriter)
|
||||
console.Println("Adding database to logger")
|
||||
DB = d
|
||||
}
|
||||
|
||||
// Close shuts down the database writer goroutine and closes the file backend.
|
||||
// Close shuts down the file backend.
|
||||
func Close() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
// Stop the DB writer goroutine by closing the channel
|
||||
if dbChan != nil {
|
||||
close(dbChan)
|
||||
dbChan = nil
|
||||
db = nil
|
||||
}
|
||||
|
||||
if file != nil {
|
||||
err := file.Close()
|
||||
file = nil
|
||||
@@ -106,24 +62,31 @@ func Close() error {
|
||||
|
||||
func logMsg(level Level, format string, args ...any) {
|
||||
message := fmt.Sprintf(format, args...)
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
now := time.Now()
|
||||
timestamp := now.Format("2006-01-02 15:04:05.000")
|
||||
line := fmt.Sprintf("%s [%s] %s", timestamp, level, message)
|
||||
|
||||
mu.Lock()
|
||||
// 1. The standard log package is internally thread-safe
|
||||
console.Println(line)
|
||||
|
||||
// 2. Write to file
|
||||
if file != nil {
|
||||
fmt.Fprintln(file, line)
|
||||
}
|
||||
|
||||
if db != nil && dbChan != nil { // both cleared by Close()
|
||||
select {
|
||||
case dbChan <- logEntry{timestamp: timestamp, level: level.String(), message: message}:
|
||||
default:
|
||||
// Channel full, drop the DB write rather than blocking
|
||||
// 3. Write to DB using GORM. It handles its own connection pooling and locking.
|
||||
if DB != nil {
|
||||
var entry db.Log
|
||||
entry.Timestamp = now.UnixMilli()
|
||||
entry.Level = level.String()
|
||||
entry.Message = message
|
||||
|
||||
// Use Save() to insert the new record.
|
||||
result := DB.Save(&entry)
|
||||
if result.Error != nil {
|
||||
console.Printf("Failed to write log to database: %v\n", result.Error)
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func Debug(format string, args ...any) { logMsg(LevelDebug, format, args...) }
|
||||
|
||||
Reference in New Issue
Block a user