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

  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. NRF52832中文资料+蓝牙芯片

    [产品应用] Nordic Semiconductor发布采用微型封装尺寸的高性能单芯片低功耗蓝牙SoC器件,瞄准新一代可穿戴产品和空间受限的loT应用.[产品说明]nRF52832晶圆级芯片尺寸封装 ...

  2. 【C++】fstream文件操作

    C语言使用FILE对文件进行操作,常用到的函数有fopen().freopen().fread().fwrite().fclose()等,分别用来打开文件.读写文件.关闭文件. C++可以使用fstr ...

  3. [746] Interlude Update 3

    [746] Interlude Update 3 Client 00 SendProtocolVersion 01 MoveBackwardToLocation 02 Say 03 RequestEn ...

  4. java-javaSE-泛型和反射

    泛型 什么是泛型 泛型,即"参数化类型".顾名思义,就是将类型参数化,然后在使用/调用时传入具体的类型(类型实参). 为什么使用泛型 泛型提高程序操作的可读性和安全性. 例如集合类 ...

  5. 星链技术设计(starlink techriage design)

    1.星链  定义:  星链,是美国太空探索技术公司的一个项目,太空探索技术公司计划在2019年至2024年间在太空搭建由约1.2万颗卫星组成的"星链"网络提供互联网服务,其中158 ...

  6. C - Perform the Combo

    C - Perform the Combo 思路:当读到这个题的时候,第一反应就是枚举,但是,无线超时,没办法,那就变,利用前缀和,减少时间. 代码: #include<iostream> ...

  7. 路飞前台全局css 全局配置文件,安装axios,安装vue-cookies,安装elementui,安装bootstrap和jq,后台主页模块表设计,后台主页模块轮播图接口,录入数据,跨域问题详解

    目录 路飞前台全局css 全局配置文件,安装axios,安装vue-cookies,安装elementui,安装bootstrap和jq,后台主页模块表设计,后台主页模块轮播图接口,录入数据,跨域问题 ...

  8. java将Word转换成PDF方法

    转载1:java将Word转换成PDF三种方法_pdfoptions_Zhsh-7的博客-CSDN博客 转载2:POI 实现 word转成pdf - 挽留匆匆的美丽 - 博客园 (cnblogs.co ...

  9. 05 Java 数组

    Java 数组 一.什么是数组 数组是相同类型数据的有序集合 数组描述的是相同类型的若干个数据,按照一定的顺序排列组合而成 其中每一个数据称为数组元素,每个数组元素可以通过下标来访问它们 二.数组的声 ...

  10. go 的internal 目录

    Go 语言中的软件包推荐按照:组织名/项目名 的形式安排软件包的文件目录结构,一般「项目名」文件目录下还会按照功能.抽象约定.具体实现等维度再划分一些子目录.在 Go 语言里包的导入路径不同则被判定为 ...