详解Go语言中配置文件使用与日志配置


Posted in Golang onJune 01, 2022

只是简单的把GET和POST接口的使用测试了一下。

我还是想按照正常的项目结构调整一下,这篇笔记主要是三个部分:调整项目目录结构、增加配置文件使用、增加日志配置,很常规而且也是每个项目都需要用到的。

项目地址:github地址 

项目结构调整

说先对项目目录结构调整一下,按照我自己的开发习惯,增加了几个目录。

项目结构如下图:

详解Go语言中配置文件使用与日志配置

解释一下目录结构

  • app/constants:主要放置一些常量
  • app/controllers:控制层,熟悉java的不多说。
  • app/errors:异常定义目录
  • app/pojo:结构体定义文件,主要是接口请求的结构体和接口返回的结构体,或者自定义的结构体。
  • app/router:路由文件
  • app/services:服务实现逻辑目录
  • app/utils:工具文件目录
  • config/log:日志配置文件目录,后面会讲到怎么使用。
  • config/toml:配置文件使用,后面会讲到怎么使用。
  • main.go作为程序的主入口。

配置文件使用

在我们项目结构中,经常会使用到配置文件。配置文件里面会记录像mysql用户名、端口、redis配置信息等等内容。下面先配置一下toml_config.go,来对config.toml配置文件读取。

详解Go语言中配置文件使用与日志配置

下面是toml_config.go的内容

package toml
 
import (
    "fmt"
    "github.com/spf13/viper"
)
 
type TomlConfig struct {
    AppName string
    Log     LogConfig
}
 
// 日志保存地址
type LogConfig struct {
    Path  string
    Level string
}
 
var c TomlConfig
 
func init() {
    // 设置文件名
    viper.SetConfigName("config")
    // 设置文件类型
    viper.SetConfigType("toml")
    // 设置文件路径,可以多个viper会根据设置顺序依次查找
    viper.AddConfigPath(".")
    viper.AutomaticEnv()
    err := viper.ReadInConfig()
    if err != nil {
        panic(fmt.Errorf("fatal error config file: %s", err))
    }
 
    viper.Unmarshal(&c)
}
func GetConfig() TomlConfig {
    return c
}

需要安装几个库,命令如下:

go get github.com/natefinch/lumberjack
go get go.uber.org/zap/zapcore

注意,在go文件中,init方法在加载该文件所在包的时候会默认执行。

我们看一下配置的内容,主要是日志级别和存放地址。

验证的话,等下面日志配置好了一起看一下。

详解Go语言中配置文件使用与日志配置

日志配置

下面继续配置一下日志,也可以看到配置文件里面配置的日志级别和存放地址都是日志的配置项。

主要在config/log下的logger.go文件,配置了日志相关内容。

详解Go语言中配置文件使用与日志配置

logger.go的内容如下

package log
 
import (
    "os"
 
    "github.com/natefinch/lumberjack"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)
 
type Field = zap.Field
 
var (
    Logger  *zap.Logger
    String  = zap.String
    Any     = zap.Any
    Int     = zap.Int
    Float32 = zap.Float32
)
 
// logpath 日志文件路径
// loglevel 日志级别
func InitLogger(logpath string, loglevel string) {
    // 日志分割
    hook := lumberjack.Logger{
        Filename:   logpath, // 日志文件路径,默认 os.TempDir()
        MaxSize:    100,     // 每个日志文件保存100M,默认 100M
        MaxBackups: 30,      // 保留30个备份,默认不限
        MaxAge:     7,       // 保留7天,默认不限
 
        Compress: true, // 是否压缩,默认不压缩
    }
    write := zapcore.AddSync(&hook)
    // 设置日志级别
    // debug 可以打印出 info debug warn
    // info  级别可以打印 warn info
    // warn  只能打印 warn
    // debug->info->warn->error
    var level zapcore.Level
    switch loglevel {
    case "debug":
        level = zap.DebugLevel
    case "info":
        level = zap.InfoLevel
    case "error":
        level = zap.ErrorLevel
    case "warn":
        level = zap.WarnLevel
    default:
        level = zap.InfoLevel
    }
    encoderConfig := zapcore.EncoderConfig{
        TimeKey:        "time",
        LevelKey:       "level",
        NameKey:        "logger",
        CallerKey:      "linenum",
        MessageKey:     "msg",
        StacktraceKey:  "stacktrace",
        LineEnding:     zapcore.DefaultLineEnding,
        EncodeLevel:    zapcore.LowercaseLevelEncoder,  // 小写编码器
        EncodeTime:     zapcore.ISO8601TimeEncoder,     // ISO8601 UTC 时间格式
        EncodeDuration: zapcore.SecondsDurationEncoder, //
        EncodeCaller:   zapcore.FullCallerEncoder,      // 全路径编码器
        EncodeName:     zapcore.FullNameEncoder,
    }
    // 设置日志级别
    atomicLevel := zap.NewAtomicLevel()
    atomicLevel.SetLevel(level)
 
    var writes = []zapcore.WriteSyncer{write}
    // 如果是开发环境,同时在控制台上也输出
    if level == zap.DebugLevel {
        writes = append(writes, zapcore.AddSync(os.Stdout))
    }
    core := zapcore.NewCore(
        zapcore.NewConsoleEncoder(encoderConfig),
        // zapcore.NewJSONEncoder(encoderConfig),
        zapcore.NewMultiWriteSyncer(writes...), // 打印到控制台和文件
        // write,
        level,
    )
    // 开启开发模式,堆栈跟踪
    caller := zap.AddCaller()
    // 开启文件及行号
    development := zap.Development()
    // 设置初始化字段,如:添加一个服务器名称
    filed := zap.Fields(zap.String("application", "test-gin"))
    // 构造日志
    Logger = zap.New(core, caller, development, filed)
    Logger.Info("Logger init success")
}

需要安装依赖包,命令如下

go get github.com/spf13/viper

在main.go文件增加logger的初始化加载,看看配置文件和日志是否都生效了。

main.go增加下面的代码

详解Go语言中配置文件使用与日志配置

看一下执行的日志

2022-05-31T21:27:54.964+0800    info   D:/goProject/learn-gin/config/log/logger.go:90 Logger init success    {"application": "test-gin"}
2022-05-31T21:27:54.964+0800   info   D:/goProject/learn-gin/main.go:31  hahahah    {"application": "test-gin"}
2022-05-31T21:27:54.964+0800   info   D:/goProject/learn-gin/main.go:32  config {"application": "test-gin", "config": {"AppName":"learn-gin","Log":{"Path":"logs/learn.log","Level":"debug"}}}

可以看到配置文件内容的打印,还有日志的打印效果,OK,舒服了。

小结

这有几个点要注意下:

1、init()和main()方法是golang默认的两个方法,不需要我们调用,程序执行会自动寻找项目中的这俩方法。如果引入了一个包,会优先执行引入包的init方法,再执行自己包内的init方法。

2、如果go项目构建是报错:missing go.sum entry for module providing package xxxxx

执行一下命令:

go build -mod=mod

到此这篇关于详解Go语言中配置文件使用与日志配置的文章就介绍到这了,更多相关Go语言日志配置内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Golang 相关文章推荐
用golang如何替换某个文件中的字符串
Apr 25 Golang
golang 实现两个结构体复制字段
Apr 28 Golang
使用Golang的channel交叉打印两个数组的操作
Apr 29 Golang
聊聊golang中多个defer的执行顺序
May 08 Golang
Go遍历struct,map,slice的实现
Jun 13 Golang
golang内置函数len的小技巧
Jul 25 Golang
golang中的struct操作
Nov 11 Golang
victoriaMetrics库布隆过滤器初始化及使用详解
Apr 05 Golang
golang连接MySQl使用sqlx库
Apr 14 Golang
GoFrame gredis缓存DoVar Conn连接对象 自动序列化GoFrame gredisDo/DoVar方法Conn连接对象自动序列化/反序列化总结
Jun 14 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 Golang
Go gorilla/sessions库安装使用
Aug 14 Golang
详解Go语言中Get/Post请求测试
Golang实现可重入锁的示例代码
May 25 #Golang
Go web入门Go pongo2模板引擎
May 20 #Golang
Go语言入门exec的基本使用
May 20 #Golang
Golang并发工具Singleflight
May 06 #Golang
深入理解 Golang 的字符串
May 04 #Golang
Golang入门之计时器
May 04 #Golang
You might like
php 购物车实例(申精)
2009/05/11 PHP
Laravel 5.4因特殊字段太长导致migrations报错的解决
2017/10/22 PHP
如何让一个json文件显示在表格里【实现代码】
2016/05/09 Javascript
通过JS和PHP两种方法判断用户请求时使用的浏览器类型
2016/09/01 Javascript
bootstrap导航栏、下拉菜单、表单的简单应用实例解析
2017/01/06 Javascript
jQuery事件详解
2017/02/23 Javascript
AngularJS 霸道的过滤器小结
2017/04/26 Javascript
Node.js 8 中的重要新特性
2017/06/28 Javascript
jquery插件开发之选项卡制作详解
2017/08/30 jQuery
浅析vue深复制
2018/01/29 Javascript
jQuery事件多次绑定与解绑问题实例分析
2019/02/19 jQuery
如何用原生js写一个弹窗消息提醒插件
2019/05/24 Javascript
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
[24:42]VP vs TNC Supermajor小组赛B组 BO3 第三场 6.2
2018/06/03 DOTA
如何优雅地改进Django中的模板碎片缓存详解
2018/07/04 Python
使用python验证代理ip是否可用的实现方法
2018/07/25 Python
Python字典创建 遍历 添加等实用基础操作技巧
2018/09/13 Python
如何通过python的fabric包完成代码上传部署
2019/07/29 Python
python中eval与int的区别浅析
2019/08/11 Python
python模块和包的应用BASE_PATH使用解析
2019/12/14 Python
pyinstaller打包找不到文件的问题解决
2020/04/15 Python
使用python-Jenkins批量创建及修改jobs操作
2020/05/12 Python
Pytorch自定义Dataset和DataLoader去除不存在和空数据的操作
2021/03/03 Python
css sprite简单实例
2016/05/23 HTML / CSS
房地产管理毕业生自荐信
2013/11/04 职场文书
食品安全检查制度
2014/02/03 职场文书
军训拉歌口号
2014/06/13 职场文书
学生穿着不得体检讨书
2014/10/12 职场文书
2014年个人工作总结范文
2014/11/07 职场文书
保险公司反洗钱宣传活动总结
2015/05/08 职场文书
化工厂员工工作总结
2015/10/15 职场文书
六五普法先进个人主要事迹材料
2015/11/03 职场文书
幼儿园心得体会范文
2016/01/21 职场文书
python实现自定义日志的具体方法
2021/05/28 Python
springboot应用服务启动事件的监听实现
2022/04/06 Java/Android
什么是clearfix (一文搞清楚css清除浮动clearfix)
2023/05/21 HTML / CSS