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())
+}