package logger import ( "flag" "fmt" "io" "log" "os" "path" "runtime" "runtime/debug" "strings" ) var stdlogger *log.Logger var errlogger *log.Logger var _ = flag.Bool("logfile", false, "") func init() { binpath, _ := os.Executable() binname := path.Base(strings.ReplaceAll(binpath, "\\", "/")) var outWriter io.Writer var errWriter io.Writer outWriter = os.Stdout errWriter = os.Stderr args := os.Args useLogFile := false for _, arg := range args { if arg == "-logfile" { useLogFile = true break } } if useLogFile { ext := path.Ext(binname) if len(ext) > 0 { binname = binname[:len(binname)-len(ext)] } logFile, err := os.Create(fmt.Sprintf("%s.log", binname)) if err != nil { os.Stdout.Write([]byte(err.Error())) panic(err) } outWriter = io.MultiWriter(outWriter, logFile) errWriter = io.MultiWriter(errWriter, logFile) } stdlogger = log.New(outWriter, "", log.LstdFlags) errlogger = log.New(errWriter, "", log.LstdFlags) } func Println(v ...interface{}) { stdlogger.Output(2, fmt.Sprintln(v...)) } func Printf(format string, v ...interface{}) { stdlogger.Output(2, fmt.Sprintf(format, v...)) } func Error(v ...interface{}) { errlogger.Output(2, fmt.Sprintln(v...)) errlogger.Output(2, string(debug.Stack())) } func Errorf(format string, v ...interface{}) { errlogger.Output(2, fmt.Sprintf(format, v...)) errlogger.Output(2, string(debug.Stack())) } func Fatal(v ...interface{}) { errlogger.Output(2, fmt.Sprint(v...)) errlogger.Output(2, string(debug.Stack())) os.Exit(1) } func Fatalln(v ...interface{}) { errlogger.Output(2, fmt.Sprintln(v...)) errlogger.Output(2, string(debug.Stack())) os.Exit(1) } func Panic(v ...interface{}) { s := fmt.Sprint(v...) errlogger.Output(2, s) errlogger.Output(2, string(debug.Stack())) panic(s) } func Panicf(format string, v ...interface{}) { s := fmt.Sprintf(format, v...) errlogger.Output(2, s) errlogger.Output(2, string(debug.Stack())) panic(s) } func Panicln(v ...interface{}) { s := fmt.Sprintln(v...) errlogger.Output(2, s) errlogger.Output(2, string(debug.Stack())) panic(s) } type errWithCallstack struct { inner error frames []*runtime.Frame } func (ecs *errWithCallstack) Error() string { if ecs.frames == nil { return ecs.inner.Error() } out := make([]string, 0, len(ecs.frames)+1) out = append(out, ecs.inner.Error()) for i := len(ecs.frames) - 1; i >= 0; i-- { frame := ecs.frames[i] out = append(out, fmt.Sprintf("%s\n\t%s:%d", frame.Function, frame.File, frame.Line)) } return strings.Join(out, "\n") } func ErrorWithCallStack(err error) error { var frames []*runtime.Frame if recur, ok := err.(*errWithCallstack); ok { err = recur.inner frames = recur.frames } pc, _, _, ok := runtime.Caller(1) if ok { curframes := runtime.CallersFrames([]uintptr{pc}) f, _ := curframes.Next() frames = append(frames, &f) } return &errWithCallstack{ inner: err, frames: frames, } }