├─mylogger │ console.go │ file.go │ myLogger.go
myLogger.go
package mylogger
import (
"errors"
"fmt"
"runtime"
"strings"
)
type logLevel uint8
type Logger interface {
Debug(format string, a ...interface{})
Trace(format string, a ...interface{})
Info(format string, a ...interface{})
Warning(format string, a ...interface{})
Error(format string, a ...interface{})
Fatal(format string, a ...interface{})
SetPrefix(prefix string)
}
const (
UnKnow logLevel = iota
DebugLevel
TraceLevel
InfoLevel
WarningLevel
ErrorLevel
FatalLevel
)
var (
levels = map[logLevel]string{
DebugLevel: "Debug",
TraceLevel: "Trace",
InfoLevel: "Info",
WarningLevel: "Warning",
ErrorLevel: "Error",
FatalLevel: "Fatal",
}
)
func (ll logLevel) String () string {
return levels[ll]
}
func parseLogLevel(s string) (logLevel, error) {
s = strings.ToLower(s)
switch s {
case "debug":
return DebugLevel, nil
case "trace":
return TraceLevel, nil
case "info":
return InfoLevel, nil
case "warning":
return WarningLevel, nil
case "error":
return ErrorLevel, nil
case "fatal":
return FatalLevel, nil
default:
return UnKnow, errors.New("无效的日志级别")
}
}
func getInfo(n int) (string, error) {
pc, fileName, lineNo, ok := runtime.Caller(n)
if !ok {
return "", errors.New("runtime.Caller() failed\n")
}
funcName := runtime.FuncForPC(pc).Name()
funcName = strings.Split(funcName, ".")[1]
return fmt.Sprintf("%s:%s:%d", fileName, funcName, lineNo), nil
}
console.go
package mylogger
import (
"fmt"
"time"
)
type ConsoleLogger struct {
Level logLevel
Prefix string
}
func (cl *ConsoleLogger) Print(level logLevel, format string, a ...interface{}) {
if cl.Level <= level {
msg := fmt.Sprintf(format, a...)
now := time.Now()
info, err := getInfo(3)
if err != nil {
fmt.Println(err.Error())
}else if cl.Prefix == "" {
fmt.Printf("%s ? %s %s %s\n", now.Format("2006/01/02 - 15:04:05"), level, info, msg)
}else {
fmt.Printf("%s %s ? %s %s %s\n", cl.Prefix, now.Format("2006/01/02 - 15:04:05"), level, info, msg)
}
}
}
func (cl *ConsoleLogger) SetPrefix(prefix string) {
cl.Prefix = prefix
}
// ConsoleLogger 构造函数
func NewConsoleLog(Level string) *ConsoleLogger {
level, err := parseLogLevel(Level)
if err != nil {
panic(err)
}
return &ConsoleLogger{Level:level}
}
func (cl *ConsoleLogger) Debug(format string, a ...interface{}) {
cl.Print(DebugLevel, format, a...)
}
func (cl *ConsoleLogger) Trace(format string, a ...interface{}) {
cl.Print(TraceLevel, format, a...)
}
func (cl *ConsoleLogger) Info(format string, a ...interface{}) {
cl.Print(InfoLevel, format, a...)
}
func (cl *ConsoleLogger) Warning(format string, a ...interface{}) {
cl.Print(WarningLevel, format, a...)
}
func (cl *ConsoleLogger) Error(format string, a ...interface{}) {
cl.Print(ErrorLevel, format, a...)
}
func (cl *ConsoleLogger) Fatal(format string, a ...interface{}) {
cl.Print(FatalLevel, format, a...)
}
file.go
package mylogger
import (
"fmt"
"os"
"path"
"time"
)
type FileLogger struct {
// 日志级别 比该级别高的打印的时候会显示
Level logLevel `json:"level"`
// 前缀 打印日志信息的前缀
Prefix string `json:"prefix"`
// 日志文件夹路径
FilePath string `json:"file_path"`
// 日志文件名
FileName string `json:"file_name"`
// 最大文件大小 分割日志文件的时候会用到
MaxFileSize int64 `json:"max_file_size"`
// 最大时间间隔 按时间分割文件的时候会用到
MaxAge int `json:"max_age"`
// 记录上次切割文件的时间
LastSplitTime time.Time
// 日志文件对象
FileObj *os.File
// Error日志文件对象
ErrFileObj *os.File
}
// FileLogger 构造函数
func NewFileLog(Level string, fp, fn string, maxSize int64) *FileLogger {
level, err := parseLogLevel(Level)
if err != nil {
panic(err)
}
fl := &FileLogger{
Level: level,
FilePath: fp,
FileName: fn,
MaxFileSize: maxSize,
}
err = fl.initFile()
if err != nil {
panic(err)
}
return fl
}
// FileLogger 构造函数
func NewFileLogWithMaxAge(Level string, fp, fn string, maxSize int64, maxAge int) *FileLogger {
level, err := parseLogLevel(Level)
if err != nil {
panic(err)
}
fl := &FileLogger{
Level: level,
FilePath: fp,
FileName: fn,
MaxFileSize: maxSize,
MaxAge:maxAge,
LastSplitTime:time.Now(),
}
err = fl.initFile()
if err != nil {
panic(err)
}
return fl
}
func (fl *FileLogger) CheckFileSize (file *os.File) bool {
fileInfo, err := file.Stat()
if err != nil {
fmt.Printf("get file info failed,err:%v\n", err)
return false
}
return fileInfo.Size() >= fl.MaxFileSize
}
func (fl *FileLogger) CheckFileLastAge (now time.Time) bool {
if fl.LastSplitTime == (time.Time{}){
return false
}
return int(now.Sub(fl.LastSplitTime).Hours()) > fl.MaxAge
}
func (fl *FileLogger) SetPrefix(prefix string) {
fl.Prefix = prefix
}
func (fl *FileLogger) Print(level logLevel, format string, a ...interface{}) {
if fl.Level <= level {
msg := fmt.Sprintf(format, a...)
now := time.Now()
info, err := getInfo(3)
if err != nil {
fmt.Println(err.Error())
}else {
if fl.CheckFileSize(fl.FileObj) || fl.CheckFileLastAge(now) {
newFileObje, err := fl.splitFile(fl.FileObj)
if err != nil {
return
}
fl.FileObj = newFileObje
}
if fl.Prefix == "" {
fmt.Fprintf(fl.FileObj, "%s ? %s %s %s\n", now.Format("2006/01/02 - 15:04:05"), level, info, msg)
}else {
fmt.Fprintf(fl.FileObj, "%s %s ? %s %s %s\n", fl.Prefix, now.Format("2006/01/02 - 15:04:05"), level, info, msg)
}
if level >= ErrorLevel {
if fl.CheckFileSize(fl.ErrFileObj) || fl.CheckFileLastAge(now){
newFileObje, err := fl.splitFile(fl.ErrFileObj)
if err != nil {
return
}
fl.ErrFileObj = newFileObje
}
if fl.Prefix == "" {
fmt.Fprintf(fl.ErrFileObj, "%s ? %s %s %s\n", now.Format("2006/01/02 - 15:04:05"), level, info, msg)
} else {
fmt.Fprintf(fl.ErrFileObj, "%s %s ? %s %s %s\n", fl.Prefix, now.Format("2006/01/02 - 15:04:05"), level, info, msg)
}
}
}
}
}
func (fl *FileLogger) initFile() error {
fullFileName := path.Join(fl.FilePath, fl.FileName)
fileObj, err := os.OpenFile(fullFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("open log file failed, err:%v", err)
return err
}
errFileObj, err := os.OpenFile(fullFileName+".err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("open err log file failed, err:%v", err)
return err
}
fl.FileObj = fileObj
fl.ErrFileObj = errFileObj
return nil
}
func (fl *FileLogger) splitFile(file *os.File) (*os.File, error) {
nowStr := time.Now().Format("20060102150405000")
fileInfo, err := file.Stat()
if err != nil {
fmt.Printf("get file info failed,err:%v\n", err)
return nil, err
}
logName := path.Join(fl.FilePath, fileInfo.Name())
newlogName := fmt.Sprintf("%s.%s.bak", logName, nowStr)
// 1. 关闭当前文件
file.Close()
// 2. 备份一个 rename
os.Rename(logName, newlogName)
// 3. 打开一个新的日志文件
fileObj, err := os.OpenFile(logName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("open log file failed, err:%v", err)
return nil, err
}
// 4. 将打开的文件赋值给 fl.FileObj
return fileObj, nil
}
func (fl *FileLogger) Debug(format string, a ...interface{}) {
fl.Print(DebugLevel, format, a...)
}
func (fl *FileLogger) Trace(format string, a ...interface{}) {
fl.Print(TraceLevel, format, a...)
}
func (fl *FileLogger) Info(format string, a ...interface{}) {
fl.Print(InfoLevel, format, a...)
}
func (fl *FileLogger) Warning(format string, a ...interface{}) {
fl.Print(WarningLevel, format, a...)
}
func (fl *FileLogger) Error(format string, a ...interface{}) {
fl.Print(ErrorLevel, format, a...)
}
func (fl *FileLogger) Fatal(format string, a ...interface{}) {
fl.Print(FatalLevel, format, a...)
}
package main
import "go_Logger/mylogger"
var myLog mylogger.Logger
func main() {
myLog := mylogger.NewConsoleLog("debug")
myLog.SetPrefix("[MY-LOG]")
myLog.Debug("这是一条Debug日志")
myLog.Trace("这是一条Trace日志")
myLog.Info("这是一条Info日志")
myLog.Warning("这是一条Warning日志")
name := "zhangyafei"
myLog.Error("这是一条Error日志, name:%s", name)
myLog.Fatal("这是一条Fatal日志")
}
终端
E:\go\project\src\go_Logger>go_Logger.exe [MY-LOG] 2020/06/11 - 12:22:04 ? Debug E:/go/project/src/go_Logger/main.go:main:25 这是一条Debug日志 [MY-LOG] 2020/06/11 - 12:22:04 ? Trace E:/go/project/src/go_Logger/main.go:main:26 这是一条Trace日志 [MY-LOG] 2020/06/11 - 12:22:04 ? Info E:/go/project/src/go_Logger/main.go:main:27 这是一条Info日志 [MY-LOG] 2020/06/11 - 12:22:04 ? Warning E:/go/project/src/go_Logger/main.go:main:28 这是一条Warning日志 [MY-LOG] 2020/06/11 - 12:22:04 ? Error E:/go/project/src/go_Logger/main.go:main:30 这是一条Error日志, name:zhangyafei [MY-LOG] 2020/06/11 - 12:22:04 ? Fatal E:/go/project/src/go_Logger/main.go:main:31 这是一条Fatal日志
package main
import "go_Logger/mylogger"
var myLog mylogger.Logger
func main() {
myLog = mylogger.NewFileLog("info", "log", "mylog.log", 10*1024*1024)
myLog.SetPrefix("[MY-LOG]")
myLog.Debug("这是一条Debug日志")
myLog.Trace("这是一条Trace日志")
myLog.Info("这是一条Info日志")
myLog.Warning("这是一条Warning日志")
name := "zhangyafei"
myLog.Error("这是一条Error日志, name:%s", name)
myLog.Fatal("这是一条Fatal日志")
}
log/mylog.log
[MY-LOG] 2020/06/11 - 12:24:20 ? Info E:/go/project/src/go_Logger/main.go:main:27 这是一条Info日志 [MY-LOG] 2020/06/11 - 12:24:20 ? Warning E:/go/project/src/go_Logger/main.go:main:28 这是一条Warning日志 [MY-LOG] 2020/06/11 - 12:24:20 ? Error E:/go/project/src/go_Logger/main.go:main:30 这是一条Error日志, name:zhangyafei [MY-LOG] 2020/06/11 - 12:24:20 ? Fatal E:/go/project/src/go_Logger/main.go:main:31 这是一条Fatal日志
log/mylog.log.err
[MY-LOG] 2020/06/11 - 12:24:20 ? Error E:/go/project/src/go_Logger/main.go:main:30 这是一条Error日志, name:zhangyafei [MY-LOG] 2020/06/11 - 12:24:20 ? Fatal E:/go/project/src/go_Logger/main.go:main:31 这是一条Fatal日志
文件大小切割
package main
import "go_Logger/mylogger"
var myLog mylogger.Logger
func main() {
myLog = mylogger.NewFileLog("info", "log", "mylog.log", 10*1024*1024)
myLog.SetPrefix("[MY-LOG]")
for {
myLog.Debug("这是一条Debug日志")
myLog.Trace("这是一条Trace日志")
myLog.Info("这是一条Info日志")
myLog.Warning("这是一条Warning日志")
name := "zhangyafei"
myLog.Error("这是一条Error日志, name:%s", name)
myLog.Fatal("这是一条Fatal日志")
}
}

package main
import "go_Logger/mylogger"
var myLog mylogger.Logger
func main() {
myLog = mylogger.NewFileLogWithMaxAge("Debug", "log", "mylog.log", 10*1024*1024, 24)
myLog.SetPrefix("[MY-LOG]")
for {
myLog.Debug("这是一条Debug日志")
myLog.Trace("这是一条Trace日志")
myLog.Info("这是一条Info日志")
myLog.Warning("这是一条Warning日志")
name := "zhangyafei"
myLog.Error("这是一条Error日志, name:%s", name)
myLog.Fatal("这是一条Fatal日志")
}
}
原文:https://www.cnblogs.com/zhangyafei/p/13092469.html