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

  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. QT--弹出新的对话框 show()/exec()的区别

    show()显示非模态对话框,exec()显示模态对话框. 非模态对话框不会阻塞程序的线程,因此 如果你的对话框时创建在栈上,跳出作用域之后,对象便销毁了,对话框会一闪而过: 如果使用new在堆上创建 ...

  2. 雪花算法-Java分布式系统自增id

    1.雪花算法的用途 分布式系统中ID生成方案,比较简单的是UUID(Universally Unique Identifier,通用唯一识别码),但是其存在两个明显的弊端: 一.UUID是128位的, ...

  3. Generative Adversarial Network - Python实现

    算法特征 ①. discriminator区别真假; ②. generator以假乱真 算法推导 Part Ⅰ: 熵之相关定义 entropy之定义如下, \[\begin{equation*} H( ...

  4. ES实战- data too large, data for

    场景 客户现场业务系统突然查询不到数据,个人一开始分析以为是聚合查询报错,于是去看了下系统日志,看到如下日志打印: Caused by: ElasticsearchStatusException[El ...

  5. 基于MIPI的高性能成像系统

    硬件组件Digilent Genesys ZU × 1 (FPGA平台) Digilent PCAM5 × 1 (MIPI摄像头) 软件组件AMD-Xilinx Vivado 设计套件 介绍从简单的嵌 ...

  6. verilog 和system verilog 文件操作

    1. 文件操作 Verilog具有系统任务和功能,可以打开文件.将值输出到文件.从文件中读取值并加 载到其他变量和关闭文件. 1.1 Verilog文件操作 1.1.1 打开和关闭文件 module ...

  7. Google colab防断联

    (1)进入Colab的notebook界面,按快捷键F12,打开开发者模式或者右键检查进入,选择console (2)复制并运行代码 function ClickConnect(){ console. ...

  8. linux 动态库、静态库

    库:可执行的二进制代码,不可以独立执行(没有main函数入口) 库是否兼容:取决于编译器.汇编器.链接器 linux链接静态库(.a):将库中用到的函数的代码指令,写入到可执行文件中.运行时无依赖 l ...

  9. 第二周day6

    第二周day6,星期六 所花时间:0 代码量:0 搏客量:1 了解到的知识点:多锻炼.

  10. kali WiFi相关研究(学习中...)

    基础环境准备: 笔记本一台E470c(内置网卡 Qualcomm Atheros QCA9377 802.11ac) # 经过测试创建虚拟AP不成功 外置网卡一个:UGREEN 绿联AC1300M,芯 ...