golang-IO相关-(logrus,viper)
2026年3月30日 · 461 字 · 3 分钟
在这里介绍了golang的IO相关,包括logrus,viper 首先要导入两个包 首先创建一个logger实例 然后可以设置日志的等级,低于这个日志等级会忽略 设置日志格式 实现日志分割 可以是日志携带多余的key-value 设置日志的输入文件 设置日志中间件 完整代码 测试代码 导入viper的包 初始化viper 使用配置文件的内容 第一种方法(这里也展示了dbViper.WatchConfig()的用法:当配置文件变了重新识别配置文件) 第二种方法golang-IO相关-(logrus,viper)
logrus日志框架
import (
"fmt"
"time"
rotatelogs "github.com/lestrrat-go/file-rotatelogs" //日志分割
"github.com/sirupsen/logrus" //logrus日志框架
)
logger := logrus.New() //创建一个logger实例
logger.SetLevel(logrus.WarnLevel)
//普通日志格式
logger.SetFormatter(&logrus.TextFormatter{
// ForceColors: true, //强制显示颜色(仅在某些终端能正常工作)
DisableColors: true, //强制不显示颜色
TimestampFormat: "2006-01-02 15:04:05.000", // 显示ms
})
//JSON日志格式
logger.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05.000", // 显示ms
})
fout, err := rotatelogs.New(
logFile+".%Y%m%d%H", //指定日志文件的路径和名称,路径不存在时会创建
rotatelogs.WithLinkName(logFile), //为最新的一份日志创建软链接
rotatelogs.WithRotationTime(1*time.Hour), //每隔1小时生成一份新的日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), //只留最近7天的日志,或使用WithRotationCount只保留最近的几份日志
)
if err != nil {
panic(err)
}
logEntry := logger.WithFields(logrus.Fields{"name": "dqq", "age": 18}) //日志中携带一些额外的key-value
logger.SetOutput(fout) //设置日志文件
// logger.SetOutput(os.Stdout) //日志输出到终端
logger.SetReportCaller(true) //输出是从哪里调起的日志打印,日志里会包含func和file
logger.AddHook(&AppHook{AppName: "印象简单用于测试中间件的日志"}) //在输出日志【之前】执行钩子
// 实现logrus.Hook接口
type AppHook struct {
AppName string
}
// 适用于哪些Level
func (h *AppHook) Levels() []logrus.Level {
// return logrus.AllLevels
return []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}
}
// 在Fire函数时可读取或修改logrus.Entry
func (h *AppHook) Fire(entry *logrus.Entry) error {
entry.Data["app"] = h.AppName //修改logrus.Entry
fmt.Println(entry.Message+"我是日志中间件") //读取logrus.Entry。比如将 Error、Fatal 和 Panic 级别的错误日志发送到 logstash、kafka 等
return nil
}
package io
import (
"fmt"
"time"
rotatelogs "github.com/lestrrat-go/file-rotatelogs" //日志分割
"github.com/sirupsen/logrus" //logrus日志框架
)
func InitLogrus(logLevel string, logFile string) *logrus.Logger {
logger := logrus.New() //创建一个logger实例
//设置日志级别
switch logLevel {
case "debug":
logger.SetLevel(logrus.DebugLevel)
case "info":
logger.SetLevel(logrus.InfoLevel)
case "warn":
logger.SetLevel(logrus.WarnLevel)
case "error":
logger.SetLevel(logrus.ErrorLevel)
case "fatal":
logger.SetLevel(logrus.FatalLevel)
case "panic":
logger.SetLevel(logrus.PanicLevel)
default:
panic(fmt.Errorf("invalid log level %s", logLevel))
}
//设置日志格式
//普通文本格式
// logger.SetFormatter(&logrus.TextFormatter{
// // ForceColors: true, //强制显示颜色(仅在某些终端能正常工作)
// DisableColors: true, //强制不显示颜色
// TimestampFormat: "2006-01-02 15:04:05.000", // 显示ms
// })
//json格式
logger.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05.000", // 显示ms
})
//实现日志分割
fout, err := rotatelogs.New(
logFile+".%Y%m%d%H", //指定日志文件的路径和名称,路径不存在时会创建
rotatelogs.WithLinkName(logFile), //为最新的一份日志创建软链接
rotatelogs.WithRotationTime(1*time.Hour), //每隔1小时生成一份新的日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), //只留最近7天的日志,或使用WithRotationCount只保留最近的几份日志
)
if err != nil {
panic(err)
}
logger.SetOutput(fout) //设置日志文件
// logger.SetOutput(os.Stdout) //日志输出到终端
logger.SetReportCaller(true) //输出是从哪里调起的日志打印,日志里会包含func和file
logger.AddHook(&AppHook{AppName: "印象简单用于测试中间件的日志"}) //在输出日志【之前】执行钩子
return logger
}
// 实现logrus.Hook接口
type AppHook struct {
AppName string
}
// 适用于哪些Level
func (h *AppHook) Levels() []logrus.Level {
// return logrus.AllLevels
return []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}
}
// 在Fire函数时可读取或修改logrus.Entry
func (h *AppHook) Fire(entry *logrus.Entry) error {
entry.Data["app"] = h.AppName //修改logrus.Entry
fmt.Println(entry.Message + "我是日志中间件") //读取logrus.Entry。比如将 Error、Fatal 和 Panic 级别的错误日志发送到 logstash、kafka 等
return nil
}
package io
import (
"testing"
)
func TestInitLogrus(t *testing.T) {
logger := InitLogrus("info", "./logs/test.log")
logEntry := logger.WithFields(logrus.Fields{"name": "hhh", "age": 18}) //日志中携带一些额外的key-value
logger.Debugf("这是调试日志%s", "1111")
logger.Infof("这是测试日志%s", "2222")
logEntry.Infof("这是测试日志%s", "2222")
logger.Error("这是错误日志")
defer func() {
recover()
}()
logger.Panic("这是恐慌错误日志")
logger.Fatal("这是致命错误日志")
}
viper解析配置文件
import (
"fmt"
"path"
"github.com/spf13/viper"
)
func InitViper(dir, file, FileType string) *viper.Viper {
config := viper.New()
config.AddConfigPath(dir) // 文件所在目录
config.SetConfigName(file) // 文件名(不带路径,不带后缀)
config.SetConfigType(FileType) // 文件类型
if err := config.ReadInConfig(); err != nil {
panic(fmt.Errorf("解析配置文件%s出错:%s", path.Join(dir, file)+"."+FileType, err)) //系统初始化阶段发生任何错误,直接结束进程。logger还没初始化,不能用logger.Fatal()
}
return config
}
//读取配置的第一种方式
dbViper := InitViper("./conf", "mysql", "yaml")
dbViper.WatchConfig() //确保在调用WatchConfig()之前添加了所有的配置路径(AddConfigPath)
if dbViper.IsSet("blog.age") { //检查有没有此项配置
age := dbViper.GetInt("blog.age")
fmt.Println("age", age)
} else {
fmt.Println("blog.age不存在")
}
port := dbViper.GetInt("blog.port") //该项不存在时会返回0值
fmt.Println("port", port)
time.Sleep(10 * time.Second) //10秒之内修改一下配置文件,看看viper能不能读取最新值
port = dbViper.GetInt("blog.port")
fmt.Println("port", port)
//读取配置的第二种方式
logViper := InitViper("./conf", "log", "yaml")
type LogConfig struct {
Level string `mapstructure:"level"` //Tag
File string `mapstructure:"file"`
}
var config LogConfig
if err := logViper.Unmarshal(&config); err != nil {
fmt.Println(err)
t.Fail()
} else {
fmt.Println(config.Level)
fmt.Println(config.File)
}