Golang实现redis系列-(1)日志组件的封装

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: Golang实现redis系列-(1)日志组件的封装

日志滚动

前言

虽然zap+Lumberjack可以实现日志切割与归档,但是在项目中用不到太多(越简单越好),此时去学习两个库还不如自己封装一层go内置的log包,以后有了新需求再加或者再重构

需求

  1. 要求每日日志存在xxxx/xx/xx的文件夹中
  2. 日志文件名为filename_n.log
  3. 日志文件的大小有要求
  4. 日志要输出到文件和stdout中

代码

package log
import (
  "fmt"
  "io"
  "log"
  "os"
  "strconv"
  "sync"
  "time"
)
// Settings 存储logger的配置信息,为func Setup提供配置
type Settings struct {
  //文件所在路径
  Path string
  //文件名
  Name string
  //文件后缀
  Ext string
  //时间格式
  TimeFormat string
  //文件夹内文件最大数量
  MaxBackups uint32
  //文件的大小(k)
  MaxSize uint32
  //用于计数到第几个文件
  Cnt int
}
var (
  logger             *log.Logger
  defaultPrefix      = ""
  defaultCallerDepth = 2
  mu                 sync.Mutex
  logPrefix          = ""
  levelFlags         = []string{"ERROR", "FATAL"}
  flags              = log.LstdFlags | log.Lmicroseconds | log.Lshortfile
  filePCB            *os.File
  config             *Settings
  fileStat           os.FileInfo
)
type logLevel int
// log levels
const (
  ERROR logLevel = iota
  FATAL
)
func init() {
  logger = log.New(os.Stdout, defaultPrefix, flags)
}
//检查目录是否存在,true为不存在
func checkNotExist(src string) bool {
  _, err := os.Stat(src)
  return os.IsNotExist(err)
}
//检查目录是否有权限,true为没权限
func checkNotPermission(src string) bool {
  _, err := os.Stat(src)
  return os.IsPermission(err)
}
func isNotExistMkDir(src string) error {
  if notExist := checkNotExist(src); notExist {
    if err := mkDir(src); err != nil {
      return err
    }
  }
  return nil
}
func mkDir(src string) error {
  err := os.MkdirAll(src, os.ModePerm) //Unix permission bits, 0o777
  if err != nil {
    return err
  }
  return nil
}
func mustOpen(fileName, dir string) (*os.File, error) {
  perm := checkNotPermission(dir)
  if perm {
    return nil, fmt.Errorf("permission denied dir: %s", dir)
  }
  err := isNotExistMkDir(dir)
  if err != nil {
    return nil, fmt.Errorf("error during make dir %s, err: %s", dir, err)
  }
  f, err := os.OpenFile(dir+string(os.PathSeparator)+fileName, os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0644)
  if err != nil {
    return nil, fmt.Errorf("fail to open file, err: %s", err)
  }
  return f, nil
}
// Setup 配置logger
func Setup(settings *Settings) {
  config = settings
  if settings.Cnt == 11 {
    settings.Cnt = 1
  }
  if filePCB != nil {
    filePCB.Close()
    filePCB = nil
  }
  dir := settings.Path + time.Now().Format(settings.TimeFormat)
  fileName := fmt.Sprintf("%s_%s.%s",
    settings.Name,
    strconv.Itoa(settings.Cnt),
    settings.Ext)
  logFile, err := mustOpen(fileName, dir)
  if err != nil {
    log.Fatalf("logging.Setup err: %s", err)
  }
  filePCB = logFile
  mw := io.MultiWriter(os.Stdout, logFile)
  logger = log.New(mw, defaultPrefix, flags)
  settings.Cnt++
}
//写入文件时检查文件大小和日期(mustOpen中其实已经会检查日期了)
func checkFileSize() {
  fileStat, _ = filePCB.Stat()
  if fileStat.Size() > int64(config.MaxSize*1024) {
    Setup(config)
  }
}
//设置logger的前缀
func setPrefix(level logLevel) {
  logPrefix = fmt.Sprintf("[%s] ", levelFlags[level])
  logger.SetPrefix(logPrefix)
}
func Error(v ...interface{}) {
  mu.Lock()
  defer mu.Unlock()
  setPrefix(ERROR)
  checkFileSize()
  logger.Println(v...)
}
// Fatal 打印错误日志,然后停止程序
func Fatal(v ...interface{}) {
  mu.Lock()
  defer mu.Unlock()
  setPrefix(FATAL)
  checkFileSize()
  logger.Fatalln(v...)
}
package log_test
import (
  "Gotosp/pkg/log"
  "testing"
)
func TestSetup(t *testing.T) {
  log.Setup(&log.Settings{
    Path:       "logs",
    Name:       "filename",
    Ext:        "log",
    TimeFormat: "2006-01-02",
    MaxBackups: 20, //最多MaxBackups个文件
    MaxSize:    10, //文件最大MaxSize(k)
    Cnt:        1,  //从filename_cnt开始,后期做config配置
  })
  for i := 0; i < 10000; i++ {
    log.Error("ERROR")
  }
  log.Fatal("stop")
}

测试


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
30天前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
22 3
|
2月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
48 3
Golang语言之Prometheus的日志模块使用案例
|
30天前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
49 0
|
1月前
|
NoSQL 网络协议 应用服务中间件
redis,memcached,nginx网络组件
redis,memcached,nginx网络组件
16 0
|
3月前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
123 1
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
3月前
|
消息中间件 监控 搜索推荐
OpenFeign日志组件Logger原理与应用
该文章详细解释了如何在OpenFeign中配置并使用请求和响应的GZIP压缩功能。
|
3月前
|
JSON Go API
一文搞懂 Golang 高性能日志库 - Zap
一文搞懂 Golang 高性能日志库 - Zap
181 2
|
3月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Reids是否可以开启慢日志(slowlog)和执行config指令
【Azure Redis 缓存】Azure Reids是否可以开启慢日志(slowlog)和执行config指令
|
3月前
|
Kubernetes API Docker
在K8S中,如何查看kubelet组件的日志?
在K8S中,如何查看kubelet组件的日志?
|
3月前
|
存储 JSON Go
一文搞懂 Golang 高性能日志库 Zerolog
一文搞懂 Golang 高性能日志库 Zerolog
285 0