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

  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. 靶场练习1:Medium_Socialnetwork

    靶机链接 https://www.vulnhub.com/entry/boredhackerblog-social-network,454/ 信息收集阶段 进行主机的发现,由于已知主机跟Kali在同一 ...

  2. deepinlinux安装golang

    Download 从 Google 官方获取安装包,不用FQ直接访问 http://golang.google.cn,选择 Linux 的安装包如 go1.14.linux-amd64.tar.gz ...

  3. Go语言快速入门

    简介 Go是一个专门针对多处理器系统应用程序的编程进行了优化的,可以媲美C或C++代码的速度,而且更加安全.支持并行进程的语言. Go支持面向对象,而且具有真正的闭包(closures)和反射 (re ...

  4. reduced form(简化式)和structural form(结构式)

    在复习软件构造的时候,我发现了这样一道练习题 例题要求我们对照给出的RI和AF画出相应的映射图.在这里产生了一个疑问,什么是reduced form?是分子小于分母的意思吗? 但是根据给出的答案,并不 ...

  5. JavaScript&TypeScript学习总结

    目录 一.JavaScript学习总结 1.什么是JavaScript 2.变量 3.变量命名 4.操作符 5.遍历语句 6.函数 7.对象 8.数组 二.TypeScript学习总结 1.什么是Ty ...

  6. 微信小程序隐私指引完整填写范本(开发者收集你选中的照片或视频信息,用于?)

    为了分辨用户,开发者将在获取你的明示同意后,收集你的微信昵称.头像.为了显示距离,开发者将在获取你的明示同意后,收集你的位置信息.开发者收集你的地址,用于获取位置信息.开发者收集你的发票信息,用于维护 ...

  7. [Docker-2]排查基于docker部署mysql主从过程中遇到“Slave_IO_Running: Connecting”这个疑难杂症

    关于"Slave_IO_Running: Connecting"的排查方法,已经有很多博客写得清清楚楚了(很多都是复制粘贴..真浪费时间),那么如果已有的常规排查方法都不能解决你的 ...

  8. 【BOOK】数据存储--MongoDB

    MongoDB存储 1.链接MongoDB        指定数据库        指定集合 import pymongo ## 连接数据库 client = pymongo.MongoClient( ...

  9. TP3.2.x判断手机端访问,同一个域名在PC和手机端展示不同模板(半独立式网站)

    首先介绍APP_STATUS内置常量,TP入口文件增加APP_STATUS 参数,  自动加载不同的项目配置文件,通过配置文件指向不同的模块 手机端访问时调用Wap手机模块,实现在手机端访问时展示出手 ...

  10. You are using pip version 8.1.2, however version 23.0 is available.You should consider upgrading via the 'pip install --upgrade pip' command.

    今天使用python2安装es模块时报错: 原因是pip(模块管理工具)版本过低,需先升级pip,再进行安装 先替换pip的镜像,默认镜像拉取慢,还可能会失败 cd ~;mkdir .pip;touc ...