gin-plus最佳实践

217 阅读10分钟

写在前面

前段时间对gin做了再次封装 github.com/aide-cloud/…, 正好我的新项目prometheus- manager github.com/aide-cloud/… 系统还在设计和开发中, 索性就把原本基于 kratos 框架改成gin-plus.

  • prometheus- manager 是用于管理和操作prometheus监控系统的应用系统
  • gin-plus 基于 gin http框架封装的规范性业务库, 旨在简化CRUD, 降低代码冗余, 提升代码可读性

prometheus-manager项目初始化

.
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── prom_agent
│   ├── prom_console
│   └── prom_server
├── deploy
├── doc
├── go.mod
├── go.sum
└── pkg

prom_server

这里只保留了一个模块来演示

./cmd/prom_server
├── cmd.go  # 项目启动文件
├── configs # 配置文件目录
│   ├── config-dev.yaml
│   └── config-pro.yaml
├── core.go # 额外的初始化程序
├── internal # 核心功能都在这里面
│   ├── conf # 服务配置
│   │   ├── conf.go    # 配置相关的结构体
│   │   └── method.go  # 配置相关的结构体方法
│   ├── data # DB、cache、RPC等操作第三方的都放这里
│   │   └── strategy  # 规则模块相关data操作
│   │       └── strategy.go
│   ├── server      # 该项目为多服务程序, 故此这里可以有多个服务初始化
│   │   ├── http.go     # http服务
│   │   ├── timer.go    # 定时器服务
│   │   └── watcher.go  # 监听服务
│   └── service # 业务逻辑都在这里
│       ├── api.go     # 所有服务的入口
│       ├── option.go  # api配置项
│       ├── strategy   # 规则管理模块, 以及它对应的CRUD操作
│           ├── create.go  # 新增规则
│           ├── delete.go  # 删除规则
│           ├── detail.go  # 规则详情
│           ├── edit.go    # 规则编辑
│           ├── list.go    # 规则列表
│           └── strategy.go # 规则模块结构体定义和New方法
└── openapi.yaml  # 生成的api文档

data

strategy.go

// data模块下, 默认都给包名增加了data前缀
package dataStrategy

import (
	"prometheus-manager/pkg/conn"
	"prometheus-manager/pkg/model"
	// gorm-normalize也是对gorm做的业务封装, 旨在规范项目中的DB操作
	// https://github.com/aide-cloud/gorm-normalize
	query "github.com/aide-cloud/gorm-normalize"
	"gorm.io/gorm"
)

type (
	// Strategy 规则模块的data操作结构体定义
	Strategy struct {
		query.IAction[model.PromStrategy] // 组合gorm-normalize库下的action, 该库为范型实现, 这样实现后, 就具备了基本的CRUD动作
		// 下面是基于model.PromStrategy定义的可以做gorm Preload相关的Key
		PreloadAlarmPagesKey query.AssociationKey
		PreloadCategoriesKey query.AssociationKey
		PreloadAlertLevelKey query.AssociationKey
		PreloadGroupInfoKey  query.AssociationKey
	}

	// StrategyOption ...
	StrategyOption func(*Strategy)
)

// NewStrategy 实例化规则模块
func NewStrategy(opts ...StrategyOption) *Strategy {
	strategy := &Strategy{
		IAction: query.NewAction(query.WithDB[model.PromStrategy](conn.GetMysqlDB())), // 注册db action

		PreloadAlarmPagesKey: "AlarmPages",
		PreloadCategoriesKey: "Categories",
		PreloadAlertLevelKey: "AlertLevel",
		PreloadGroupInfoKey:  "GroupInfo",
	}
	for _, o := range opts {
		o(strategy)
	}

	return strategy
}

// 下面是封装的公共的Preload方法, 规范Preload使用

// PreloadAlarmPages preload alarm_pages
func (l *Strategy) PreloadAlarmPages() query.Scopemethod {
	return func(db *gorm.DB) *gorm.DB {
		return db.Preload(string(l.PreloadAlarmPagesKey))
	}
}

// PreloadCategories preload categories
func (l *Strategy) PreloadCategories() query.Scopemethod {
	return func(db *gorm.DB) *gorm.DB {
		return db.Preload(string(l.PreloadCategoriesKey))
	}
}

// PreloadAlertLevel preload alert_level
func (l *Strategy) PreloadAlertLevel() query.Scopemethod {
	return func(db *gorm.DB) *gorm.DB {
		return db.Preload(string(l.PreloadAlertLevelKey))
	}
}

// PreloadGroupInfo preload group_info
func (l *Strategy) PreloadGroupInfo() query.Scopemethod {
	return func(db *gorm.DB) *gorm.DB {
		return db.Preload(string(l.PreloadGroupInfoKey))
	}
}

service

strategy.go 模块定义

package strategy

import (
	ginplus "github.com/aide-cloud/gin-plus"
	"github.com/gin-gonic/gin"
)

var _ IStrategy = (*Strategy)(nil)

type (
	// IStrategy ...
	IStrategy interface {
		// 继承ginplus的两个接口, 然后去实现
		ginplus.Middlewarer // 模块级别的中间件注册接口
		ginplus.MethoderMiddlewarer // 方法级别中间件注册接口
		// add interface method
	}

	// Strategy ...
	Strategy struct {
		// add child module
	}

	// Option ...
	Option func(*Strategy)
)

// defaultStrategy ...
func defaultStrategy() *Strategy {
	return &Strategy{
		// add child module
	}
}

// NewStrategy ...
func NewStrategy(opts ...Option) *Strategy {
	m := defaultStrategy()
	for _, o := range opts {
		o(m)
	}

	return m
}

// Middlewares 添加Strategy模块的公共中间件
func (l *Strategy) Middlewares() []gin.HandlerFunc {
	return []gin.HandlerFunc{
		func(ctx *gin.Context) {
			// your code ...
		},
		// other ...
	}
}

// MethoderMiddlewares 添加Strategy模块的方法级别中间件
func (l *Strategy) MethoderMiddlewares() map[string][]gin.HandlerFunc {
	return map[string][]gin.HandlerFunc{
		// your method middlewares
	}
}

create.go 规则创建

package strategy

import (
	"context"

	query "github.com/aide-cloud/gorm-normalize"
	dataStrategy "prometheus-manager/cmd/prom_server/internal/data/strategy"
	"prometheus-manager/pkg/alert"
	"prometheus-manager/pkg/model"
)

type (
	// CreateStrategyReq 请求参数定义(实现ginplus.IValidater就可以直接校验请求参数, 这里没有去做)
	CreateStrategyReq struct {
		GroupId     uint              `json:"group_id"`
		Alert       string            `json:"alert"`
		Expr        string            `json:"expr"`
		For         string            `json:"for"`
		Labels      alert.Labels      `json:"labels"`
		Annotations alert.Annotations `json:"annotations"`
		// AlarmPageIds 告警页面
		AlarmPageIds []uint `json:"alarm_page_ids"`
		// PromDictIds 规则类型
		PromDictIds []uint `json:"prom_dict_ids"`
		// AlertLevelId 告警级别
		AlertLevelId uint `json:"alert_level_id"`
	}

	// CreateStrategyResp 相应参数定义
	CreateStrategyResp struct {
		ID uint `json:"id"`
	}
)

// Create 创建prom规则
func (l *Strategy) Create(ctx context.Context, req *CreateStrategyReq) (*CreateStrategyResp, error) {
        // 实例化strategy模块data操作
        strategyData := dataStrategy.NewStrategy()

        // 准备gorm db操作中的关联数据
	alarmPages := make([]*model.PromAlarmPage, 0, len(req.AlarmPageIds))
	for _, alarmPageId := range req.AlarmPageIds {
		alarmPages = append(alarmPages, &model.PromAlarmPage{BaseModel: query.BaseModel{ID: alarmPageId}})
	}
	promDicts := make([]*model.PromDict, 0, len(req.PromDictIds))
	for _, promDictId := range req.PromDictIds {
		promDicts = append(promDicts, &model.PromDict{BaseModel: query.BaseModel{ID: promDictId}})
	}
        // 准备即将创建的新规则数据
	newStrategy := &model.PromStrategy{
		GroupID:      req.GroupId,
		Alert:        req.Alert,
		Expr:         req.Expr,
		For:          req.For,
		Labels:       req.Labels,
		Annotations:  req.Annotations,
		AlarmPages:   alarmPages,
		Categories:   promDicts,
		AlertLevelID: req.AlertLevelId,
	}
	// 调用strategyData的创建方法, 创建我们的新规则
	if err := strategyData.WithContext(ctx).Create(newStrategy); err != nil {
		return nil, err
	}
	// your code ...
	return &CreateStrategyResp{ID: newStrategy.ID}, nil
}

delete.go 规则删除

package strategy

import (
	"context"

	dataStrategy "prometheus-manager/cmd/prom_server/internal/data/strategy"
)

type (
	// DeleteStrategyReq 请求参数
	DeleteStrategyReq struct {
		ID uint `uri:"id" binding:"required"` // 这里的ID从url中获取(/strategy/:id)
	}

	// DeleteStrategyResp 响应参数
	DeleteStrategyResp struct {
		ID uint `json:"id"`
	}
)
// Delete 删除规则
func (l *Strategy) Delete(ctx context.Context, req *DeleteStrategyReq) (*DeleteStrategyResp, error) {
	// 实例化data操作
	strategyData := dataStrategy.NewStrategy()
	// 执行删除逻辑
	if err := strategyData.WithContext(ctx).DeleteByID(req.ID); err != nil {
		return nil, err
	}
	return &DeleteStrategyResp{ID: req.ID}, nil
}

edit.go 规则编辑

package strategy

import (
	"context"
	dataStrategy "prometheus-manager/cmd/prom_server/internal/data/strategy"
	"prometheus-manager/pkg/alert"
	"prometheus-manager/pkg/model"

	query "github.com/aide-cloud/gorm-normalize"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

type (
	// EditStrategyReq 请求参数
	EditStrategyReq struct {
		ID uint `uri:"id" binding:"required"` // 修改数据通过ID修改, 所以这里的ID也是放在URL中的

		GroupId     uint              `json:"group_id"`
		Alert       string            `json:"alert"`
		Expr        string            `json:"expr"`
		For         string            `json:"for"`
		Labels      alert.Labels      `json:"labels"`
		Annotations alert.Annotations `json:"annotations"`
		// AlarmPageIds 告警页面
		AlarmPageIds []uint `json:"alarm_page_ids"`
		// PromDictIds 规则类型
		PromDictIds []uint `json:"prom_dict_ids"`
		// AlertLevelId 告警级别
		AlertLevelId uint `json:"alert_level_id"`
	}

	// EditStrategyResp 相应参数
	EditStrategyResp struct {
		ID uint `json:"id"`
	}
)
// Edit 编辑规则
func (l *Strategy) Edit(ctx context.Context, req *EditStrategyReq) (*EditStrategyResp, error) {
	// 实例化data操作
	strategyData := dataStrategy.NewStrategy()
	// 查询要修改的数据是否存在
	firstDetail, err := strategyData.WithContext(ctx).FirstByID(req.ID)
	if err != nil {
		return nil, err
	}
	// 用查到的数据和传入的数据对比, 得到要修改的数据
	updateMap := buildUpdateMap(req, firstDetail)

	alarmPages := make([]schema.Tabler, 0, len(req.AlarmPageIds))
	for _, alarmPageId := range req.AlarmPageIds {
		alarmPages = append(alarmPages, &model.PromAlarmPage{BaseModel: query.BaseModel{ID: alarmPageId}})
	}
	promDicts := make([]schema.Tabler, 0, len(req.PromDictIds))
	for _, promDictId := range req.PromDictIds {
		promDicts = append(promDicts, &model.PromDict{BaseModel: query.BaseModel{ID: promDictId}})
	}
	// 因为这里需要修改规则自身数据, 还要修改规则关联的其他数据, 所以用了事物
	err = strategyData.DB().Transaction(func(tx *gorm.DB) error {
        	// 修改规则自身数据
		if err := strategyData.WithDB(tx).WithContext(ctx).UpdateMapByID(req.ID, updateMap); err != nil {
			return err
		}

		// 替换关联的数据
		if err := strategyData.WithDB(tx).WithContext(ctx).Scopes(query.WhereID(req.ID)).Association().Replace(strategyData.PreloadAlarmPagesKey, alarmPages...); err != nil {
			return err
		}

		if err := strategyData.WithDB(tx).WithContext(ctx).Scopes(query.WhereID(req.ID)).Association().Replace(strategyData.PreloadCategoriesKey, promDicts...); err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &EditStrategyResp{ID: req.ID}, nil
}

// buildUpdateMap 返回要修改的新数据
func buildUpdateMap(req *EditStrategyReq, firstDetail *model.PromStrategy) map[string]any {
	updateMap := map[string]interface{}{}

	if req.GroupId != firstDetail.GroupID {
		updateMap["group_id"] = req.GroupId
	}
	if req.Alert != firstDetail.Alert {
		updateMap["alert"] = req.Alert
	}
	if req.Expr != firstDetail.Expr {
		updateMap["expr"] = req.Expr
	}
	if req.For != firstDetail.For {
		updateMap["for"] = req.For
	}
	if !req.Labels.Equal(firstDetail.Labels) {
		updateMap["labels"] = req.Labels
	}
	if !req.Annotations.Equal(firstDetail.Annotations) {
		updateMap["annotations"] = req.Annotations
	}

	alarmPages := make([]*model.PromAlarmPage, 0, len(req.AlarmPageIds))
	for _, alarmPageId := range req.AlarmPageIds {
		alarmPages = append(alarmPages, &model.PromAlarmPage{BaseModel: query.BaseModel{ID: alarmPageId}})
	}
	updateMap["alarm_pages"] = alarmPages
	promDicts := make([]*model.PromDict, 0, len(req.PromDictIds))
	for _, promDictId := range req.PromDictIds {
		promDicts = append(promDicts, &model.PromDict{BaseModel: query.BaseModel{ID: promDictId}})
	}
	updateMap["categories"] = promDicts

	return updateMap
}

detail.go 规则详情

package strategy

import (
	"context"

	dataStrategy "prometheus-manager/cmd/prom_server/internal/data/strategy"
	"prometheus-manager/pkg/alert"
	"prometheus-manager/pkg/model"
	"prometheus-manager/pkg/times"
)

type (
	// DetailStrategyReq 请求参数
	DetailStrategyReq struct {
		ID uint `uri:"id" binding:"required"` // 这里也是通过ID查询规则详情, 所以ID也是放在URL中

		IsDelete bool `form:"is_delete"` // 这个参数用于控制是否查询已经被软删除的数据, 来自于params
	}

	// DetailStrategyResp 响应参数
	DetailStrategyResp struct {
		Group       *GroupItem        `json:"group"`
		ID          uint              `json:"id"`
		Alert       string            `json:"alert"`
		Expr        string            `json:"expr"`
		For         string            `json:"for"`
		Labels      alert.Labels      `json:"labels"`      // 标签
		Annotations alert.Annotations `json:"annotations"` // 告警文案
		AlarmPages  []*AlarmPageItem  `json:"alarm_pages"`
		Categories  []*CategoryItem   `json:"categories"`
		AlertLevel  *AlertLevelItem   `json:"alert_level"`
		Status      model.Status      `json:"status"`

		CreatedAt int64 `json:"created_at"`
		UpdatedAt int64 `json:"updated_at"`
		DeletedAt int64 `json:"deleted_at"`
	}

	GroupItem struct {
		ID   uint   `json:"id"`
		Name string `json:"name"`
	}

	AlarmPageItem struct {
		ID   uint   `json:"id"`
		Name string `json:"name"`
	}

	CategoryItem struct {
		ID   uint   `json:"id"`
		Name string `json:"name"`
	}

	AlertLevelItem struct {
		ID   uint   `json:"id"`
		Name string `json:"name"`
	}
)

// Detail 规则详情
func (l *Strategy) Detail(ctx context.Context, req *DetailStrategyReq) (*DetailStrategyResp, error) {
	// 实例化data操作
	strategyData := dataStrategy.NewStrategy()

	// 查询规则信息
	var detailInfo *model.PromStrategy
	var err error
	if req.IsDelete {
		detailInfo, err = strategyData.WithContext(ctx).FirstByIDWithTrashed(req.ID)
	} else {
		detailInfo, err = strategyData.WithContext(ctx).FirstByID(req.ID)
	}

	if err != nil {
		return nil, err
	}
	// 组装数据返回
	return &DetailStrategyResp{
		ID:          detailInfo.ID,
		Alert:       detailInfo.Alert,
		Expr:        detailInfo.Expr,
		For:         detailInfo.For,
		Labels:      detailInfo.Labels,
		Annotations: detailInfo.Annotations,
		AlertLevel:  buildAlertLevelItem(detailInfo.AlertLevel),
		AlarmPages:  buildAlarmPageItems(detailInfo.AlarmPages),
		Categories:  buildCategoryItems(detailInfo.Categories),
		Group:       buidGroupItem(detailInfo.GroupInfo),
		Status:      detailInfo.Status,
		CreatedAt:   times.TimeToUnix(detailInfo.CreatedAt),
		UpdatedAt:   times.TimeToUnix(detailInfo.UpdatedAt),
		DeletedAt:   int64(detailInfo.DeletedAt),
	}, nil
}

func buidGroupItem(group *model.PromGroup) *GroupItem {
	if group == nil {
		return nil
	}

	return &GroupItem{
		ID:   group.ID,
		Name: group.Name,
	}
}

func buildAlertLevelItem(alertLevel *model.PromDict) *AlertLevelItem {
	if alertLevel == nil {
		return nil
	}

	return &AlertLevelItem{
		ID:   alertLevel.ID,
		Name: alertLevel.Name,
	}
}

func buildAlarmPageItems(alarmPages []*model.PromAlarmPage) []*AlarmPageItem {
	alarmPageItems := make([]*AlarmPageItem, 0, len(alarmPages))

	for _, alarmPage := range alarmPages {
		if alarmPage == nil {
			continue
		}
		alarmPageItems = append(alarmPageItems, &AlarmPageItem{
			ID:   alarmPage.ID,
			Name: alarmPage.Name,
		})
	}

	return alarmPageItems
}

func buildCategoryItems(categories []*model.PromDict) []*CategoryItem {
	categoryItems := make([]*CategoryItem, 0, len(categories))

	for _, category := range categories {
		if category == nil {
			continue
		}
		categoryItems = append(categoryItems, &CategoryItem{
			ID:   category.ID,
			Name: category.Name,
		})
	}

	return categoryItems
}

list.go 规则列表

package strategy

import (
	"context"

	dataStrategy "prometheus-manager/cmd/prom_server/internal/data/strategy"
	"prometheus-manager/pkg/alert"
	"prometheus-manager/pkg/times"

	query "github.com/aide-cloud/gorm-normalize"
)

type (
	// ListStrategyReq 请求参数
	ListStrategyReq struct {
		Keyword string `form:"keyword"` // 关键字查询
		Curr    int    `form:"curr"` // 分页相关
		Size    int    `form:"size"`
	}

	// ListStrategyResp 响应参数
	ListStrategyResp struct {
		List []*StrategyItem `json:"list"` // 数据列表
		Page *query.Page     `json:"page"` // 分页信息
	}

	StrategyItem struct {
		ID    uint   `json:"id"`
		Alert string `json:"alert"`
		Expr  string `json:"expr"`
		For   string `json:"for"`

		Labels alert.Labels `json:"labels"`
		// Annotations 告警文案
		Annotations alert.Annotations `json:"annotations"`
		// AlertLevel 告警级别
		AlertLevel *AlertLevelItem `json:"alert_level"`
		// GroupInfo 所属规则组
		GroupInfo *GroupItem `json:"group_info"`

		CreatedAt int64 `json:"created_at"`
		UpdatedAt int64 `json:"updated_at"`
		DeletedAt int64 `json:"deleted_at"`
	}
)

// List 规则列表
func (l *Strategy) List(ctx context.Context, req *ListStrategyReq) (*ListStrategyResp, error) {
	// 实例化规则data操作
	strategyData := dataStrategy.NewStrategy()
	// 构建where条件
	wheres := []query.Scopemethod{
		query.WhereLikeKeyword(req.Keyword, "alert"),  // 基于alert字段模糊查询
		strategyData.PreloadAlertLevel(), // 预加载
		strategyData.PreloadGroupInfo(), // 预加载
	}

	// 分页实例
	pgInfo := query.NewPage(req.Curr, req.Size)
	// 执行查询
	strategies, err := strategyData.WithContext(ctx).List(pgInfo, wheres...)
	if err != nil {
		return nil, err
	}
	// 组装响应数据
	list := make([]*StrategyItem, 0, len(strategies))
	for _, strategy := range strategies {
		list = append(list, &StrategyItem{
			ID:          strategy.ID,
			Alert:       strategy.Alert,
			Expr:        strategy.Expr,
			For:         strategy.For,
			Labels:      strategy.Labels,
			Annotations: strategy.Annotations,
			AlertLevel:  buildAlertLevelItem(strategy.AlertLevel),
			GroupInfo:   buidGroupItem(strategy.GroupInfo),
			CreatedAt:   times.TimeToUnix(strategy.CreatedAt),
			UpdatedAt:   times.TimeToUnix(strategy.UpdatedAt),
			DeletedAt:   int64(strategy.DeletedAt),
		})
	}

	return &ListStrategyResp{
		List: list,
		Page: pgInfo,
	}, nil
}

api模块声明

api.go

package service

import (
	alarmHistory "prometheus-manager/cmd/prom_server/internal/service/alarm_history"
	alarmPage "prometheus-manager/cmd/prom_server/internal/service/alarm_page"
	promDict "prometheus-manager/cmd/prom_server/internal/service/prom_dict"
	"prometheus-manager/cmd/prom_server/internal/service/strategy"
	strategyGroup "prometheus-manager/cmd/prom_server/internal/service/strategy_group"

	ginplus "github.com/aide-cloud/gin-plus"
	"github.com/gin-gonic/gin"
)

var _ IApi = (*Api)(nil)

type (
	// IApi ...
	IApi interface {
		ginplus.Middlewarer
		ginplus.MethoderMiddlewarer
		// add interface method
	}

	// Api ...
	Api struct {
		// add child module
		Strategy      *strategy.Strategy
		StrategyGroup *strategyGroup.StrategyGroup
		PromDict      *promDict.PromDict
		AlarmPage     *alarmPage.AlarmPage
		History       *alarmHistory.AlarmHistory
	}

	// ApiOption ...
	ApiOption func(*Api)
)

// defaultApi ...
func defaultApi() *Api {
	return &Api{
		// add child module
	}
}

// NewApi ...
func NewApi(opts ...ApiOption) *Api {
	m := defaultApi()
	for _, o := range opts {
		o(m)
	}

	return m
}

// Middlewares 添加Api模块的公共中间件
func (l *Api) Middlewares() []gin.HandlerFunc {
	return []gin.HandlerFunc{
		func(ctx *gin.Context) {
			// your code ...
		},
		// other ...
	}
}

// MethoderMiddlewares ...
func (l *Api) MethoderMiddlewares() map[string][]gin.HandlerFunc {
	return map[string][]gin.HandlerFunc{
		// your method middlewares
	}
}

server

http.go gin-plus http定义

package server

import (
	"fmt"
	"time"

	"prometheus-manager/cmd/prom_server/internal/conf"
	"prometheus-manager/cmd/prom_server/internal/service"
	alarmHistory "prometheus-manager/cmd/prom_server/internal/service/alarm_history"
	alarmPage "prometheus-manager/cmd/prom_server/internal/service/alarm_page"
	promDict "prometheus-manager/cmd/prom_server/internal/service/prom_dict"
	"prometheus-manager/cmd/prom_server/internal/service/strategy"
	strategyGroup "prometheus-manager/cmd/prom_server/internal/service/strategy_group"

	ginplus "github.com/aide-cloud/gin-plus"
	"github.com/gin-gonic/gin"
	"github.com/go-kratos/kratos/v2/log"
)
// NewHttpServer 实例化http服务
func NewHttpServer(server *conf.Server, looger log.Logger) *ginplus.GinEngine {
	logHelper := log.NewHelper(log.With(looger, "module", "server/server"))
	logHelper.Infof("HttpServer starting")
	middle := ginplus.NewMiddleware()
	var r *gin.Engine
	// 初始化gin实例
	if server.Mode == gin.DebugMode {
		gin.SetMode(gin.DebugMode)
		r = gin.Default()
	} else {
		gin.SetMode(gin.ReleaseMode)
		r = gin.New()
	}

	r.Use(
		middle.Cors(),
		middle.Logger(server.Name, time.DateTime),
	)

	// 初始化ginplus实例
	ginplusEngine := ginplus.New(r,
		ginplus.WithAddr(fmt.Sprintf("%s:%d", server.Http.Host, server.Http.Port)), // 自定义服务地址, 默认8080
		ginplus.AppendHttpMethodPrefixes(httpMethodPrefixes...), // 注册自定义http方法识别的前缀
		// 注册api模块
		ginplus.WithControllers(
			service.NewApi(
				service.WithStrategyApi(strategy.NewStrategy()),
				service.WithStrategyGroupApi(strategyGroup.NewStrategyGroup()),
				service.WithPromDictApi(promDict.NewPromDict()),
				service.WithAlarmPageApi(alarmPage.NewAlarmPage()),
				service.WithAlarmHistoryApi(alarmHistory.NewAlarmHistory()),
			),
		),
	)
	// 注册默认路由
	ginplusEngine.RegisterPing().RegisterSwaggerUI().RegisterMetrics()
	return ginplusEngine
}
// http方法匹配的前缀, 例如CreateUser就会匹配 POST /user
var httpMethodPrefixes = []ginplus.HttpMethod{
	{
		Prefix: "Create",
		Method: ginplus.Post,
	}, {
		Prefix: "Update",
		Method: ginplus.Put,
	}, {
		Prefix: "Edit",
		Method: ginplus.Put,
	}, {
		Prefix: "Delete",
		Method: ginplus.Delete,
	}, {
		Prefix: "Detail",
		Method: ginplus.Get,
	}, {
		Prefix: "List",
		Method: ginplus.Get,
	}, {
		Prefix: "Login",
		Method: ginplus.Post,
	}, {
		Prefix: "Logout",
		Method: ginplus.Post,
	}, {
		Prefix: "Register",
		Method: ginplus.Post,
	},
}

服务启动

cmd.go

package main

import (
	"flag"

	"prometheus-manager/cmd/prom_server/internal/server"
	"prometheus-manager/pkg/hello"
	"prometheus-manager/pkg/plog"

	ginplus "github.com/aide-cloud/gin-plus"
)

var (
	// Version 版本号
	Version string
	// ServiceName 服务名称
	ServiceName = "prom-server"
	// configPath 配置文件路径
	configPath = flag.String("config", "configs/config.yaml", "config file path")
)

func main() {
	flag.Parse()
	bc := Init()
	// 初始化日志
	logger := plog.NewLog()

	hello.FmtASCIIGenerator(ServiceName, Version, bc.GetServer().GetMatadata())

	// 多服务注册
	svs := []ginplus.Server{
		server.NewHttpServer(bc.GetServer(), logger),
		server.NewWatchServer(bc.GetKafka(), bc.GetAlert(), logger),
		server.NewTimer(bc.GetPushStrategy(), logger),
	}

	// 启动gin-plus
	ginplus.NewCtrlC(svs...).Start()
}

启动

❯ make server
Starting development server...
# 根据is_dev判断是否是开发环境,如果是开发环境,使用config-dev.yaml配置文件,否则使用config-prod.yaml配置文件
{"level":"info","msg":"prometheus-manager_server version: "}
prometheus-manager_server service starting...
┌───────────────────────────────────────────────────────────────────────────────────────┐
│                                      _____  _____   ______                            │
│                               /\    |_   _||  __ \ |  ____|                           │
│                              /  \     | | || |  | || |__                              │
│                             / /\ \    | | || |  | ||  __|                             │
│                            / /__\ \  _| |_|| |__| || |____                            │
│                           /_/    \_\|_____||_____/ |______|                           │
│                                 good luck and no bug                                  │
└───────────────────────────────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────────────────────────────
├── Name: prometheus-manager_server
├── Version:
├── ID: WutongMacBook-Pro.local
├── Metadata:
├────── version: 1.0.0
├────── description: prometheus-manager_server is a prometheus manager server
└───────────────────────────────────────────────────────────────────────────────────────

{"level":"info","msg":"moduleserver/servermsgHttpServer starting"}
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] POST   /api/strategy/create      --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] DELETE /api/strategy/delete/:id  --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/strategy/detail/:id  --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] PUT    /api/strategy/edit/:id    --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/strategy/list        --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] POST   /api/strategyGroup/create --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] DELETE /api/strategyGroup/delete/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/strategyGroup/detail/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] PUT    /api/strategyGroup/edit/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] POST   /api/strategyGroup/list   --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] POST   /api/promDict/create      --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] DELETE /api/promDict/delete/:id  --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/promDict/detail/:id  --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] PUT    /api/promDict/edit/:id    --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/promDict/list        --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] POST   /api/alarmPage/create     --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] DELETE /api/alarmPage/delete/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/alarmPage/detail/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] PUT    /api/alarmPage/edit/:id   --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/alarmPage/list       --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/alarmHistory/detail/:id --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /api/alarmHistory/list    --> github.com/aide-cloud/gin-plus.(*GinEngine).newDefaultHandler.func1 (7 handlers)
[GIN-debug] GET    /ping                     --> github.com/aide-cloud/gin-plus.New.func1 (5 handlers)
[GIN-debug] GET    /swagger-ui/*filepath     --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (5 handlers)
[GIN-debug] HEAD   /swagger-ui/*filepath     --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (5 handlers)
[GIN-debug] GET    /openapi/doc/swagger      --> github.com/aide-cloud/gin-plus.registerSwaggerUI.func1 (5 handlers)
[GIN-debug] GET    /metrics                  --> github.com/aide-cloud/gin-plus.registerMetrics.WrapH.func1 (5 handlers)
{"level":"warn","msg":"moduleserver/servermsgNot enabel kafka"}
{"level":"info","msg":"moduleserver/servermsg[WatchServer] server starting"}
2023/10/17 22:04:43 [GIN-PLUS] [INFO] Server is running at 0.0.0.0:8080
{"level":"info","msg":"moduleserver/timermsg[Timer] server starting"}

结尾