From ddd99f747663ff6f2a5446ab7fc92490ea90ddef Mon Sep 17 00:00:00 2001 From: Yusuke Nemoto Date: Thu, 14 Dec 2017 04:04:55 +0900 Subject: PLT-6896 per-paging for logs (#7903) * PLT-6896 Read logs from last * Getting rid of file.Stats * remove deprecated value * Make non-reassigned value constant --- api4/params.go | 17 ++++++++++++++--- api4/system.go | 2 +- api4/system_test.go | 16 ++++++++-------- app/admin.go | 55 ++++++++++++++++++++++++++++++++++++++--------------- model/client4.go | 2 +- 5 files changed, 64 insertions(+), 28 deletions(-) diff --git a/api4/params.go b/api4/params.go index 1f0fe8e63..64ee43771 100644 --- a/api4/params.go +++ b/api4/params.go @@ -11,9 +11,11 @@ import ( ) const ( - PAGE_DEFAULT = 0 - PER_PAGE_DEFAULT = 60 - PER_PAGE_MAXIMUM = 200 + PAGE_DEFAULT = 0 + PER_PAGE_DEFAULT = 60 + PER_PAGE_MAXIMUM = 200 + LOGS_PER_PAGE_DEFAULT = 10000 + LOGS_PER_PAGE_MAXIMUM = 10000 ) type ApiParams struct { @@ -43,6 +45,7 @@ type ApiParams struct { ActionId string Page int PerPage int + LogsPerPage int Permanent bool } @@ -165,5 +168,13 @@ func ApiParamsFromRequest(r *http.Request) *ApiParams { params.PerPage = val } + if val, err := strconv.Atoi(r.URL.Query().Get("logs_per_page")); err != nil || val < 0 { + params.LogsPerPage = LOGS_PER_PAGE_DEFAULT + } else if val > LOGS_PER_PAGE_MAXIMUM { + params.LogsPerPage = LOGS_PER_PAGE_MAXIMUM + } else { + params.LogsPerPage = val + } + return params } diff --git a/api4/system.go b/api4/system.go index 7bc846766..93e9ddcd2 100644 --- a/api4/system.go +++ b/api4/system.go @@ -187,7 +187,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { return } - lines, err := c.App.GetLogs(c.Params.Page, c.Params.PerPage) + lines, err := c.App.GetLogs(c.Params.Page, c.Params.LogsPerPage) if err != nil { c.Err = err return diff --git a/api4/system_test.go b/api4/system_test.go index 3afcf633c..1b2bb5d99 100644 --- a/api4/system_test.go +++ b/api4/system_test.go @@ -308,18 +308,18 @@ func TestGetLogs(t *testing.T) { logs, resp := th.SystemAdminClient.GetLogs(0, 10) CheckNoError(t, resp) - // if len(logs) != 10 { - // t.Log(len(logs)) - // t.Fatal("wrong length") - // } + if len(logs) != 10 { + t.Log(len(logs)) + t.Fatal("wrong length") + } logs, resp = th.SystemAdminClient.GetLogs(1, 10) CheckNoError(t, resp) - // if len(logs) != 10 { - // t.Log(len(logs)) - // t.Fatal("wrong length") - // } + if len(logs) != 10 { + t.Log(len(logs)) + t.Fatal("wrong length") + } logs, resp = th.SystemAdminClient.GetLogs(-1, -1) CheckNoError(t, resp) diff --git a/app/admin.go b/app/admin.go index ef5a1c5d5..e46d9073c 100644 --- a/app/admin.go +++ b/app/admin.go @@ -4,7 +4,7 @@ package app import ( - "bufio" + "io" "os" "strings" "time" @@ -20,9 +20,6 @@ import ( ) func (a *App) GetLogs(page, perPage int) ([]string, *model.AppError) { - - perPage = 10000 - var lines []string if a.Cluster != nil && *a.Config().ClusterSettings.Enable { lines = append(lines, "-----------------------------------------------------------------------------------------------------------") @@ -62,20 +59,48 @@ func (a *App) GetLogsSkipSend(page, perPage int) ([]string, *model.AppError) { defer file.Close() - offsetCount := 0 - limitCount := 0 - scanner := bufio.NewScanner(file) - for scanner.Scan() { - if limitCount >= perPage { - break + var newLine = []byte{'\n'} + var lineCount int + const searchPos = -1 + lineEndPos, err := file.Seek(0, io.SeekEnd) + if err != nil { + return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) + } + for { + pos, err := file.Seek(searchPos, io.SeekCurrent) + if err != nil { + return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) } - if offsetCount >= page*perPage { - lines = append(lines, scanner.Text()) - limitCount++ - } else { - offsetCount++ + b := make([]byte, 1) + _, err = file.ReadAt(b, pos) + if err != nil { + return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) } + + if b[0] == newLine[0] || pos == 0 { + lineCount++ + if lineCount > page*perPage { + line := make([]byte, lineEndPos-pos) + _, err := file.ReadAt(line, pos) + if err != nil { + return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) + } + lines = append(lines, string(line)) + } + if pos == 0 { + break + } + lineEndPos = pos + } + + if len(lines) == perPage { + break + } + } + + for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 { + lines[i], lines[j] = lines[j], lines[i] } } else { lines = append(lines, "") diff --git a/model/client4.go b/model/client4.go index 916e9d6de..d37fb3b0f 100644 --- a/model/client4.go +++ b/model/client4.go @@ -2649,7 +2649,7 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { // GetLogs page of logs as a string array. func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) + query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage) if r, err := c.DoApiGet("/logs"+query, ""); err != nil { return nil, BuildErrorResponse(r, err) } else { -- cgit v1.2.3-1-g7c22