From 22f5a975c3fcd5b134ee30d45da0e5a0abba1f32 Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Wed, 30 Jul 2025 18:50:52 +0800 Subject: [PATCH] perf: Optimize website log reading (#9755) Refs https://github.com/1Panel-dev/1Panel/issues/9383 --- agent/app/dto/response/file.go | 2 +- agent/app/service/file.go | 34 ++++++++++-- agent/utils/files/utils.go | 60 ++++++++++++++++++++++ frontend/src/components/log/file/index.vue | 11 ++-- 4 files changed, 98 insertions(+), 9 deletions(-) diff --git a/agent/app/dto/response/file.go b/agent/app/dto/response/file.go index c7e5702ae..051029d2c 100644 --- a/agent/app/dto/response/file.go +++ b/agent/app/dto/response/file.go @@ -38,12 +38,12 @@ type FileWgetRes struct { } type FileLineContent struct { - Content string `json:"content"` End bool `json:"end"` Path string `json:"path"` Total int `json:"total"` TaskStatus string `json:"taskStatus"` Lines []string `json:"lines"` + Scope string `json:"scope"` } type FileExist struct { diff --git a/agent/app/service/file.go b/agent/app/service/file.go index 66f321b01..d686f754d 100644 --- a/agent/app/service/file.go +++ b/agent/app/service/file.go @@ -542,24 +542,48 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name)) } - lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest) + file, err := os.Open(logFilePath) if err != nil { return nil, err } - if req.Latest && req.Page == 1 && len(lines) < 1000 && total > 1 { - preLines, _, _, err := files.ReadFileByLine(logFilePath, total-1, req.PageSize, false) + defer file.Close() + stat, err := file.Stat() + if err != nil { + return nil, err + } + var ( + lines []string + isEndOfFile bool + total int + scope string + ) + + if stat.Size() > 500*1024*1024 { + lines, err = files.TailFromEnd(logFilePath, req.PageSize) + isEndOfFile = true + scope = "tail" + } else { + lines, isEndOfFile, total, err = files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest) if err != nil { return nil, err } - lines = append(preLines, lines...) + if req.Latest && req.Page == 1 && len(lines) < 1000 && total > 1 { + preLines, _, _, err := files.ReadFileByLine(logFilePath, total-1, req.PageSize, false) + if err != nil { + return nil, err + } + lines = append(preLines, lines...) + } + scope = "page" } + res := &response.FileLineContent{ - Content: strings.Join(lines, "\n"), End: isEndOfFile, Path: logFilePath, Total: total, TaskStatus: taskStatus, Lines: lines, + Scope: scope, } return res, nil } diff --git a/agent/utils/files/utils.go b/agent/utils/files/utils.go index 18d69b733..f137dcd8a 100644 --- a/agent/utils/files/utils.go +++ b/agent/utils/files/utils.go @@ -101,6 +101,66 @@ func countLines(path string) (int, error) { } } +func TailFromEnd(filename string, lines int) ([]string, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return nil, err + } + fileSize := stat.Size() + + bufSize := int64(4096) + var result []string + var leftover string + + for offset := fileSize; offset > 0 && len(result) < lines; { + readSize := bufSize + if offset < bufSize { + readSize = offset + } + offset -= readSize + + buf := make([]byte, readSize) + _, err := file.ReadAt(buf, offset) + if err != nil && err != io.EOF { + return nil, err + } + + data := string(buf) + leftover + linesInChunk := strings.Split(data, "\n") + + if offset > 0 { + leftover = linesInChunk[0] + linesInChunk = linesInChunk[1:] + } else { + leftover = "" + } + + for i := len(linesInChunk) - 1; i >= 0; i-- { + if len(result) < lines { + if !(i == len(linesInChunk)-1 && linesInChunk[i] == "" && len(result) == 0) { + result = append([]string{linesInChunk[i]}, result...) + } + } + } + } + + if leftover != "" && len(result) < lines { + result = append([]string{leftover}, result...) + } + + if len(result) > lines { + result = result[len(result)-lines:] + } + + return result, nil +} + func ReadFileByLine(filename string, page, pageSize int, latest bool) (lines []string, isEndOfFile bool, total int, err error) { if !NewFileOp().Stat(filename) { return diff --git a/frontend/src/components/log/file/index.vue b/frontend/src/components/log/file/index.vue index 938e8b8b0..d53b26589 100644 --- a/frontend/src/components/log/file/index.vue +++ b/frontend/src/components/log/file/index.vue @@ -1,6 +1,7 @@