Makefile
build: clean goget
go-1.17 build -o run cmd/main/main.go
clean:
go-1.17 clean --modcache
# 启用go module 需使用该命令更新依赖
goget:
go-1.17 env -w GOPROXY="https://goproxy.cn,direct"
go-1.17 env -w GOPRIVATE="*.xx.com"
go-1.17 env -w GONOPROXY="*.xx.com"
go-1.17 env -w GONOSUMDB="*.xxx.com"
go-1.17 mod tidy
# 开发环境运行
run: build
rm -rf /var/www/go_user
mkdir /var/www/go_user
cp run /var/www/go_user/
cp -r config /var/www/go_user/
docker-compose -f ./docker/docker-compose.yml up
# 静态代码检测 https://pkg.go.dev/cmd/vet
vet: goget
go-1.17 vet ./...
main.go
var engine *gin.Engine
func main() {
Init()
if len(os.Args) == 1 {
engine = routers.Init(routers.Health, router.Routers)
if err := engine.Run(config.AppConfig.Listen); err != nil {
zap_logger.Error(nil,xxx, fmt.Sprintf("startup service failed, err:%v\n", err))
}
} else {
// 有参数就执行命令行程序
base_routers.Cli()
cli.Execute()
}
}
// 初始化都放这里
func Init() {
configFilename := ""
if !config.IsOnline() {
configFilename = fmt.Sprintf("%s/config/app_test.yaml", xxx)
gin.SetMode(gin.DebugMode)
} else {
configFilename = fmt.Sprintf("%s/config/app_prod.yaml",xxx)
gin.SetMode(gin.ReleaseMode)
}
config.AppConfig = config.ParseConfig(configFilename)
if config.AppConfig == nil {
panic("init failed configFilename:" + configFilename)
}
zap_logger.Init()
database.MysqlInit()
redis.RedisInit()
// 一个端口开启 pprof+charts+prometheus
prometheus.AddPrometheus()
monitor.StartPprof()
}
AddPrometheus
func AddPrometheus() {
go func() {
defer func() {
if err := recover(); err != nil {
zap_logger.Errorf(nil, logTag, "prometheus err: %+v", err)
}
}()
server := http.NewServeMux()
server.Handle("/metrics", promhttp.Handler())
// start an http server using the mux server
zap_logger.Errorf(nil, logTag, "prometheus error:%v", http.ListenAndServe(":8000", server))
}()
}
StartPprof
func StartPprof() {
// dev test
if config.IsDev() || config.IsTest() {
go func() {
defer func() {
if err := recover(); err != nil {
zap_logger.Errorf(nil, logTag, "StartPprof %+v", err)
}
}()
//pprof, go tool pprof -http=:16061 http://localhost:8081/debug/pprof/heap
// http://localhost:8081/debug/charts
zap_logger.Errorf(nil, logTag, "prometheus error:%v", http.ListenAndServe(":8081", nil))
}()
}
}
zap_logger
配置
log:
default:
level: debug
file: /logs/gouser.log
backup_num: 1
max_size: 2000
retain_days: 1
初始化
const (
logTmFmtWithMS = "2006-01-02 15:04:05.000"
)
var Logger *zap.Logger
var ZapWriter zapcore.WriteSyncer
// Init 配置日志模块
func Init() {
defaultLog := config.AppConfig.LogConf.Default
var level zapcore.Level
if level.UnmarshalText([]byte(defaultLog.Level)) != nil {
level = zapcore.InfoLevel
}
encoderConfig := zapcore.EncoderConfig{
MessageKey: "msg",
LineEnding: zapcore.DefaultLineEnding,
EncodeDuration: zapcore.StringDurationEncoder,
}
ZapWriter = zapcore.AddSync(&lumberjack.Logger{
Filename: defaultLog.File,
MaxSize: defaultLog.MaxSize, // megabytes
MaxBackups: defaultLog.BackupNum,
MaxAge: defaultLog.RetainDays, // days
LocalTime: true,
})
core := zapcore.NewTee(zapcore.NewCore(
zapcore.NewConsoleEncoder(encoderConfig), zapcore.AddSync(ZapWriter), level))
Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
}
// 后续就可以全局引用 Logger 进行日志打印了
routers
package routers
import (
"github.com/gin-gonic/gin"
)
type Option func(*gin.Engine)
var options = []Option{}
// 注册app的路由配置
func Include(opts ...Option) {
options = append(options, opts...)
}
func RegisterHandler(routerGroup *gin.RouterGroup, path string, handler gin.HandlerFunc) {
routerGroup.GET(path, handler)
routerGroup.POST(path, handler)
}
// 只支持Post
func RegisterPostHandler(routerGroup *gin.RouterGroup, path string, handler gin.HandlerFunc) {
routerGroup.POST(path, handler)
}
// 初始化
func Init(opts ...Option) *gin.Engine {
// 加载多个APP的路由配置
Include(opts...)
r := gin.New()
for _, opt := range options {
opt(r)
}
r.SetTrustedProxies(nil)
return r
}
cli
// CobraRootCmd represents the base command when called without any subcommands
var CobraRootCmd = &cobra.Command{
Use: "root_cmd",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the CobraRootCmd.
func Execute() {
err := CobraRootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
// cli cmd
func Cli() {
// cron
cli.CobraRootCmd.AddCommand(crontab.ClientCmd)
// worker
cli.CobraRootCmd.AddCommand(worker.WorkerCmd)
}
controller
type userController struct {
*controller.BaseController
}
var UserController = new(userController)
//按需获取用户基本信息
func (ctr *userController) GetUserInfosAction(ctx *gin.Context) {
params := &common.Params{}
if ctx.ShouldBind(params) != nil || (!params.Validate()) {
ctr.Fail(ctx, nil, bbt_error.PARAMS_INVALID_ERROR_MSG)
return
}
result := user.GetUserService().GetUserInfos(ctx, params)
ctr.Success(ctx, result)
}