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

  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 }

自定义go语言日志输出的更多相关文章

  1. springboot+logback日志输出企业实践(上)

    目录 1.引言 2.logback简介 3. springboot默认日志框架-logback 3.1 springboot示例工程搭建 3.2 日志输出与基本配置 3.2.1 日志默认输出 3.2. ...

  2. SpringBoot日志输出定义

    在application.yml配置文件中添加 logging: level: root: INFO #根日志输出级别 com.juyss.dao: DEBUG #自定义包的日志输出级别 file: ...

  3. Java自定义日志输出文件

    Java自定义日志输出文件 日志的打印,在程序中是必不可少的,如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个Appender的日志级别.打印形式和日志的输出路径 ...

  4. HAproxy增加日志记录功能和自定义日志输出内容、格式

    http://blog.51cto.com/eric1/1854574 一.增加haproxy日志记录功能   1.1 由于数据分析的需要,我们必须打开haproxy日志,记录相关信息. 在配置前,我 ...

  5. Hadoop案例(五)过滤日志及自定义日志输出路径(自定义OutputFormat)

    过滤日志及自定义日志输出路径(自定义OutputFormat) 1.需求分析 过滤输入的log日志中是否包含xyg (1)包含xyg的网站输出到e:/xyg.log (2)不包含xyg的网站输出到e: ...

  6. Logback自定义日志输出内容

    场景 一般情况下,日志打印的内容都是根据配置文件中配置的pattern格式指定好的.在我们调用logger.info(), logger.debug()等日志打印方法时,打印的内容格式与配置文件中的p ...

  7. 《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)

    1.简介 前面宏哥一连几篇介绍如何通过开源jar包Log4j.jar.log4j2.jar和logback实现日志文件输出,Log4j和logback确实很强大,能生成三种日志文件,一种是保存到磁盘的 ...

  8. Redis 自定义 RedisAppender 插件, 实现日志缓冲队列,集中日志输出.

    因为某些异步日志设置了即使队列满了,也不可丢弃,在并发高的时候,导致请求方法同步执行,响应变慢. 编写这个玩意,除了集中日志输出以外,还希望在高并发的时间点有缓冲作用. 之前用Kafka实现了一次入队 ...

  9. FFmpeg源代码简单分析:日志输出系统(av_log()等)

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  10. springboot(二).springboot整合logback用于日志输出

    springboot整合logback用于日志输出 我们项目的基本框架已经完成,http请求已经可以访问,现在给我们的框架添加日志记录的功能并能将每天的记录记录到文件中去 在这里,我们使用logbac ...

随机推荐

  1. 修改jar包内容

    列举jar包内容 # 列举jar包所有文件 jar tvf test.jar 从jar包中提取文件 # 从test.jar中提取test.jar/test.txt到test.txt jar xvf t ...

  2. WPS中VB编辑器的安装

    本来是因为要转换很多个文件的列的位置,他们格式一样,位置也一样,就是需要转换每个文件中列的位置,一个个操作又很麻烦,因此我在百度中发现了可以使用VBA进行操作,又由于excel里好像有VB编辑器,WP ...

  3. Vue I18n Vue.js 的国际化插件+elementUI的使用

    先附上插件官网 vue-i18n中文官网 我们的vue项目需要支持多语言时,可以使用这个插件 安装插件教程在官网可以找到 代码结构可以如下 zh.js 查看代码 export default { lo ...

  4. 用“餐厅打包”的故事说明白Python里面的自定义函数

    注:博主并非Python专业程序员,年龄12岁,Python龄不到1岁,才疏学浅,如有错误还请大佬指教! 希望能通过本专栏帮助到一些Python小白! 嗨~大家好!上篇博文咱们说了,万一有一些上万行才 ...

  5. css可继承与不可继承的属性

    一.可继承性的属性 字体相关的:font-size/font-family/font-weight/font-style/font-variant/font-stretch 文本相关的:color/t ...

  6. vue3 门户网站搭建6-wangeditor

    门户网站的新闻.公告等文章,内容可配置,故引入 wagneditor 1.安装: npm i wangeditor 2.方便调用,抽成组件: <template> <div ref= ...

  7. matlab算符合集

    1.逻辑算符 1)且 : A & B -- 两个逻辑数组之间 逐个元素 进行逻辑"与"操作 AB可为矩阵. 首先判断表达式A的逻辑值,然后判断B,继而进行逻辑"与 ...

  8. 《Makefile常用函数》

    https://blog.csdn.net/oqqHuTu12345678/article/details/125617988?spm=1001.2014.3001.5501

  9. 转载-Shell脚本中字符串截取功能

    在Shell脚本编写中,有几个地方都是要用到字符串截取的功能,那将这块的内容进行下记录: 1.字符串变量的截取操作 对字符串变量的截取操作一般都是通过${操作符}的方式进行 1)从指定位置index截 ...

  10. CSP-S T3函数调用

    函数是各种编程语言中一项重要的概念,借助函数,我们总可以将复杂的任务分解成一个个相对简单的子任务,直到细化为十分简单的基础操作,从而使代码的组织更加严密.更加有条理.然而,过多的函数调用也会导致额外的 ...