脚手架目录结构
1、配置管理
项目目录下创建setting/setting.go:
package setting
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
// Conf 定义配置的全局变量
var Conf = new(AppConfig)
type AppConfig struct {
Name string `mapstructure:"name"`
Mode string `mapstructure:"mode"`
Version string `mapstructure:"version"`
StartTime string `mapstructure:"start_time"`
MachineID int64 `mapstructure:"machine_id"`
Port int `mapstructure:"port"`
*LogConfig `mapstructure:"log"`
*MySQLConfig `mapstructure:"mysql"`
*RedisConfig `mapstructure:"redis"`
}
type MySQLConfig struct {
Host string `mapstructure:"host"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DB string `mapstructure:"dbname"`
Port int `mapstructure:"port"`
MaxOpenConns int `mapstructure:"max_open_conns"`
MaxIdleConns int `mapstructure:"max_idle_conns"`
}
type RedisConfig struct {
Host string `mapstructure:"host"`
Password string `mapstructure:"password"`
Port int `mapstructure:"port"`
DB int `mapstructure:"db"`
PoolSize int `mapstructure:"pool_size"`
MinIdleConns int `mapstructure:"min_idle_conns"`
}
type LogConfig struct {
Level string `mapstructure:"level"`
Filename string `mapstructure:"filename"`
MaxSize int `mapstructure:"max_size"`
MaxAge int `mapstructure:"max_age"`
MaxBackups int `mapstructure:"max_backups"`
}
// 配置相关
// Init 配置初始化
func Init(filePath string) (err error) {
// 指定配置文件路径
viper.SetConfigFile(filePath)
// 读取配置信息
err = viper.ReadInConfig()
if err != nil {
// 读取配置信息失败
fmt.Printf("viper.ReadInConfig failed, err:%v\n", err)
return
}
// 把读取到的配置信息反序列化到 Conf 变量中
if err := viper.Unmarshal(Conf); err != nil {
fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
return err
}
// 监听配置文件变化
viper.WatchConfig()
// 当使用结构体变量存储配置的时候,需要在配置发生变更后手动更新一下结构体变量
viper.OnConfigChange(func(in fsnotify.Event) {
fmt.Println("配置文件修改了...")
if err := viper.Unmarshal(Conf); err != nil {
fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
}
})
return nil
}
在conf/conf.yaml配置:
name: myapp
mode: dev
version: "1.0"
port: 8099
log:
level: debug
filename: myapp.log
max_size: 400
max_age: 30
max_backups: 15
mysql:
host: 127.0.0.1
port: 3306
user: root
password: root1234
db: db1
MaxOpenConns: 20
MaxIdleConns: 2
2、logger从配置文件读取
Logger/logger.go
package logger
import (
"gin_zap/setting"
"strings"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// initlogger 初始化日志
func Init() (err error) {
// 1、encoder
encndercfg := zap.NewProductionEncoderConfig()
encndercfg.TimeKey = "time" // 改变时间的key
encndercfg.EncodeTime = zapcore.ISO8601TimeEncoder // 更改时间格式
encndercfg.EncodeLevel = zapcore.CapitalLevelEncoder //将日志级别大写并带有颜色
enconder := zapcore.NewJSONEncoder(encndercfg)
// 2、writerSyncer 将日志写到文件和终端
lumberJackLogger1 := &lumberjack.Logger{
Filename: setting.Conf.LogConfig.Filename, // 从配置文件读取
MaxSize: setting.Conf.LogConfig.MaxSize,
MaxBackups: setting.Conf.LogConfig.MaxBackups,
MaxAge: setting.Conf.LogConfig.MaxAge,
Compress: false,
}
lumberJackLogger2 := &lumberjack.Logger{
Filename: strings.Replace(setting.Conf.LogConfig.Filename, ".log", "_err.log", 1),
MaxSize: setting.Conf.LogConfig.MaxSize,
MaxBackups: setting.Conf.LogConfig.MaxBackups,
MaxAge: setting.Conf.LogConfig.MaxAge,
Compress: false,
}
// 3、设置loglevel
level, _ := zapcore.ParseLevel(setting.Conf.LogConfig.Level) // 从配置文件中读取
// 创建zapcore
core1 := zapcore.NewCore(enconder, zapcore.AddSync(lumberJackLogger1), level)
core2 := zapcore.NewCore(enconder, zapcore.AddSync(lumberJackLogger2), zapcore.ErrorLevel) // 将error级别的log单独放在一个文件
core := zapcore.NewTee(core1, core2)
// 创建logger
logger := zap.New(core)
// 替换zap全局的logger
zap.ReplaceGlobals(logger)
zap.L().Info(" logger init success")
return
}
3、数据库初始化
Dao/mysql.go
package dao
// 将之前数据库连接代码写进去
func Init() error {
return nil
}
4、路由初始化
router/router.go
package router
import (
"gin_zap/middleware"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func Init() *gin.Engine {
r := gin.New()
r.Use(middleware.GinLogger(zap.L()), middleware.GinRecovery(zap.L(), true))
r.GET("/littleboy", func(c *gin.Context) {
zap.L().Info("返回一条日志")
})
return r
}
5、路由启动
r.Run()
6、main函数启动
package main
import (
"fmt"
"gin_zap/dao"
"gin_zap/logger"
"gin_zap/router"
"gin_zap/setting"
"os"
"go.uber.org/zap"
)
func main() {
// 1、加载配置
if len(os.Args) < 2 {
panic("执行时必须指定参数")
}
err := setting.Init(os.Args[1])
if err != nil {
panic(err)
}
fmt.Println(setting.Conf.Name)
// 2、 加载日志模块
err = logger.Init()
if err != nil {
panic(err)
}
// 3、数据库初始化
err = dao.Init()
if err != nil {
zap.L().Error("mysql connect error")
}
// 4、路由初始化
r := router.Init()
// 5、程序启动
r.Run()
}