From 3e5f476dff8ff503f40f0048da9c1ae566be7d4e Mon Sep 17 00:00:00 2001 From: Oleksandr Ieremeev Date: Sun, 19 Aug 2018 16:40:32 +0300 Subject: [PATCH] Extend logs page (some previous logs, timestamp or rows) --- handlers/dashboard.go | 19 ++++++++++------- source/tmpl/logs.html | 2 +- utils/log.go | 34 ++++++++++++++++++++++++------ utils/logRow.go | 49 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 utils/logRow.go diff --git a/handlers/dashboard.go b/handlers/dashboard.go index a726f48a..49495eff 100644 --- a/handlers/dashboard.go +++ b/handlers/dashboard.go @@ -80,7 +80,15 @@ func LogsHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusSeeOther) return } - ExecuteResponse(w, r, "logs.html", nil) + utils.LockLines.Lock() + logs := make([]string, 0) + len := len(utils.LastLines) + // We need string log lines from end to start. + for i := len - 1; i >= 0; i-- { + logs = append(logs, utils.LastLines[i].FormatForHtml()+"\r\n") + } + utils.LockLines.Unlock() + ExecuteResponse(w, r, "logs.html", logs) } func LogsLineHandler(w http.ResponseWriter, r *http.Request) { @@ -88,12 +96,7 @@ func LogsLineHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } - switch v := utils.LastLine.(type) { - case string: - w.Write([]byte(v)) - case error: - w.Write([]byte(v.Error())) - case []byte: - w.Write(v) + if lastLine := utils.GetLastLine(); lastLine != nil { + w.Write([]byte(lastLine.FormatForHtml())) } } diff --git a/source/tmpl/logs.html b/source/tmpl/logs.html index 4e32b505..b999babe 100644 --- a/source/tmpl/logs.html +++ b/source/tmpl/logs.html @@ -22,7 +22,7 @@
- +
diff --git a/utils/log.go b/utils/log.go index 4f077f04..781e2c6a 100644 --- a/utils/log.go +++ b/utils/log.go @@ -23,13 +23,15 @@ import ( "os" "os/signal" "syscall" + "sync" ) var ( - logFile *os.File - fmtLogs *log.Logger - ljLogger *lumberjack.Logger - LastLine interface{} + logFile *os.File + fmtLogs *log.Logger + ljLogger *lumberjack.Logger + LastLines []*LogRow + LockLines sync.Mutex ) func createLog(dir string) error { @@ -69,6 +71,7 @@ func InitLogs() error { fmtLogs = log.New(logFile, "", log.Ldate|log.Ltime) log.SetOutput(ljLogger) rotate() + LastLines = make([]*LogRow, 0) return err } @@ -84,7 +87,7 @@ func rotate() { } func Log(level int, err interface{}) error { - LastLine = err + pushLastLine(err) var outErr error switch level { case 5: @@ -119,6 +122,25 @@ func Http(r *http.Request) string { msg := fmt.Sprintf("%v (%v) | IP: %v", r.RequestURI, r.Method, r.Host) fmtLogs.Printf("WEB: %v\n", msg) fmt.Printf("WEB: %v\n", msg) - LastLine = msg + pushLastLine(msg) return msg } + +func pushLastLine(line interface{}) { + LockLines.Lock() + defer LockLines.Unlock() + LastLines = append(LastLines, NewLogRow(line)) + // We want to store max 1000 lines in memory (for /logs page). + for len(LastLines) > 1000 { + LastLines = LastLines[1:] + } +} + +func GetLastLine() *LogRow { + LockLines.Lock() + defer LockLines.Unlock() + if len(LastLines) > 0 { + return LastLines[len(LastLines) - 1] + } + return nil +} diff --git a/utils/logRow.go b/utils/logRow.go new file mode 100644 index 00000000..207c8a4b --- /dev/null +++ b/utils/logRow.go @@ -0,0 +1,49 @@ +// Statup +// Copyright (C) 2018. Hunter Long and the project contributors +// Written by Hunter Long and the project contributors +// +// https://github.com/hunterlong/statup +// +// The licenses for most software and other practical works are designed +// to take away your freedom to share and change the works. By contrast, +// the GNU General Public License is intended to guarantee your freedom to +// share and change all versions of a program--to make sure it remains free +// software for all its users. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package utils + +import ( + "time" + "fmt" +) + +type LogRow struct { + Date time.Time + Line interface{} +} + +func NewLogRow(line interface{}) (logRow *LogRow) { + logRow = new(LogRow) + logRow.Date = time.Now() + logRow.Line = line + return +} + +func (o *LogRow) LineAsString() string { + switch v := o.Line.(type) { + case string: + return v + case error: + return v.Error() + case []byte: + return string(v) + } + return "" +} + +func (o *LogRow) FormatForHtml() string { + return fmt.Sprintf("%s: %s", o.Date.Format("2006-01-02 15:04:05"), o.LineAsString()) +}