golang-IO相关-(logrus,viper)

2026年3月30日 · 461 字 · 3 分钟

在这里介绍了golang的IO相关,包括logrus,viper

golang-IO相关-(logrus,viper)

logrus日志框架

首先要导入两个包

import (
    "fmt"
    "time"

    rotatelogs "github.com/lestrrat-go/file-rotatelogs" //日志分割
    "github.com/sirupsen/logrus"                        //logrus日志框架
)

首先创建一个logger实例

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)
    }

可以是日志携带多余的key-value

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解析配置文件

导入viper的包

import (
    "fmt"
    "path"

    "github.com/spf13/viper"
)

初始化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.WatchConfig()的用法:当配置文件变了重新识别配置文件)

//读取配置的第一种方式
    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)
    }