Go语言(十六) 日志项目升级
时间:2022-07-25
本文章向大家介绍Go语言(十六) 日志项目升级,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
日志项目升级
- 升级功能点
- 异步刷盘
- 日志切分
项目结构
xlog/
├── console.go #console日志输出
├── file.go #文件输出(本次优化点)
├── level.go #日志级别类
├── log.go #日志库
├── log_base.go # 基类库
└── tool.go #工具库,用于获取文件名,函数名,所在行
代码拆解
- log.go
package xlog
//定义全局默认的日志类型
var logger XLog = newXLog(XLogTypeFile,XLogLevelDebug,"","default")
type XLog interface {
Init() error //文件初始化
LogDebug(fmt string, args ...interface{})
LogTrace(fmt string, args ...interface{})
LogInfo(fmt string, args ...interface{})
LogWarn(fmt string, args ...interface{})
LogError(fmt string, args ...interface{})
LogFatal(fmt string, args ...interface{})
Close()
SetLevel(level int)
}
func newXLog(logType, level int, filename, module string) XLog {
//定义接口
var logger XLog
switch logType {
case XLogTypeFile:
logger = NewXFile(level,filename, module)
case XLogTypeConsole:
logger = NewXConsole(level, module)
default:
logger = NewXFile(level,filename, module)
}
return logger
}
//封装接口,后期可以直接调用
func Init(logType, level int, filename, module string) (err error){
logger = newXLog(logType,level,filename,module)
return logger.Init()
}
func LogDebug(fmt string, args ...interface{}) {
logger.LogDebug(fmt, args...)
}
func LogTrace(fmt string, args ...interface{}) {
logger.LogTrace(fmt, args...)
}
func LogInfo(fmt string, args ...interface{}) {
logger.LogInfo(fmt, args...)
}
func LogWarn(fmt string, args ...interface{}) {
logger.LogWarn(fmt, args...)
}
func LogError(fmt string, args ...interface{}) {
logger.LogError(fmt, args...)
}
func LogFatal(fmt string, args ...interface{}) {
logger.LogFatal(fmt, args...)
}
func Close() {
logger.Close()
}
func SetLevel(level int) {
logger.SetLevel(level)
}
- log_base.go
package xlog
import (
"fmt"
"os"
"path/filepath"
"time"
)
type LogData struct {
timeStr string
levelStr string
module string
filename string
funcName string
lineNo int
data string
}
type XLogBase struct {
level int
module string
}
func (l *XLogBase) writeLog(file *os.File,logData *LogData) {
fmt.Fprintf(file,"%s %s %s (%s:%s:%d) %sn",
logData.timeStr, logData.levelStr, logData.module,
logData.filename, logData.funcName, logData.lineNo, logData.data)
}
func (l *XLogBase) formatLogger(level int, module, format string, args ...interface{}) *LogData {
now := time.Now()
timeStr := now.Format("2006-01-02 15:04:05.000")
levelStr := getLevelStr(level)
filename, funcName, lineNo := GetLineInfo(5)
filename = filepath.Base(filename)
data := fmt.Sprintf(format, args...)
//fmt.Printf("%s %s %s (%s:%s:%d) %sn",timeStr,leveStr,module,filename,funcName,lineNo,data)
return &LogData{
timeStr: timeStr,
levelStr: levelStr,
module: module,
filename: filename,
funcName: funcName,
lineNo: lineNo,
data: data,
}
}
- level.go
package xlog
const (
XLogLevelDebug = iota
XLogLevelTrace
XLogLevelInfo
XLogLevelWarn
XLogLevelError
XLogLevelFatal
)
const (
XLogTypeFile = iota
XLogTypeConsole
)
func getLevelStr(level int) string {
switch level {
case XLogLevelDebug:
return "DEBUG"
case XLogLevelTrace:
return "TRACE"
case XLogLevelInfo:
return "INFO"
case XLogLevelWarn:
return "WARN"
case XLogLevelError:
return "ERROR"
case XLogLevelFatal:
return "FATAL"
default:
return "UNKNOWN"
}
}
- console.go 本次无更新
package xlog
import (
"os"
)
type XConsole struct {
*XLogBase //指针实现
}
func NewXConsole(level int, module string) XLog {
logger := &XConsole{}
//初始化指针,防止panic
logger.XLogBase = &XLogBase{
level: level,
module: module,
}
return logger
}
//不需要初始化文件写入
func (c *XConsole)Init() error {
return nil
}
func (c *XConsole) LogDebug(format string, args ...interface{}) {
if c.level > XLogLevelDebug {
return
}
logData := c.formatLogger(XLogLevelDebug, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) LogTrace(format string, args ...interface{}) {
if c.level > XLogLevelTrace {
return
}
logData := c.formatLogger(XLogLevelTrace, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) LogInfo(format string, args ...interface{}) {
if c.level > XLogLevelInfo {
return
}
logData := c.formatLogger(XLogLevelInfo, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) LogWarn(format string, args ...interface{}) {
if c.level > XLogLevelWarn {
return
}
logData := c.formatLogger(XLogLevelWarn, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) LogError(format string, args ...interface{}) {
if c.level > XLogLevelError {
return
}
logData := c.formatLogger(XLogLevelError, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) LogFatal(format string, args ...interface{}) {
if c.level > XLogLevelFatal {
return
}
logData := c.formatLogger(XLogLevelFatal, c.module, format, args...)
c.writeLog(os.Stdout,logData)
}
func (c *XConsole) SetLevel(level int) {
c.level = level
}
func (c *XConsole) Close() {}
- file.go 本次更新异步刷盘&日志切分
package xlog
import (
"fmt"
"os"
"sync"
"time"
)
type XFile struct {
filename string
file *os.File
*XLogBase
logChan chan *LogData
wg *sync.WaitGroup
curDay int //也可以按小时去切割,curHour int
}
func (c *XFile) Init() (err error) {
c.file,err = os.OpenFile(c.filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY,0755)
if err != nil {
return
}
return
}
func NewXFile(level int, filename, module string) XLog {
logger := &XFile{
filename: filename,
}
logger.XLogBase = &XLogBase{
module: module,
level: level,
}
logger.curDay = time.Now().Day() // 初始化结构体logger.curHour = time.Now().Hour()
logger.wg = &sync.WaitGroup{} //防止主进程退出,不执行子进程
logger.logChan = make(chan *LogData,10000) //管道初始化
//异步刷日志到磁盘
logger.wg.Add(1)
go logger.syncLog()
return logger
}
func (c *XFile) syncLog() {
//从管道读取日志,然后写入文件
for data := range c.logChan {
c.splitLog() //调用切分日志的操作
c.writeLog(c.file,data)
}
c.wg.Done()
}
func (c *XFile) splitLog() {
now := time.Now()
if now.Day() == c.curDay {
return
}
c.curDay = now.Day() //更新时间 //按小时切分的配置,c.curHour = now.Hour()
c.file.Sync()
c.file.Close()
newFilename := fmt.Sprintf("%s-%04d-%02d-%02d",c.filename,
now.Year(),now.Month(),now.Day())
/*
按小时切分配置
newFilename := fmt.Sprintf("%s-%04d-%02d-%02d-%02d", c.filename,now.Year(), now.Month(), now.Day(), now.Hour())
*/
os.Rename(c.filename,newFilename)
c.Init()
}
func (c *XFile) writeToChan(level int,module string,format string,args ...interface{}) {
logData := c.formatLogger(level, module, format, args...)
select {
case c.logChan <- logData:
default:
}
}
func (c *XFile) LogDebug(format string, args ...interface{}) {
if c.level > XLogLevelDebug {
return
}
c.writeToChan(XLogLevelDebug, c.module, format, args...)
}
func (c *XFile) LogTrace(format string, args ...interface{}) {
if c.level > XLogLevelTrace {
return
}
c.writeToChan(XLogLevelTrace, c.module, format, args...)
}
func (c *XFile) LogInfo(format string, args ...interface{}) {
if c.level > XLogLevelInfo {
return
}
c.writeToChan(XLogLevelInfo, c.module, format, args...)
}
func (c *XFile) LogWarn(format string, args ...interface{}) {
if c.level > XLogLevelWarn {
return
}
c.writeToChan(XLogLevelWarn, c.module, format, args...)
}
func (c *XFile) LogError(format string, args ...interface{}) {
if c.level > XLogLevelError {
return
}
c.writeToChan(XLogLevelError, c.module, format, args...)
}
func (c *XFile) LogFatal(format string, args ...interface{}) {
if c.level > XLogLevelFatal {
return
}
c.writeToChan(XLogLevelFatal, c.module, format, args...)
}
func (c *XFile) SetLevel(level int) {
c.level = level
}
func (c *XFile)Close() {
//管道为空要关闭
if c.logChan != nil {
close(c.logChan)
}
c.wg.Wait()
if c.file != nil {
c.file.Sync() //同步写磁盘
c.file.Close()
}
}
- tool.go
package xlog
import "runtime"
func GetLineInfo(skip int) (filename, funcName string, lineNo int) {
pc, file, line, ok := runtime.Caller(skip)
if ok {
fun := runtime.FuncForPC(pc)
funcName = fun.Name()
}
filename = file
lineNo = line
return
}
测试样例
- 注意事项:
- 可以通过xlog.Debug("xxx")直接打印
- 不同的模块与需要初始化操作
打印落盘需要定义好对应的日志路径以及,模块名
err := xlog.Init(logType, xlog.XLogLevelDebug, "./xlog.log", "xlog_example")
if err != nil {
fmt.Printf("logger init failedn")
return
}
- xlog_example/main.go
package main
import (
"flag"
"fmt"
_"fmt"
"oldBoy/xlog"
)
//写日志测试
func logic() {
for {
xlog.LogDebug("dads1,user_id:%d,username:%s", 12331, "sadsaf")
xlog.LogTrace("dads2")
xlog.LogInfo("dads3")
xlog.LogWarn("dads4")
xlog.LogError("sss1")
xlog.LogFatal("sss2")
}
}
func main() {
var logTypeStr string
flag.StringVar(&logTypeStr, "type", "console", "please input logger type")
flag.Parse()
var logType int
if (logTypeStr == "file") {
logType = xlog.XLogTypeFile
} else {
logType = xlog.XLogTypeConsole
}
xlog.LogDebug("log type is %v", logType)
_ = logType
err := xlog.Init(logType, xlog.XLogLevelDebug, "./xlog.log", "xlog_example")
if err != nil {
fmt.Printf("logger init failedn")
return
}
logic()
xlog.Close()
fmt.Printf("close return")
}
- 前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例
- 前端MVC Vue2学习总结(六)——axios与跨域HTTP请求、Lodash工具库
- spring之config.xml完整版示例
- 前端MVC Vue2学习总结(五)——表单输入绑定、组件
- 【HCTF】2017部分Web出题思路详解
- 前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器
- 如何移除Android应用广告
- 前端MVC Vue2学习总结(三)——模板语法、过滤器、计算属性、观察者、Class 与 Style 绑定
- 前端MVC Vue2学习总结(二)——Vue的实例、生命周期与Vue脚手架(vue-cli)
- hive具体操作
- hive中配置hwi
- 从零开始内网安全渗透学习
- hive启动后相关操作
- 开源API测试工具 Hitchhiker v0.10 - 中文版
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 了解红黑树的起源,理解红黑树的本质
- 在java中进行日期时间比较的4种方法
- 【crossbeam系列】4 crossbeam-channel:加强版channel
- 不想得手指关节炎?帮你提炼IDEA常用代码补全操作
- SpringBoot实现本地存储文件上传及提供HTTP访问服务
- 从 0 到 1 搭建技术中台之 iOS 可视化埋点实践
- 超给力,一键生成数据库文档-数据库表结构逆向工程
- 精讲RestTemplate第6篇-文件上传下载与大文件流式下载
- 【Rust日报】2020-09-12 Apple 使用 Rust 进行底层编程
- 精讲RestTemplate第4篇-POST请求方法使用详解
- 精讲RestTemplate第3篇-GET请求使用方法详解
- 通过JSch运行远程linux主机上的shell脚本
- 精讲RestTemplate第5篇-DELETE、PUT等请求方法使用详解
- 一个小小的签到功能,到底用MySQL还是Redis?
- 在IntelliJ IDEA中多线程并发代码的调试方法