Skip to content

Commit 4436d10

Browse files
authored
feat: dump query from audit log table (#10)
Change-Id: I1c69c5e94032778c4b5eef7cdf5c32d85b796e4c
1 parent 96c1f00 commit 4436d10

10 files changed

+425
-111
lines changed

README.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ dorisdump dump --dump-schema --host <host> --port <port> --user root --password
2525
# Hint: Use '*' like '/path/to/fe.audit.log*' to match multiple logs
2626
dorisdump dump --dump-schema --dump-query --dbs db1 --audit-logs '/path/to/fe.audit.log,/path/to/fe.audit.log.20240802-1'
2727

28-
# Auto download audit log from remote (require SSH password or private key)
29-
dorisdump dump --dump-query --host <host> --port <port> --ssh-password '******'
28+
# Auto download audit log from remote FE (require SSH password or private key)
29+
dorisdump dump --dump-query --host <fe host> --port <fe port> --ssh-password '******'
30+
31+
# Dump queries from audit log table instead of files
32+
# Need to enable audit plugin on FE, see <https://doris.apache.org/docs/admin-manual/audit-plugin>
33+
dorisdump dump --dump-query --host <fe host> --port <fe port> --audit-log-table=audit_db.audit_table
3034

3135

3236
# Replay
@@ -51,6 +55,10 @@ dorisdump diff --help
5155
dorisdump diff replay1 replay2
5256
```
5357

58+
### Config
59+
60+
You may want to pass parameters by config file or environment, see `dorisdump --help` and [example](./example/example.dorisdump.yaml).
61+
5462
## Build
5563

5664
1. Install **optional** dependences:

cmd/dump.go

+76-16
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ import (
3939
var DumpConfig = Dump{}
4040

4141
type Dump struct {
42-
AuditLogPaths []string
42+
AuditLogPaths []string
43+
AuditLogTable string
44+
4345
AuditLogUnescape bool
4446
OutputDDLDir string
4547
OutputQueryDir string
@@ -60,6 +62,7 @@ type Dump struct {
6062
QueryStates []string
6163
OnlySelect bool
6264
Strict bool
65+
From, To string
6366

6467
Clean bool
6568
}
@@ -147,7 +150,10 @@ func init() {
147150
pFlags.StringSliceVar(&DumpConfig.QueryStates, "query-states", []string{}, "Dump queries with states, like 'ok', 'eof' and 'err'")
148151
pFlags.BoolVar(&DumpConfig.OnlySelect, "only-select", true, "Only dump SELECT queries")
149152
pFlags.BoolVarP(&DumpConfig.Strict, "strict", "s", false, "Filter out sqls that can't be parsed")
150-
pFlags.StringSliceVar(&DumpConfig.AuditLogPaths, "audit-logs", nil, "Audit log paths, either local path or ssh://xxx")
153+
pFlags.StringVar(&DumpConfig.From, "from", "", "Dump queries from this time, like '2006-01-02 15:04:05'")
154+
pFlags.StringVar(&DumpConfig.To, "to", "", "Dump queries to this time, like '2006-01-02 16:04:05'")
155+
pFlags.StringSliceVar(&DumpConfig.AuditLogPaths, "audit-logs", nil, "Scan query from audit log files, either local path or 'ssh://xxx'")
156+
pFlags.StringVar(&DumpConfig.AuditLogTable, "audit-log-table", "", "Scan query from audit log table, like 'audit_db.audit_tbl'")
151157
pFlags.BoolVar(&DumpConfig.AuditLogUnescape, "audit-log-unescape", true, "Unescape '\\n', '\\t' and '\\r' in audit log")
152158
pFlags.StringVar(&DumpConfig.AuditLogEncoding, "audit-log-encoding", "auto", "Audit log encoding, like utf8, gbk, ...")
153159
pFlags.StringVar(&DumpConfig.SSHAddress, "ssh-address", "", "SSH address for downloading audit log, default is 'root@{db_host}:22'")
@@ -168,10 +174,25 @@ func completeDumpConfig() error {
168174
DumpConfig.OutputQueryDir = filepath.Join(GlobalConfig.OutputDir, "sql")
169175
DumpConfig.LocalAuditLogCacheDir = filepath.Join(GlobalConfig.DataDir, "auditlog")
170176

177+
if DumpConfig.AuditLogTable != "" && !strings.Contains(DumpConfig.AuditLogTable, ".") {
178+
return errors.New("Need to specific database in '--audit-log-table', like 'audit_db.audit_tbl'")
179+
}
180+
171181
if DumpConfig.QueryMinDuration_ > 0 {
172182
DumpConfig.QueryMinDurationMs = int(DumpConfig.QueryMinDuration_.Milliseconds())
173183
}
174184

185+
if DumpConfig.From != "" {
186+
if _, err := time.Parse(time.DateTime, DumpConfig.From); err != nil {
187+
return err
188+
}
189+
}
190+
if DumpConfig.To != "" {
191+
if _, err := time.Parse(time.DateTime, DumpConfig.To); err != nil {
192+
return err
193+
}
194+
}
195+
175196
GlobalConfig.DBs, GlobalConfig.Tables = lo.Uniq(GlobalConfig.DBs), lo.Uniq(GlobalConfig.Tables)
176197
dbs, tables := GlobalConfig.DBs, GlobalConfig.Tables
177198
if DumpConfig.DumpSchema && len(dbs) == 0 {
@@ -336,11 +357,57 @@ func outputSchemas(schemas []*src.DBSchema) error {
336357
}
337358

338359
func dumpQueries(ctx context.Context) ([][]string, error) {
360+
opts := src.AuditLogScanOpts{
361+
DBs: GlobalConfig.DBs,
362+
QueryMinDurationMs: DumpConfig.QueryMinDurationMs,
363+
QueryStates: DumpConfig.QueryStates,
364+
Unique: DumpConfig.QueryOutputMode == "unique",
365+
UniqueNormalize: DumpConfig.QueryUniqueNormalize,
366+
Unescape: DumpConfig.AuditLogUnescape,
367+
OnlySelect: DumpConfig.OnlySelect,
368+
Strict: DumpConfig.Strict,
369+
From: DumpConfig.From,
370+
To: DumpConfig.To,
371+
}
372+
373+
if DumpConfig.AuditLogTable != "" {
374+
return dumpQueriesFromTable(ctx, opts)
375+
}
376+
return dumpQueriesFromFile(ctx, opts)
377+
}
378+
379+
func dumpQueriesFromTable(ctx context.Context, opts src.AuditLogScanOpts) ([][]string, error) {
380+
if opts.From == "" || opts.To == "" {
381+
return nil, errors.New("Must specific both '--from' and '--to' when dumping from audit log table")
382+
}
383+
if opts.Unique {
384+
return nil, errors.New("Not yet support '--query-output-mode=unique' with '--audit-log-table'")
385+
}
386+
387+
dbTable := strings.SplitN(DumpConfig.AuditLogTable, ".", 2)
388+
dbname, table := dbTable[0], dbTable[1]
389+
390+
db, err := connectDB(dbname)
391+
if err != nil {
392+
return nil, err
393+
}
394+
395+
logrus.Infof("Dumping queries from audit log table '%s'...\n", DumpConfig.AuditLogTable)
396+
397+
sqls, err := src.GetDBAuditLogs(ctx, db, dbname, table, opts, GlobalConfig.Parallel)
398+
if err != nil {
399+
logrus.Errorf("Extract queries from audit logs table failed, %v\n", err)
400+
return nil, err
401+
}
402+
return [][]string{sqls}, nil
403+
}
404+
405+
func dumpQueriesFromFile(ctx context.Context, opts src.AuditLogScanOpts) ([][]string, error) {
339406
auditLogs := DumpConfig.AuditLogPaths
340407
if len(auditLogs) == 0 {
341408
sshUrl, err := chooseRemoteAuditLog(ctx)
342409
if err != nil {
343-
return nil, fmt.Errorf("Please specific audit log path by --audit-logs, error: %v", err)
410+
return nil, fmt.Errorf("Please specific audit log files by '--audit-logs' or table by '--audit-log-table', error: %v", err)
344411
}
345412
auditLogs = []string{sshUrl}
346413
}
@@ -372,23 +439,16 @@ func dumpQueries(ctx context.Context) ([][]string, error) {
372439
auditLogFiles = append(auditLogFiles, localPaths...)
373440
}
374441

375-
logrus.Infoln("Dumping queries from audit logs...")
442+
logrus.Infoln("Dumping queries from audit log files...")
376443

377444
queries, err := src.ExtractQueriesFromAuditLogs(
378-
GlobalConfig.DBs,
379445
auditLogFiles,
380446
DumpConfig.AuditLogEncoding,
381-
DumpConfig.QueryMinDurationMs,
382-
DumpConfig.QueryStates,
447+
opts,
383448
GlobalConfig.Parallel,
384-
DumpConfig.QueryOutputMode == "unique",
385-
DumpConfig.QueryUniqueNormalize,
386-
DumpConfig.AuditLogUnescape,
387-
DumpConfig.OnlySelect,
388-
DumpConfig.Strict,
389449
)
390450
if err != nil {
391-
logrus.Errorf("Extract queries from audit logs failed, %v\n", err)
451+
logrus.Errorf("Extract queries from audit logs file failed, %v\n", err)
392452
return nil, err
393453
}
394454

@@ -466,7 +526,7 @@ func outputQueryFileNameFormat(total int) string {
466526
}
467527

468528
func chooseRemoteAuditLog(ctx context.Context) (string, error) {
469-
conn, err := connectDB(GlobalConfig.DBs[0])
529+
conn, err := connectDB("information_schema")
470530
if err != nil {
471531
return "", err
472532
}
@@ -494,7 +554,7 @@ func chooseRemoteAuditLog(ctx context.Context) (string, error) {
494554
return "", errors.New("No audit log found on remote server")
495555
}
496556

497-
choosed, err := src.Choose("Choose audit log on remote server to dump:", auditLogs)
557+
choosed, err := src.Choose("Choose audit log on remote server to dump", auditLogs)
498558
if err != nil {
499559
return "", err
500560
}
@@ -551,7 +611,7 @@ func expandSSHPath(remotePath string) (string, error) {
551611

552612
func connectDB(db string) (*sqlx.DB, error) {
553613
if db == "" {
554-
return nil, fmt.Errorf("database name is required, please use --db flag")
614+
return nil, fmt.Errorf("database name is required")
555615
}
556616
return src.NewDB(GlobalConfig.DBHost, GlobalConfig.DBPort, GlobalConfig.DBUser, GlobalConfig.DBPassword, db)
557617
}

cmd/replay.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ func completeReplayConfig() (err error) {
100100

101101
var t time.Time
102102
if ReplayConfig.From_ != "" {
103-
t, err = time.Parse("2006-01-02 15:04:05", ReplayConfig.From_)
103+
t, err = time.Parse(time.DateTime, ReplayConfig.From_)
104104
if err != nil {
105105
return err
106106
}
107107
ReplayConfig.From = t.UnixMilli()
108108
}
109109
if ReplayConfig.To_ != "" {
110-
t, err = time.Parse("2006-01-02 15:04:05", ReplayConfig.To_)
110+
t, err = time.Parse(time.DateTime, ReplayConfig.To_)
111111
if err != nil {
112112
return err
113113
}

0 commit comments

Comments
 (0)