目录结构

my_logger.go
package mylogger
import (
"path"
"runtime"
"strings"
)
type LogLevel uint8 // 值越小, 表示权限越大
const (
DEBUG = iota
INFO
WARNING
ERROR
FATAL
)
// 获取运行时的一些信息
func getRunInfo(skip int) (funcName, fileName string, lineNo int) {
pc, file, lineNo, ok := runtime.Caller(skip)
if !ok {
return
}
funcName = strings.Split(runtime.FuncForPC(pc).Name(), ".")[1]
fileName = path.Base(file)
return
}
console_logger.go
package mylogger
import (
"fmt"
"strings"
"time"
)
type ConsoleLogger struct {
level LogLevel
}
func NewConsoleLogger(level string) ConsoleLogger {
var tmp LogLevel
switch level := strings.ToLower(level); level {
case "debug":
tmp = DEBUG
case "info":
tmp = INFO
case "warning":
tmp = WARNING
case "error":
tmp = ERROR
case "fatal":
tmp = FATAL
default:
panic("不支持的级别类型")
}
return ConsoleLogger{tmp}
}
func log(l ConsoleLogger, level LogLevel, message string, a ...interface{}) {
message = fmt.Sprintf(message, a...)
keyMap := map[LogLevel]string{
DEBUG: "DEBUG",
INFO: "INFO",
WARNING: "WARING",
ERROR: "ERROR",
FATAL: "FATAL",
}
strLevel := keyMap[level]
// 获取运行时的一些信息
funcName, fileName, lineNo := getRunInfo(3)
if l.level <= level {
fmt.Printf("[%s][%s][%s/%s:%d]: %s
", time.Now().Format("2006/01/02 15:04:05"), strLevel, funcName, fileName, lineNo, message)
}
}
func (l ConsoleLogger) Debug(message string, a ...interface{}) {
//if l.level <= DEBUG {
// fmt.Printf("[%s][%s]: %s
", time.Now().Format("2006/01/02 15:04:05"), "DEBUG", message)
//}
log(l, DEBUG, message, a...)
}
func (l ConsoleLogger) Info(message string, a ...interface{}) {
//if l.level <= INFO {
// fmt.Printf("[%s][%s]: %s
", time.Now().Format("2006/01/02 15:04:05"), "INFO", message)
//}
log(l, INFO, message, a...)
}
func (l ConsoleLogger) Warning(message string, a ...interface{}) {
//if l.level <= WARNING {
// fmt.Printf("[%s][%s]: %s
", time.Now().Format("2006/01/02 15:04:05"), "WARNING", message)
//}
log(l, WARNING, message, a...)
}
func (l ConsoleLogger) Error(message string, a ...interface{}) {
//if l.level <= ERROR {
// fmt.Printf("[%s][%s]: %s
", time.Now().Format("2006/01/02 15:04:05"), "ERROR", message)
//}
log(l, ERROR, message, a...)
}
func (l ConsoleLogger) Fatal(message string, a ...interface{}) {
//if l.level <= FATAL {
// fmt.Printf("[%s][%s]: %s
", time.Now().Format("2006/01/02 15:04:05"), "FATAL", message)
//}
log(l, FATAL, message, a...)
}
file_logger.go
package mylogger
import (
"fmt"
"os"
"path"
"strings"
"time"
)
type FileLogger struct {
level LogLevel
basePath string
fileName string
errFileName string
fileObj *os.File
errFileObj *os.File
fileMaxSize int64
}
func NewFileLogger(level, basePath, fileName, errFileName string, fileMaxSize int64) (FileLogger, error) {
var tmp LogLevel
switch level := strings.ToLower(level); level {
case "debug":
tmp = DEBUG
case "info":
tmp = INFO
case "warning":
tmp = WARNING
case "error":
tmp = ERROR
case "fatal":
tmp = FATAL
default:
panic("不支持的级别类型")
}
fileLogger := FileLogger{
level: tmp,
basePath: basePath,
fileName: fileName,
errFileName: errFileName,
fileMaxSize: fileMaxSize,
}
// 初始化`[标准日志]文件`和`[错误日志]文件`
// 打开[标准日志]文件
fileObj, err := os.OpenFile(path.Join(basePath, fileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("打开文件[fileObj]失败")
return fileLogger, err
}
fileLogger.fileObj = fileObj
// 打开[错误日志]文件
errFileObj, err := os.OpenFile(path.Join(basePath, errFileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("打开文件[errFileObj]失败")
return fileLogger, err
}
fileLogger.errFileObj = errFileObj
return fileLogger, nil
}
func splitFile(basePath, fileName string, fileObj *os.File, fileMaxSize int64) *os.File {
// ----------做文件截断操作------------
// todo 做文件截断操作
// 1. 判断当前打开的文件的大小是否超过设置的长度限制
fileInfo, err2 := fileObj.Stat()
if err2 != nil {
fmt.Println("获取文件信息失败")
fmt.Println("err", err2)
panic("程序又崩溃了")
}
fileSize := fileInfo.Size()
if fileSize >= fileMaxSize{
fmt.Println("正在将文件截断")
// 2. 如果超过, 则 2.1:关闭当前文件操作句柄, 2.2:并重命名当前文件 2.3:打开一个新的文件操作句柄
// 2.1
err2 := fileObj.Close()
if err2 != nil {
fmt.Println("文件关闭失败[1]")
panic("程序报错了[2]")
}
// 2.2
timeStr := time.Now().Format("20060102150405000")
oldName := path.Join(basePath, fileName)
newName := oldName + ".bak_"+timeStr
err2 = os.Rename(oldName, newName)
if err2 != nil {
fmt.Println("文件重命名失败[1]")
fmt.Println("err", err2)
panic("重命名失败[1]")
}
// 2.3
newFileObj, err2 := os.OpenFile(path.Join(basePath, fileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err2 != nil {
fmt.Println("文件已被截断, 重新打开新文件失败[1]")
panic("程序又又蹦啦")
}
//l.fileObj = newFileObj
return newFileObj
}
// 3. 长度未超出限制, 则啥事也不做, pass
// ----------做文件截断操作------------
return nil
}
func fileLog(l *FileLogger, level LogLevel, message string, a ...interface{}) {
message = fmt.Sprintf(message, a...)
keyMap := map[LogLevel]string{
DEBUG: "DEBUG",
INFO: "INFO",
WARNING: "WARING",
ERROR: "ERROR",
FATAL: "FATAL",
}
strLevel := keyMap[level]
// 获取运行时的一些信息
funcName, fileName, lineNo := getRunInfo(3)
// 写入[标准日志]
if l.level <= level { // 判断log句柄有没有权限, 如果有权限, 则输出
// 截断文件
newFileObj := splitFile(l.basePath, l.fileName, l.fileObj, l.fileMaxSize)
if newFileObj != nil{
l.fileObj = newFileObj
}
_, err := fmt.Fprintf(l.fileObj, "[%s][%s][%s/%s:%d]: %s
", time.Now().Format("2006/01/02 15:04:05"), strLevel, funcName, fileName, lineNo, message)
if err != nil {
fmt.Println("文件写入失败")
return
}
}
// 写入[错误日志]
if level >= ERROR{
// todo 做文件截断
// 截断文件
newFileObj := splitFile(l.basePath, l.errFileName, l.errFileObj, l.fileMaxSize)
if newFileObj != nil{
l.errFileObj = newFileObj
}
_, err := fmt.Fprintf(l.errFileObj, "[%s][%s][%s/%s:%d]: %s
", time.Now().Format("2006/01/02 15:04:05"), strLevel, funcName, fileName, lineNo, message)
if err != nil {
fmt.Println("文件写入失败")
return
}
}
}
func (l *FileLogger) Debug(message string, a ...interface{}) {
fileLog(l, DEBUG, message, a...)
}
func (l *FileLogger) Info(message string, a ...interface{}) {
fileLog(l, INFO, message, a...)
}
func (l *FileLogger) Warning(message string, a ...interface{}) {
fileLog(l, WARNING, message, a...)
}
func (l *FileLogger) Error(message string, a ...interface{}) {
fileLog(l, ERROR, message, a...)
}
func (l *FileLogger) Fatal(message string, a ...interface{}) {
fileLog(l, FATAL, message, a...)
}
测试
package main
import (
"fmt"
"time"
"code.xxx.com/studygolang/day06/mylogger"
)
func main() {
// 1. 向控制台输出的
//log := mylogger.NewConsoleLogger("error") // 初始化
// 2. 向文件输出的
log, err := mylogger.NewFileLogger("info", "./resources/logs/", "mylogger.txt", "errorlogger.txt", 1024*1024*10)
if err != nil {
fmt.Println("日志文件初始化失败")
return
}
for {
// 打印日志
log.Info("你好呀, 这是一条info信息")
log.Debug("你好呀, 这是一条debug信息")
log.Warning("你好呀, 这是一条waring信息")
log.Error("你好呀, 这是一条error信息 id: %d name: %s", 1, "sch")
log.Fatal("你好呀, 这是一条fatal信息")
time.Sleep(1000)
}
}