Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
6.9 KiB
380 lines
6.9 KiB
//high level log wrapper, so it can output different log based on level |
|
package log |
|
|
|
import ( |
|
"fmt" |
|
"io" |
|
"log" |
|
"os" |
|
"runtime" |
|
"sync" |
|
"time" |
|
) |
|
|
|
const ( |
|
Ldate = log.Ldate |
|
Llongfile = log.Llongfile |
|
Lmicroseconds = log.Lmicroseconds |
|
Lshortfile = log.Lshortfile |
|
LstdFlags = log.LstdFlags |
|
Ltime = log.Ltime |
|
) |
|
|
|
type ( |
|
LogLevel int |
|
LogType int |
|
) |
|
|
|
const ( |
|
LOG_FATAL = LogType(0x1) |
|
LOG_ERROR = LogType(0x2) |
|
LOG_WARNING = LogType(0x4) |
|
LOG_INFO = LogType(0x8) |
|
LOG_DEBUG = LogType(0x10) |
|
) |
|
|
|
const ( |
|
LOG_LEVEL_NONE = LogLevel(0x0) |
|
LOG_LEVEL_FATAL = LOG_LEVEL_NONE | LogLevel(LOG_FATAL) |
|
LOG_LEVEL_ERROR = LOG_LEVEL_FATAL | LogLevel(LOG_ERROR) |
|
LOG_LEVEL_WARN = LOG_LEVEL_ERROR | LogLevel(LOG_WARNING) |
|
LOG_LEVEL_INFO = LOG_LEVEL_WARN | LogLevel(LOG_INFO) |
|
LOG_LEVEL_DEBUG = LOG_LEVEL_INFO | LogLevel(LOG_DEBUG) |
|
LOG_LEVEL_ALL = LOG_LEVEL_DEBUG |
|
) |
|
|
|
const FORMAT_TIME_DAY string = "20060102" |
|
const FORMAT_TIME_HOUR string = "2006010215" |
|
|
|
var _log *logger = New() |
|
|
|
func init() { |
|
SetFlags(Ldate | Ltime | Lshortfile) |
|
SetHighlighting(runtime.GOOS != "windows") |
|
} |
|
|
|
func Logger() *log.Logger { |
|
return _log._log |
|
} |
|
|
|
func SetLevel(level LogLevel) { |
|
_log.SetLevel(level) |
|
} |
|
func GetLogLevel() LogLevel { |
|
return _log.level |
|
} |
|
|
|
func SetOutput(out io.Writer) { |
|
_log.SetOutput(out) |
|
} |
|
|
|
func SetOutputByName(path string) error { |
|
return _log.SetOutputByName(path) |
|
} |
|
|
|
func SetFlags(flags int) { |
|
_log._log.SetFlags(flags) |
|
} |
|
|
|
func Info(v ...interface{}) { |
|
_log.Info(v...) |
|
} |
|
|
|
func Infof(format string, v ...interface{}) { |
|
_log.Infof(format, v...) |
|
} |
|
|
|
func Debug(v ...interface{}) { |
|
_log.Debug(v...) |
|
} |
|
|
|
func Debugf(format string, v ...interface{}) { |
|
_log.Debugf(format, v...) |
|
} |
|
|
|
func Warn(v ...interface{}) { |
|
_log.Warning(v...) |
|
} |
|
|
|
func Warnf(format string, v ...interface{}) { |
|
_log.Warningf(format, v...) |
|
} |
|
|
|
func Warning(v ...interface{}) { |
|
_log.Warning(v...) |
|
} |
|
|
|
func Warningf(format string, v ...interface{}) { |
|
_log.Warningf(format, v...) |
|
} |
|
|
|
func Error(v ...interface{}) { |
|
_log.Error(v...) |
|
} |
|
|
|
func Errorf(format string, v ...interface{}) { |
|
_log.Errorf(format, v...) |
|
} |
|
|
|
func Fatal(v ...interface{}) { |
|
_log.Fatal(v...) |
|
} |
|
|
|
func Fatalf(format string, v ...interface{}) { |
|
_log.Fatalf(format, v...) |
|
} |
|
|
|
func SetLevelByString(level string) { |
|
_log.SetLevelByString(level) |
|
} |
|
|
|
func SetHighlighting(highlighting bool) { |
|
_log.SetHighlighting(highlighting) |
|
} |
|
|
|
func SetRotateByDay() { |
|
_log.SetRotateByDay() |
|
} |
|
|
|
func SetRotateByHour() { |
|
_log.SetRotateByHour() |
|
} |
|
|
|
type logger struct { |
|
_log *log.Logger |
|
level LogLevel |
|
highlighting bool |
|
|
|
dailyRolling bool |
|
hourRolling bool |
|
|
|
fileName string |
|
logSuffix string |
|
fd *os.File |
|
|
|
lock sync.Mutex |
|
} |
|
|
|
func (l *logger) SetHighlighting(highlighting bool) { |
|
l.highlighting = highlighting |
|
} |
|
|
|
func (l *logger) SetLevel(level LogLevel) { |
|
l.level = level |
|
} |
|
|
|
func (l *logger) SetLevelByString(level string) { |
|
l.level = StringToLogLevel(level) |
|
} |
|
|
|
func (l *logger) SetRotateByDay() { |
|
l.dailyRolling = true |
|
l.logSuffix = genDayTime(time.Now()) |
|
} |
|
|
|
func (l *logger) SetRotateByHour() { |
|
l.hourRolling = true |
|
l.logSuffix = genHourTime(time.Now()) |
|
} |
|
|
|
func (l *logger) rotate() error { |
|
l.lock.Lock() |
|
defer l.lock.Unlock() |
|
|
|
var suffix string |
|
if l.dailyRolling { |
|
suffix = genDayTime(time.Now()) |
|
} else if l.hourRolling { |
|
suffix = genHourTime(time.Now()) |
|
} else { |
|
return nil |
|
} |
|
|
|
// Notice: if suffix is not equal to l.LogSuffix, then rotate |
|
if suffix != l.logSuffix { |
|
err := l.doRotate(suffix) |
|
if err != nil { |
|
return err |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func (l *logger) doRotate(suffix string) error { |
|
// Notice: Not check error, is this ok? |
|
l.fd.Close() |
|
|
|
lastFileName := l.fileName + "." + l.logSuffix |
|
err := os.Rename(l.fileName, lastFileName) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
err = l.SetOutputByName(l.fileName) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
l.logSuffix = suffix |
|
|
|
return nil |
|
} |
|
|
|
func (l *logger) SetOutput(out io.Writer) { |
|
l._log = log.New(out, l._log.Prefix(), l._log.Flags()) |
|
} |
|
|
|
func (l *logger) SetOutputByName(path string) error { |
|
f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
l.SetOutput(f) |
|
|
|
l.fileName = path |
|
l.fd = f |
|
|
|
return err |
|
} |
|
|
|
func (l *logger) log(t LogType, v ...interface{}) { |
|
if l.level|LogLevel(t) != l.level { |
|
return |
|
} |
|
|
|
err := l.rotate() |
|
if err != nil { |
|
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) |
|
return |
|
} |
|
|
|
v1 := make([]interface{}, len(v)+2) |
|
logStr, logColor := LogTypeToString(t) |
|
if l.highlighting { |
|
v1[0] = "\033" + logColor + "m[" + logStr + "]" |
|
copy(v1[1:], v) |
|
v1[len(v)+1] = "\033[0m" |
|
} else { |
|
v1[0] = "[" + logStr + "]" |
|
copy(v1[1:], v) |
|
v1[len(v)+1] = "" |
|
} |
|
|
|
s := fmt.Sprintln(v1...) |
|
l._log.Output(4, s) |
|
} |
|
|
|
func (l *logger) logf(t LogType, format string, v ...interface{}) { |
|
if l.level|LogLevel(t) != l.level { |
|
return |
|
} |
|
|
|
err := l.rotate() |
|
if err != nil { |
|
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) |
|
return |
|
} |
|
|
|
logStr, logColor := LogTypeToString(t) |
|
var s string |
|
if l.highlighting { |
|
s = "\033" + logColor + "m[" + logStr + "] " + fmt.Sprintf(format, v...) + "\033[0m" |
|
} else { |
|
s = "[" + logStr + "] " + fmt.Sprintf(format, v...) |
|
} |
|
l._log.Output(4, s) |
|
} |
|
|
|
func (l *logger) Fatal(v ...interface{}) { |
|
l.log(LOG_FATAL, v...) |
|
os.Exit(-1) |
|
} |
|
|
|
func (l *logger) Fatalf(format string, v ...interface{}) { |
|
l.logf(LOG_FATAL, format, v...) |
|
os.Exit(-1) |
|
} |
|
|
|
func (l *logger) Error(v ...interface{}) { |
|
l.log(LOG_ERROR, v...) |
|
} |
|
|
|
func (l *logger) Errorf(format string, v ...interface{}) { |
|
l.logf(LOG_ERROR, format, v...) |
|
} |
|
|
|
func (l *logger) Warning(v ...interface{}) { |
|
l.log(LOG_WARNING, v...) |
|
} |
|
|
|
func (l *logger) Warningf(format string, v ...interface{}) { |
|
l.logf(LOG_WARNING, format, v...) |
|
} |
|
|
|
func (l *logger) Debug(v ...interface{}) { |
|
l.log(LOG_DEBUG, v...) |
|
} |
|
|
|
func (l *logger) Debugf(format string, v ...interface{}) { |
|
l.logf(LOG_DEBUG, format, v...) |
|
} |
|
|
|
func (l *logger) Info(v ...interface{}) { |
|
l.log(LOG_INFO, v...) |
|
} |
|
|
|
func (l *logger) Infof(format string, v ...interface{}) { |
|
l.logf(LOG_INFO, format, v...) |
|
} |
|
|
|
func StringToLogLevel(level string) LogLevel { |
|
switch level { |
|
case "fatal": |
|
return LOG_LEVEL_FATAL |
|
case "error": |
|
return LOG_LEVEL_ERROR |
|
case "warn": |
|
return LOG_LEVEL_WARN |
|
case "warning": |
|
return LOG_LEVEL_WARN |
|
case "debug": |
|
return LOG_LEVEL_DEBUG |
|
case "info": |
|
return LOG_LEVEL_INFO |
|
} |
|
return LOG_LEVEL_ALL |
|
} |
|
|
|
func LogTypeToString(t LogType) (string, string) { |
|
switch t { |
|
case LOG_FATAL: |
|
return "fatal", "[0;31" |
|
case LOG_ERROR: |
|
return "error", "[0;31" |
|
case LOG_WARNING: |
|
return "warning", "[0;33" |
|
case LOG_DEBUG: |
|
return "debug", "[0;36" |
|
case LOG_INFO: |
|
return "info", "[0;37" |
|
} |
|
return "unknown", "[0;37" |
|
} |
|
|
|
func genDayTime(t time.Time) string { |
|
return t.Format(FORMAT_TIME_DAY) |
|
} |
|
|
|
func genHourTime(t time.Time) string { |
|
return t.Format(FORMAT_TIME_HOUR) |
|
} |
|
|
|
func New() *logger { |
|
return Newlogger(os.Stderr, "") |
|
} |
|
|
|
func Newlogger(w io.Writer, prefix string) *logger { |
|
return &logger{_log: log.New(w, prefix, LstdFlags), level: LOG_LEVEL_ALL, highlighting: true} |
|
}
|
|
|