package log import ( "fmt" "os" "time" "github.com/jmoiron/sqlx" ) type ( Logger struct { DB *sqlx.DB } Log struct { ID string `json:"id" db:"id"` Level LogLevel `json:"level" db:"level"` Type string `json:"type" db:"type"` Content string `json:"content" db:"content"` CreatedAt time.Time `json:"created_at" db:"created_at"` } ) const ( TYPE_ACCOUNT string = "account" TYPE_MUSIC string = "music" TYPE_ARTIST string = "artist" TYPE_BLOG string = "blog" TYPE_ARTWORK string = "artwork" TYPE_FILES string = "files" TYPE_MISC string = "misc" ) type LogLevel int const ( LEVEL_INFO LogLevel = 0 LEVEL_WARN LogLevel = 1 ) const DEFAULT_LOG_PAGE_LENGTH = 25 func (self *Logger) Info(logType string, format string, args ...any) { logString := fmt.Sprintf(format, args...) fmt.Printf("[%s] [%s] INFO: %s\n", time.Now().Format(time.UnixDate), logType, logString) err := createLog(self.DB, LEVEL_INFO, logType, logString) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to push log to database: %v\n", err) } } func (self *Logger) Warn(logType string, format string, args ...any) { logString := fmt.Sprintf(format, args...) fmt.Fprintf(os.Stderr, "[%s] [%s] WARN: %s\n", time.Now().Format(time.UnixDate), logType, logString) err := createLog(self.DB, LEVEL_WARN, logType, logString) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to push log to database: %v\n", err) } } func (self *Logger) Fetch(id string) (*Log, error) { log := Log{} err := self.DB.Get(&log, "SELECT * FROM auditlog WHERE id=$1", id) return &log, err } func (self *Logger) Search(levelFilters []LogLevel, typeFilters []string, content string, limit int, offset int) ([]*Log, error) { logs := []*Log{} params := []any{ limit, offset } conditions := "" if len(content) > 0 { content = "%" + content + "%" conditions += " WHERE content LIKE $3" params = append(params, content) } if len(levelFilters) > 0 { if len(conditions) > 0 { conditions += " AND level IN (" } else { conditions += " WHERE level IN (" } for i := range levelFilters { conditions += fmt.Sprintf("$%d", len(params) + 1) if i < len(levelFilters) - 1 { conditions += "," } params = append(params, levelFilters[i]) } conditions += ")" } if len(typeFilters) > 0 { if len(conditions) > 0 { conditions += " AND type IN (" } else { conditions += " WHERE type IN (" } for i := range typeFilters { conditions += fmt.Sprintf("$%d", len(params) + 1) if i < len(typeFilters) - 1 { conditions += "," } params = append(params, typeFilters[i]) } conditions += ")" } query := fmt.Sprintf( "SELECT * FROM auditlog%s ORDER BY created_at DESC LIMIT $1 OFFSET $2", conditions, ) /* fmt.Printf("%s (", query) for i, param := range params { fmt.Print(param) if i < len(params) - 1 { fmt.Print(", ") } } fmt.Print(")\n") */ err := self.DB.Select(&logs, query, params...) if err != nil { return nil, err } return logs, nil } func createLog(db *sqlx.DB, logLevel LogLevel, logType string, content string) error { _, err := db.Exec( "INSERT INTO auditlog (level, type, content) VALUES ($1,$2,$3)", logLevel, logType, content, ) return err }