自定义输出符合下列需求:

  1.含两类日志输出方式:调试模式下输出到控制台;生产环境输出到日志文件

  2.调用不同的函数/方法构造不同的输出方式,后续只需调用日志级别对应的函数即可输出该级别日志

工具构造:

  - / mylogger

    - mylogger.go  类似python的init.py,怎么叫不知道

    - console.go   定义日志输出到控制台方式

    - writeFile.go  定义日志写入文件方式

mylogger.go:

 1 package mylogger
2
3 import (
4 "errors"
5 "fmt"
6 "path"
7 "runtime"
8 "strings"
9 )
10
11 // log level variable
12 type logLevel uint16
13
14 // 对外接口
15 type Logger interface {
16 Debug(format string, a ...interface{})
17 Trace(format string, a ...interface{})
18 Info(format string, a ...interface{})
19 Warning(format string, a ...interface{})
20 Error(format string, a ...interface{})
21 Fatal(format string, a ...interface{})
22 }
23
24 // level
25 const (
26 UNKNOWN logLevel = iota
27 DEBUG
28 TRACE
29 INFO
30 WARNING
31 ERROR
32 FATAL
33 )
34
35 // 将等级字符串转换成整形 string -> uint16
36 func parseLogLevel(s string) (logLevel, error){
37 s = strings.ToLower(s)
38 switch s {
39 case "trace":
40 return TRACE, nil
41 case "debug":
42 return DEBUG, nil
43 case "info":
44 return INFO, nil
45 case "warning":
46 return WARNING, nil
47 case "error":
48 return ERROR, nil
49 case "fatal":
50 return FATAL, nil
51 default:
52 err := errors.New("无效的日志级别")
53 return UNKNOWN, err
54 }
55 }
56
57 // 将整形转换成等级字符串 uint16 -> string
58 func unparseLogLevel(level logLevel) string {
59 switch level {
60 case DEBUG:
61 return "DEBUG"
62 case TRACE:
63 return "TRACE"
64 case INFO:
65 return "INFO"
66 case WARNING:
67 return "WARNING"
68 case ERROR:
69 return "ERROR"
70 case FATAL:
71 return "FATAl"
72 default:
73 return "DEBUG"
74 }
75 }
76
77 // 调用runtime.Caller获取调用log打印的具体代码位置
78 func getInfo(skip int) (funcName, fileName string, lineNo int) {
79 pc, file, lineNo, ok := runtime.Caller(skip)
80 if !ok {
81 fmt.Println("runtime.Caller() failed")
82 return
83 }
84 funcName = runtime.FuncForPC(pc).Name()
85 funcName = strings.Split(funcName, ".")[1]
86 fileName = path.Base(file)
87 return funcName, fileName, lineNo
88 }

console.go:

 1 package mylogger
2
3 import (
4 "fmt"
5 "time"
6 )
7
8 // console log 结构体
9 type consoleLogger struct {
10 level logLevel
11 }
12
13 // 控制台输出log对象构造函数
14 func NewConsoleLogger(levelStr string) consoleLogger {
15 level, err := parseLogLevel(levelStr)
16 if err != nil {
17 panic(err)
18 }
19 return consoleLogger{level:level}
20 }
21
22 // log输出公共函数
23 func (l consoleLogger) enable (level logLevel, format string, a ...interface{}) {
24 if l.level <= level {
25 // 拼接格式化字符串,格式化可有可无
26 msg := fmt.Sprintf(format, a...)
27 now := time.Now()
28 levelStr := unparseLogLevel(level)
29 funcName, fileName, lineNo := getInfo(3)
30 fmt.Printf("[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
31 }
32 }
33
34 // Debug输出
35 func (l consoleLogger) Debug (format string, a ...interface{}) {
36 l.enable(DEBUG, format, a...)
37 }
38
39 // Trace
40 func (l consoleLogger) Trace (format string, a ...interface{}) {
41 l.enable(TRACE, format, a...)
42 }
43
44 // Info
45 func (l consoleLogger) Info (format string, a ...interface{}) {
46 l.enable(INFO, format, a...)
47 }
48
49 // Warning
50 func (l consoleLogger) Warning (format string, a ...interface{}) {
51 l.enable(WARNING, format, a...)
52 }
53
54 // Error
55 func (l consoleLogger) Error (format string, a ...interface{}) {
56 l.enable(ERROR, format, a...)
57 }
58
59 // Fatal
60 func (l consoleLogger) Fatal (format string, a ...interface{}) {
61 l.enable(FATAL, format, a...)
62 }

writeFile.go:

  1 package mylogger
2
3 import (
4 "fmt"
5 "os"
6 "path"
7 "time"
8 )
9
10 // file log结构体
11 type fileLogger struct {
12 level logLevel
13 filePath string
14 fileName string
15 fileObj *os.File
16 errfileObj *os.File
17 maxFileSize int64
18 }
19
20 // 文件日志对象构造函数
21 func NewFileLogger(levelStr, fp, fn string, maxsize int64) *fileLogger {
22 level, err := parseLogLevel(levelStr)
23 if err != nil {
24 panic(err)
25 }
26 f1 := &fileLogger{level:level, filePath:fp, fileName:fn, maxFileSize:maxsize}
27 err = f1.initFile()
28 if err != nil {
29 panic(err)
30 }
31 return f1
32 }
33
34 // 初始化打开日志文件并赋值给file log结构体
35 func (f *fileLogger) initFile() error {
36 fileObj, err1 := os.OpenFile(path.Join(f.filePath, f.fileName), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
37 if err1 != nil {
38 fmt.Printf("open log file failed, err:%v\n", err1)
39 return err1
40 }
41 f.fileObj = fileObj
42
43 errfileObj, err2 := os.OpenFile(path.Join(f.filePath, fmt.Sprintf("%s.error", f.fileName)), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
44 //errfileObj, err2 := os.OpenFile(path.Join(f.filePath, "error", f.fileName), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
45 if err2 != nil {
46 fmt.Printf("open error log file failed, err:%v\n", err2)
47 return err2
48 }
49 f.errfileObj = errfileObj
50 return nil
51 }
52
53 // 关闭文件
54 func (f *fileLogger) Close() {
55 f.fileObj.Close()
56 f.errfileObj.Close()
57 }
58
59 // 切割文件函数
60 func (l *fileLogger) isCuttingFile(f *os.File) (*os.File, error) {
61 fileInfo, err := f.Stat()
62 if err != nil {
63 fmt.Printf("get file info failed, err:%v\n", err)
64 return f, nil
65 }
66 if fileInfo.Size() >= l.maxFileSize {
67 LogName := path.Join(l.filePath, fileInfo.Name())
68 newLogName := fmt.Sprintf("%s.bak%s", LogName, time.Now().Format("20060102150405"))
69 // 关闭文件
70 f.Close()
71 // 给原文件重命名
72 os.Rename(LogName, newLogName)
73 // 设置为新的文件操作符
74 fileObj, err := os.OpenFile(LogName, os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
75 if err != nil {
76 fmt.Printf("open new file failed, err:%v", err)
77 return nil, err
78 }
79 return fileObj, nil
80 }
81 return f, nil
82 }
83
84 // log输出公共函数
85 func (l *fileLogger) enable (level logLevel, format string, a ...interface{}) {
86 if l.level <= level {
87 // 拼接格式化字符串,格式化可有可无
88 msg := fmt.Sprintf(format, a...)
89 now := time.Now()
90 levelStr := unparseLogLevel(level)
91 funcName, fileName, lineNo := getInfo(3)
92 // 切割文件
93 fileObj, err := l.isCuttingFile(l.fileObj)
94 if err != nil {
95 panic(err)
96 }
97 l.fileObj = fileObj
98 fmt.Fprintf(l.fileObj, "[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
99 //如果等级 >= Warning,写入日志到errFile
100 if level >= WARNING {
101 fileObj, err := l.isCuttingFile(l.errfileObj)
102 if err != nil {
103 panic(err)
104 }
105 l.errfileObj = fileObj
106 fmt.Fprintf(l.errfileObj, "[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
107 }
108 }
109 }
110
111 // Debug输出
112 func (l *fileLogger) Debug (format string, a ...interface{}) {
113 l.enable(DEBUG, format, a...)
114 }
115
116 // Trace
117 func (l *fileLogger) Trace (format string, a ...interface{}) {
118 l.enable(TRACE, format, a...)
119 }
120
121 // Info
122 func (l *fileLogger) Info (format string, a ...interface{}) {
123 l.enable(INFO, format, a...)
124 }
125
126 // Warning
127 func (l *fileLogger) Warning (format string, a ...interface{}) {
128 l.enable(WARNING, format, a...)
129 }
130
131 // Error
132 func (l *fileLogger) Error (format string, a ...interface{}) {
133 l.enable(ERROR, format, a...)
134 }
135
136 // Fatal
137 func (l *fileLogger) Fatal (format string, a ...interface{}) {
138 l.enable(FATAL, format, a...)
139 }

简单使用:

 1 package main
2
3 import (
4 mylogger "utils/mylogger"
5 "time"
6 )
7
8 var logger mylogger.Logger
9
10 func main() {
11 // console
12 logger = mylogger.NewConsoleLogger("info")
13 // file
14 //logger := mylogger.NewFileLogger("Info", "/home/xxx/logs/gologs", "2021-11-11.log", 500*1024*1024)
15 for {
16 logger.Trace("这是一条trace记录")
17 logger.Debug("这是一条debug记录")
18 logger.Info("这是一条info记录")
19 // format string
20 name := "唐僧"
21 logger.Warning("%s说:这是一条warning记录", name)
22 logger.Error("这是一条error记录")
23 logger.Fatal("这是一条fatal记录")
24 time.Sleep(time.Second)
25 }
26 }

最新文章

  1. ASP.NET MVC5 网站开发实践(二) Member区域 - 文章管理架构
  2. 怎么在MVC中使用自定义Membership
  3. [ JS 进阶 ] test, exec, match, replace
  4. JAVA代码实现下载单个文件,和下载打包文件
  5. 导航代码position:relative
  6. 将插入的新行放入dataGridView的第一行
  7. eclipse 配置git ssh登录
  8. 【无聊放个模板系列】POJ 1274 (匈牙利)
  9. [OC Foundation框架 - 7] NSArray的创建与遍历
  10. Struts2 程序步骤
  11. nodejs将JSON字符串转化为JSON对象
  12. kafka producer 0.8.2.1 示例
  13. 深入理解Java虚拟机读书笔记4----虚拟机类加载机制
  14. Gulp教程之:Gulp能做什么,前端装逼为何要用它
  15. python requests用法总结
  16. combox省市县三级联动
  17. Vue(八):监听属性watch
  18. [Leetcode 62]机器人走路Unique Path 动态规划
  19. 异常值检测 —— MAD(median absolute deviation)
  20. python---基础知识回顾(三)(面向对象)

热门文章

  1. Jemeter 压测 Elasticsearch
  2. python菜鸟学习: 15 GUI界面化记事本
  3. john破解linux用户密码
  4. ChatGPT 爆火!真有那么神?设计师会失业吗?
  5. AWT+Swing实现百度图像识别
  6. git submodule .gitmodules 子模块
  7. Scoped方法(防止样式名称冲突)
  8. uniapp与原生交互
  9. 尝试window10系统下使用appuim获取ios元素
  10. [js函数] shallowEqual