Go: add audit log framework (#17129)

### Summary

Prepare for audit log

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-07-20 23:50:45 +08:00
committed by GitHub
parent f45f03a016
commit 3670b047f0
11 changed files with 229 additions and 6 deletions

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"net/url"
"ragflow/internal/common"
"strconv"
)
// PingServer pings the server to check if it's alive
@@ -2550,6 +2551,37 @@ func (c *CLI) AdminListUserDefaultModelsCommand(cmd *Command) (ResponseIf, error
return HandleCommonResponse(resp, fmt.Sprintf("list user %s default models", userName))
}
// AdminListUserLogsCommand list user operation logs
func (c *CLI) AdminListUserLogsCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != AdminMode || c.AdminServerClient.LoginToken == nil {
return nil, fmt.Errorf("this command is only allowed in ADMIN mode or already login")
}
userName, ok := cmd.Params["user_name"].(string)
if !ok {
return nil, fmt.Errorf("user_name not provided")
}
days, ok := cmd.Params["days"].(int)
if !ok {
return nil, fmt.Errorf("days not provided")
}
q := url.Values{}
q.Set("user_name", userName)
q.Set("days", strconv.Itoa(days))
baseUrl := fmt.Sprintf("/admin/logs?%s", q.Encode())
resp, err := c.AdminServerClient.Request("GET", baseUrl, "admin", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to list user %s logs: %w", userName, err)
}
return HandleCommonResponse(resp, fmt.Sprintf("list user %s logs", userName))
}
func (c *CLI) AdminStopUserIngestionTasksCommand(cmd *Command) (ResponseIf, error) {
if c.Config.CLIMode != AdminMode || c.AdminServerClient.LoginToken == nil {

View File

@@ -3191,10 +3191,12 @@ func (p *Parser) parseAdminListUserCommand() (*Command, error) {
case TokenProviders:
p.nextToken()
cmd = NewCommand("admin_list_user_providers")
case TokenLogs:
return p.parseAdminListUserLogs(userName)
case TokenDefault:
return p.parseAdminListUserDefaultModels(userName)
default:
return nil, fmt.Errorf("expected INGESTION or DATASETS or AGENTS or CHATS or SEARCHES or MODELS or FILES or KEYS after USER")
return nil, fmt.Errorf("expected INGESTION or DATASETS or AGENTS or CHATS or SEARCHES or MODELS or FILES or KEYS or LOGS after USER")
}
// Semicolon is optional
@@ -3299,6 +3301,31 @@ func (p *Parser) parseAdminListUserDefaultModels(userName string) (*Command, err
return cmd, nil
}
// LIST USER 'user_name' LOGS;
// LIST USER 'user_name' LOGS 10;
func (p *Parser) parseAdminListUserLogs(userName string) (*Command, error) {
p.nextToken() // consume LOGS
dayCount := 7
var err error
cmd := NewCommand("admin_list_user_operation_logs")
if p.curToken.Type == TokenNumber {
dayCount, err = p.parseNumber()
if err != nil {
return nil, err
}
p.nextToken()
}
cmd.Params["user_name"] = userName
cmd.Params["days"] = dayCount
if p.curToken.Type == TokenSemicolon {
p.nextToken()
}
return cmd, nil
}
// STOP USER 'user@example.com' INGESTION TASKS 'created';
func (p *Parser) parseAdminStopUserCommand() (*Command, error) {
p.nextToken() // consume USER

View File

@@ -259,6 +259,8 @@ func (c *CLI) ExecuteAdminCommand(cmd *Command) (ResponseIf, error) {
return c.AdminListUserProviderInstanceModelsCommand(cmd)
case "admin_list_user_default_models":
return c.AdminListUserDefaultModelsCommand(cmd)
case "admin_list_user_operation_logs":
return c.AdminListUserLogsCommand(cmd)
case "admin_stop_user_ingestion_tasks_command":
return c.AdminStopUserIngestionTasksCommand(cmd)
case "admin_remove_user_ingestion_tasks_command":

View File

@@ -545,6 +545,8 @@ func (l *Lexer) lookupIdent(ident string) Token {
return Token{Type: TokenData, Value: ident}
case "LOG":
return Token{Type: TokenLog, Value: ident}
case "LOGS":
return Token{Type: TokenLogs, Value: ident}
case "LEVEL":
return Token{Type: TokenLevel, Value: ident}
case "DEBUG":

View File

@@ -204,6 +204,7 @@ const (
TokenPreview
TokenOpenaiChat
TokenLog
TokenLogs
TokenLevel
TokenDebug
TokenInfo