statping/utils/log.go

180 lines
4.1 KiB
Go
Raw Normal View History

2018-08-16 06:22:20 +00:00
// Statup
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> 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 <http://www.gnu.org/licenses/>.
2018-06-30 00:57:05 +00:00
package utils
import (
"fmt"
"gopkg.in/natefinch/lumberjack.v2"
"log"
2018-06-30 00:57:05 +00:00
"net/http"
"os"
"os/signal"
"sync"
2018-08-21 01:22:42 +00:00
"syscall"
"time"
2018-06-30 00:57:05 +00:00
)
var (
logFile *os.File
fmtLogs *log.Logger
ljLogger *lumberjack.Logger
LastLines []*LogRow
LockLines sync.Mutex
2018-06-30 00:57:05 +00:00
)
// createLog will create the '/logs' directory based on a directory
2018-08-16 02:22:10 +00:00
func createLog(dir string) error {
2018-06-30 00:57:05 +00:00
var err error
2018-08-16 02:22:10 +00:00
_, err = os.Stat(dir + "/logs")
2018-08-14 05:10:51 +00:00
if err != nil {
if os.IsNotExist(err) {
2018-08-16 02:22:10 +00:00
os.Mkdir(dir+"/logs", 0777)
2018-08-14 05:10:51 +00:00
} else {
2018-08-16 02:22:10 +00:00
return err
2018-08-14 05:10:51 +00:00
}
}
2018-08-16 02:22:10 +00:00
file, err := os.Create(dir + "/logs/statup.log")
2018-07-27 07:06:26 +00:00
if err != nil {
return err
}
defer file.Close()
2018-08-16 02:22:10 +00:00
return err
}
2018-07-27 07:06:26 +00:00
// InitLogs will create the '/logs' directory and creates a file '/logs/statup.log' for application logging
2018-08-16 02:22:10 +00:00
func InitLogs() error {
err := createLog(Directory)
if err != nil {
return err
}
2018-07-28 03:24:54 +00:00
logFile, err = os.OpenFile(Directory+"/logs/statup.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
2018-06-30 00:57:05 +00:00
if err != nil {
log.Printf("ERROR opening file: %v", err)
2018-07-27 04:45:42 +00:00
return err
2018-06-30 00:57:05 +00:00
}
ljLogger = &lumberjack.Logger{
2018-07-28 03:24:54 +00:00
Filename: Directory + "/logs/statup.log",
2018-06-30 00:57:05 +00:00
MaxSize: 16,
MaxBackups: 3,
MaxAge: 28,
}
fmtLogs = log.New(logFile, "", log.Ldate|log.Ltime)
log.SetOutput(ljLogger)
2018-06-30 00:57:05 +00:00
rotate()
LastLines = make([]*LogRow, 0)
2018-07-27 04:45:42 +00:00
return err
2018-06-30 00:57:05 +00:00
}
func rotate() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP)
go func() {
for {
<-c
ljLogger.Rotate()
}
}()
}
// Log creates a new entry in the Logger. Log has 1-5 levels depending on how critical the log/error is
2018-07-28 01:50:13 +00:00
func Log(level int, err interface{}) error {
pushLastLine(err)
2018-07-28 01:50:13 +00:00
var outErr error
2018-06-30 00:57:05 +00:00
switch level {
case 5:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("PANIC: %v\n", err)
fmtLogs.Printf("PANIC: %v\n", err)
2018-06-30 00:57:05 +00:00
case 4:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("FATAL: %v\n", err)
fmtLogs.Printf("FATAL: %v\n", err)
2018-06-30 00:57:05 +00:00
//color.Red("ERROR: %v\n", err)
//os.Exit(2)
case 3:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("ERROR: %v\n", err)
fmtLogs.Printf("ERROR: %v\n", err)
2018-06-30 00:57:05 +00:00
//color.Red("ERROR: %v\n", err)
case 2:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("WARNING: %v\n", err)
fmtLogs.Printf("WARNING: %v\n", err)
2018-06-30 00:57:05 +00:00
//color.Yellow("WARNING: %v\n", err)
case 1:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("INFO: %v\n", err)
fmtLogs.Printf("INFO: %v\n", err)
2018-06-30 00:57:05 +00:00
//color.Blue("INFO: %v\n", err)
case 0:
2018-07-28 01:50:13 +00:00
_, outErr = fmt.Printf("%v\n", err)
fmtLogs.Printf("%v\n", err)
2018-07-28 01:50:13 +00:00
//color.White("%v\n", err)
2018-06-30 00:57:05 +00:00
}
2018-07-28 01:50:13 +00:00
return outErr
2018-06-30 00:57:05 +00:00
}
// Http returns a log for a HTTP request
2018-07-28 01:50:13 +00:00
func Http(r *http.Request) string {
2018-06-30 00:57:05 +00:00
msg := fmt.Sprintf("%v (%v) | IP: %v", r.RequestURI, r.Method, r.Host)
fmt.Printf("WEB: %v\n", msg)
pushLastLine(msg)
2018-07-28 01:50:13 +00:00
return msg
2018-06-30 00:57:05 +00:00
}
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:]
}
}
// GetLastLine returns 1 line for a recent log entry
func GetLastLine() *LogRow {
LockLines.Lock()
defer LockLines.Unlock()
if len(LastLines) > 0 {
2018-08-21 01:22:42 +00:00
return LastLines[len(LastLines)-1]
}
return nil
}
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())
}