Gin部分中间件使用

1:gin-cors

关于CORS这个大家应该都不陌生,我们在写Gin框架的时候很多时候CORS都是自己写中间件,其实Gin给我们提供了一个中间件,我们下面用一个demo来看看这个中间件如何使用

# 下载
go get -u github.com/gin-contrib/cors
package main

import (
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"time"
)

func main() {
	// 设置为release生产模式
	gin.SetMode(gin.ReleaseMode)
	
	// 初始化Gin
	r := gin.Default()

	// 配置跨域中间件
	CorsMiddleware := cors.New(cors.Config{
		// AllowOrigins 允许跨域的域名
		AllowOrigins: []string{"*"},
		// AllowMethods 是允许客户端请求的跨域协议
		AllowMethods: []string{"PUT", "PATCH", "GET", "POST", "DELETE", "OPTIONS"},
		// AllowHeaders 是允许客户端访问的请求头列表
		AllowHeaders: []string{"Origin"},
		// ExposeHeaders 是允许客户端访问的响应头列表
		ExposeHeaders: []string{"Content-Length", "Authorization"},
		// AllowCredentials 是允许客户端传递cookie等认证信息,如果设置为true,AllowOrigin不能设置为*,必须指定具体的域名
		AllowCredentials: false,
		// AllowOriginFunc 用于自定义跨域请求的域名
		AllowOriginFunc: func(origin string) bool {
			return origin == "https://github.com"
		},
		// MaxAge 设置缓存时间
		MaxAge: 12 * time.Hour,
	})

	// 注册中间件到服务中
	r.Use(CorsMiddleware)

	// 启动服务
	r.Run(":80")
}
# 当然除此之外,我们可以使用默认的配置,基于默认的配置再指定自己的配置
package main

import (
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"time"
)

func main() {
	// 设置为release生产模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化Gin
	r := gin.Default()

	// 配置跨域中间件
	CorsConfig := cors.DefaultConfig()
	CorsConfig.AllowOrigins = []string{"*"}
	CorsConfig.AllowMethods = []string{"PUT", "PATCH", "GET", "POST", "DELETE", "OPTIONS"}
	CorsConfig.AllowHeaders = []string{"Origin"}
	CorsConfig.ExposeHeaders = []string{"Content-Length", "Authorization"}
	CorsConfig.AllowCredentials = false
	CorsConfig.AllowOriginFunc = func(origin string) bool {
		return origin == "https://github.com"
	}
	CorsConfig.MaxAge = 12 * time.Hour
	
	// 注册中间件到服务中
	r.Use(cors.New(CorsConfig))

	// 启动服务
	r.Run(":80")
}
# 当然它还有一个最基本的配置,就是默认,如下
package main

import (
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func main() {
	// 设置为release生产模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化Gin
	r := gin.Default()

	// 使用默认允许所有的跨域请求
	DefaultCorsMiddleware := cors.Default()

	// 注册中间件到服务中
	r.Use(DefaultCorsMiddleware)

	// 启动服务
	r.Run(":80")
}


// 具体的源码
func Default() gin.HandlerFunc {
	config := DefaultConfig()
	config.AllowAllOrigins = true
	return New(config)
}
# 可以看到,这里的cors.Default就是封装了一下DefaultConfig,然后基于DefaultConfig设置了一个AllowAllOrigins,这个其实自己也可以封装,但是这个是默认的一个配置,我们如果没有花里胡哨的配置,然后就可以使用这个,那么这就是gin给我们提供的一个cors中间件

2:gin-csrf

CSRF(跨站请求伪造)这个可能大家不知道,但是我们只需要知道,这个东西是防止伪造正常请求的中间件,不过我们要说明,这个中间件要配合gin-sessions这个包一起使用

# 下载
go get -u github.com/utrack/gin-csrf
package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	csrf "github.com/utrack/gin-csrf"
)

func main() {
	// 设置为release生产模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化Gin
	r := gin.Default()

	// store 是一个 session 存储接口
	store := cookie.NewStore([]byte("secret"))

	// session 是一个 session 管理器
	session := sessions.Sessions("mysession", store)

	CsrfMiddleware := csrf.Middleware(csrf.Options{
		// Secret 用于生成 token
		Secret: "secret123",
		// ErrorFunc 用于处理触发CSRF的错误信息
		ErrorFunc: func(c *gin.Context) {
			c.String(400, "CSRF token mismatch")
			c.Abort()
		},
	})

	// 注册中间件
	r.Use(session, CsrfMiddleware)

	// 设置测试路由
	r.GET("/protected", func(c *gin.Context) {
		c.String(200, csrf.GetToken(c))
	})

	r.POST("/protected", func(c *gin.Context) {
		c.String(200, "CSRF token is valid")
	})

	// 启动服务
	r.Run(":80")
}
下面是测试
PS D:\Codes\gin_middleware> curl.exe 127.0.0.1/protected        
KeUQvjl3s1A-Bs9oNQfBp1IqPoo=

PS D:\Codes\gin_middleware> curl.exe -X POST 127.0.0.1/protected
CSRF token mismatch

# 针对以上的例子,解释一下CSRF的原理:
1. 用户访问受保护的页面,服务器生成一个token,并存储在session中,并返回给用户
2. 用户提交表单,包含token
3. 服务器验证token是否有效
4. 验证通过,执行操作
5. 验证失败,返回错误信息

3:gin-jwt

其实gin-jwt是在jwt-go来提供身份验证的,它主要是基于jwt-go封装了一层,提供了更多的函数供我们直接调用,并且提供了生成Token和刷新Token的处理程序,然后我们下面来看看这个demo

# 下载
go get -u github.com/appleboy/gin-jwt/v2
package main

import (
	"log"
	"net/http"
	"os"
	"time"

	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
)

type login struct {
	Username string `form:"username" json:"username" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

var identityKey = "id"

func helloHandler(c *gin.Context) {
	claims := jwt.ExtractClaims(c)
	user, _ := c.Get(identityKey)
	c.JSON(200, gin.H{
		"userID":   claims[identityKey],
		"userName": user.(*User).UserName,
		"text":     "Hello World.",
	})
}

// User demo
type User struct {
	UserName  string
	FirstName string
	LastName  string
}

func main() {
	gin.SetMode(gin.ReleaseMode)

	port := os.Getenv("PORT")
	r := gin.Default()

	if port == "" {
		port = "80"
	}

	authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
		Realm:       "test zone",
		Key:         []byte("secret key"),
		Timeout:     time.Hour,
		MaxRefresh:  time.Hour,
		IdentityKey: identityKey,
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			if v, ok := data.(*User); ok {
				return jwt.MapClaims{
					identityKey: v.UserName,
				}
			}
			return jwt.MapClaims{}
		},
		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)
			return &User{
				UserName: claims[identityKey].(string),
			}
		},
		Authenticator: func(c *gin.Context) (interface{}, error) {
			var loginVals login
			if err := c.ShouldBind(&loginVals); err != nil {
				return "", jwt.ErrMissingLoginValues
			}
			userID := loginVals.Username
			password := loginVals.Password

			if (userID == "admin" && password == "admin") || (userID == "test" && password == "test") {
				return &User{
					UserName:  userID,
					LastName:  "Bo-Yi",
					FirstName: "Wu",
				}, nil
			}

			return nil, jwt.ErrFailedAuthentication
		},
		Authorizator: func(data interface{}, c *gin.Context) bool {
			if v, ok := data.(*User); ok && v.UserName == "admin" {
				return true
			}

			return false
		},
		Unauthorized: func(c *gin.Context, code int, message string) {
			c.JSON(code, gin.H{
				"code":    code,
				"message": message,
			})
		},

		TokenLookup: "header: Authorization, query: token, cookie: jwt",

		TokenHeadName: "Bearer",

		TimeFunc: time.Now,
	})

	if err != nil {
		log.Fatal("JWT Error:" + err.Error())
	}

	errInit := authMiddleware.MiddlewareInit()

	if errInit != nil {
		log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
	}

	r.POST("/login", authMiddleware.LoginHandler)

	r.NoRoute(authMiddleware.MiddlewareFunc(), func(c *gin.Context) {
		claims := jwt.ExtractClaims(c)
		log.Printf("NoRoute claims: %#v\n", claims)
		c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
	})

	auth := r.Group("/auth")
	auth.GET("/refresh_token", authMiddleware.RefreshHandler)
	auth.Use(authMiddleware.MiddlewareFunc())
	{
		auth.GET("/hello", helloHandler)
	}

	if err := http.ListenAndServe(":"+port, r); err != nil {
		log.Fatal(err)
	}
}
# 验证一下,登录获取Token
PS D:\Codes\gin_middleware> http -v --json POST 127.0.0.1/login username=admin password=admin
POST /login HTTP/1.1
Accept-Encoding: gzip
Content-Length: 39
Content-Type: application/json
Host: 127.0.0.1
User-Agent: httpie-go/0.7.0

{
    "password": "admin",
    "username": "admin"
}

HTTP/1.1 200 OK
Content-Length: 212
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 15:27:29 GMT

{
    "code": 200,
    "expire": "2023-08-12T00:27:29+08:00",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzEyNDksImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTY5MTc2NzY0OX0.VBSmu_jcsDPGZWmljQekgv5r3yV9TnjolEFQFfmaalA"
}


# 刷新Token
PS D:\Codes\gin_middleware> http -v -f GET 127.0.0.1/auth/refresh_token "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzEyNDksImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTY5MTc2NzY0OX0.VBSmu_jcsDPGZWmljQekgv5r3yV9TnjolEFQFfmaalA"  "Content-Type: application/json"     
GET /auth/refresh_token HTTP/1.1
Accept-Encoding: gzip
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzEyNDksImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTY5MTc2NzY0OX0.VBSmu_jcsDPGZWmljQekgv5r3yV9TnjolEFQFfmaalA
Content-Type: application/json
Host: 127.0.0.1
User-Agent: httpie-go/0.7.0


HTTP/1.1 200 OK
Content-Length: 212
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 15:28:54 GMT

{
    "code": 200,
    "expire": "2023-08-12T00:28:54+08:00",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzEzMzQsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTY5MTc2NzczNH0.cZoCIkGZM6zWUovXUHbFaSneunNcSQLzSColZ9DPN-A"
}

# 验证Token登录
PS D:\Codes\gin_middleware> http -f GET 127.0.0.1/auth/hello "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzEzMzQsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTY5MTc2NzczNH0.cZoCIkGZM6zWUovXUHbFaSneunNcSQLzSColZ9DPN-A"  "Content-Type: application/json"
HTTP/1.1 200 OK
Content-Length: 59
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 15:47:04 GMT

{
    "text": "Hello World.",
    "userID": "admin",
    "userName": "admin"
}

# 验证test,登录test获取Token
PS D:\Codes\gin_middleware> http -v --json POST 127.0.0.1/login username=test password=test                                                                                                                                             
POST /login HTTP/1.1                                  
Accept-Encoding: gzip
Content-Length: 37
Content-Type: application/json
Host: 127.0.0.1
User-Agent: httpie-go/0.7.0

{
    "password": "test",
    "username": "test"
}

HTTP/1.1 200 OK
Content-Length: 211
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 15:49:02 GMT

{
    "code": 200,
    "expire": "2023-08-12T00:49:02+08:00",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzI1NDIsImlkIjoidGVzdCIsIm9yaWdfaWF0IjoxNjkxNzY4OTQyfQ.WycfOCswPuQjXYHCYdLC_8NkYEm1H5hSiiL4VDXdKHQ"
}

# 使用Test的Token验证
PS D:\Codes\gin_middleware> http -f GET 127.0.0.1/auth/hello "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NzI1NDIsImlkIjoidGVzdCIsIm9yaWdfaWF0IjoxNjkxNzY4OTQyfQ.WycfOCswPuQjXYHCYdLC_8NkYEm1H5hSiiL4VDXdKHQ"  "Content-Type: application/json"
HTTP/1.1 403 Forbidden
Content-Length: 74
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 15:49:14 GMT
Www-Authenticate: JWT realm=test zone

{
    "code": 403,
    "message": "you don't have permission to access this resource"
}

# 可以看到,test的权限是不足的,那么,这就是JWT的一个中间件了

# 这里我用的工具是httpie-go这个工具,你们可以用自己喜欢的,比如curl等,这里看到了我们传递了程序中指定的账号密码,返回了Token和Token的过期时间
工具地址:https://github.com/nojima/httpie-go

4:gin-location

它其实主要用于公开主机的地址和服务协议,我们可以理解为它是一个注册中心,那么这个就好理解了,我们主要来看demo吧

# 下载
go get -u github.com/gin-contrib/location
package main

import (
	"github.com/gin-contrib/location"
	"github.com/gin-gonic/gin"
)

func main() {
	gin.SetMode(gin.ReleaseMode)

	r := gin.Default()

	r.Use(location.Default())

	r.GET("/", func(c *gin.Context) {
		url := location.Get(c)
		url.Scheme = "https"
		url.Host = "www.baidu.com"
		url.Path = "/"
		c.JSON(200, gin.H{
			"location": url,
		})
	})

	r.Run(":80")
}

// 默认配置如下
func Default() gin.HandlerFunc {
	config := DefaultConfig()
	return New(config)
}

// DefaultConfig具体代码如下
func DefaultConfig() Config {
	return Config{
		Host:   "localhost:8080",
		Scheme: "http",
		Headers: Headers {
			Scheme: "X-Forwarded-Proto",
			Host:   "X-Forwarded-For",
		},
	}
}
# 这里引入的是一个默认的配置,我们下面配置的就是把这个默认配置改成了自定义的配置了当然我们在上面也是对其进行了更改的,下面我们验证一下
PS D:\Codes\gin_middleware> http http://127.0.0.1/
HTTP/1.1 200 OK
Content-Length: 183
Content-Type: application/json; charset=utf-8
Date: Fri, 11 Aug 2023 16:26:27 GMT

{
    "location": {
        "Scheme": "https",
        "Opaque": "",
        "User": null,
        "Host": "www.baidu.com",
        "Path": "/",
        "RawPath": "",
        "OmitHost": false,
        "ForceQuery": false,
        "RawQuery": "",
        "Fragment": "",
        "RawFragment": ""
    }
}

# 这样我们可以理解为,我们的百度这个服务就被我们注册到这个路由上了,我们可以通过调用这个路由然后去发现这个服务

5:gin-limiter

限流中间件,我们利用Redis来存储IP的访问次数,实现限流,我们依赖两个包

# 下载
go get -u github.com/go-redis/redis/v8
go get -u github.com/davidleitw/gin-limiter
package main

import (
	limiter "github.com/davidleitw/gin-limiter"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"log"
)

func main() {
	gin.SetMode(gin.ReleaseMode)

	// 初始化redis客户端
	rdb := redis.NewClient(&redis.Options{
		Addr:     "10.0.0.11:31647",
		Password: "",
		DB:       0,
	})

	// 测试redis是否连接成功
	_, err := rdb.Ping(rdb.Context()).Result()
	if err != nil {
		log.Println(err)
	}

	// limiter.LimitDispatcher(限制规则, 限制数量, redis客戶端)
	dispatcher, err := limiter.LimitDispatcher("24-M", 100, rdb)
	if err != nil {
		log.Println(err)
	}

	// 初始化gin
	r := gin.Default()

	// 配置路由并使用限制器
	r.GET("/test", dispatcher.MiddleWare("4-M", 20), func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello World!",
		})
	})

	r.POST("/test", dispatcher.MiddleWare("5-M", 10), func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello World!",
		})
	})

	// 启动gin
	err = r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 启动并验证
PS D:\Codes\gin_middleware> http http://127.0.0.1/test
HTTP/1.1 200 OK
Content-Length: 26
Content-Type: application/json; charset=utf-8
Date: Sat, 12 Aug 2023 06:53:41 GMT
X-Ratelimit-Limit-Global: 100
X-Ratelimit-Limit-Route: 20
X-Ratelimit-Remaining-Global: 99
X-Ratelimit-Remaining-Route: 19
X-Ratelimit-Reset-Global: 2023-08-12 15:17:41
X-Ratelimit-Reset-Route: 2023-08-12 14:57:41

{
    "message": "Hello World!"
}
... 

# 请求20次之后
PS D:\Codes\gin_middleware> http http://127.0.0.1/test
HTTP/1.1 429 Too Many Requests
Content-Length: 21
Content-Type: application/json; charset=utf-8
Date: Sat, 12 Aug 2023 06:53:51 GMT

"2023-08-12 15:17:41"

# 可以看到,20次之后我们就被限流了,这是一个GET的方法,然后我们再看看POST的接口
PS D:\Codes\gin_middleware> http POST http://127.0.0.1/test
HTTP/1.1 200 OK
Content-Length: 26
Content-Type: application/json; charset=utf-8
Date: Sat, 12 Aug 2023 06:56:12 GMT
X-Ratelimit-Limit-Global: 100
X-Ratelimit-Limit-Route: 10
X-Ratelimit-Remaining-Global: 7
X-Ratelimit-Remaining-Route: 71
X-Ratelimit-Reset-Global: 2023-08-12 15:17:41
X-Ratelimit-Reset-Route: 2023-08-12 15:01:09

{
    "message": "Hello World!"
}

# 请求10次之后
PS D:\Codes\gin_middleware> http POST http://127.0.0.1/test
HTTP/1.1 429 Too Many Requests
Content-Length: 21
Content-Type: application/json; charset=utf-8
Date: Sat, 12 Aug 2023 06:56:13 GMT

"2023-08-12 15:17:41"

# 同样我们也被限流了,当然,我们还有一个更简单的限流工具,我们来看看它

7:gin-limit

如果我们不想接入Redis的话,我们就可以使用这个中间件来实现,下面我们用demo验证一下

# 下载
go get -u github.com/aviddiviner/gin-limit
package main

import (
	limit "github.com/aviddiviner/gin-limit"
	"github.com/gin-gonic/gin"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 使用中间件
	r.Use(limit.MaxAllowed(20))

	// 配置路由并使用限制器
	r.GET("/test", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello World!",
		})
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}

// limit.MaxAllowed具体的实现源码
func MaxAllowed(n int) gin.HandlerFunc {
	sem := make(chan struct{}, n)
	acquire := func() { sem <- struct{}{} }
	release := func() { <-sem }
	return func(c *gin.Context) {
		acquire() // before request
		defer release() // after request
		c.Next()
		
	}
}
# 实现结果
# 配置前
PS D:\Codes\gin_middleware> ab.exe -n 400 -c 12 -t 20 http://127.0.0.1/test
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
......

Server Software:
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /test
Document Length:        26 bytes

Concurrency Level:      12
Time taken for tests:   8.597 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      7450000 bytes
HTML transferred:       1300000 bytes
Requests per second:    5815.81 [#/sec] (mean)
Time per request:       2.063 [ms] (mean)
Time per request:       0.172 [ms] (mean, across all concurrent requests)
Transfer rate:          846.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       5
Processing:     0    2   0.6      2      13
Waiting:        0    1   0.7      1      11
Total:          0    2   0.6      2      13

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      3
  95%      3
  98%      3
  99%      4
 100%     13 (longest request)

# 配置后
PS D:\Codes\gin_middleware> ab.exe -n 400 -c 12 -t 20 http://127.0.0.1/test
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
......

Server Software:
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /test
Document Length:        26 bytes

Concurrency Level:      12
Time taken for tests:   8.657 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      7450000 bytes
HTML transferred:       1300000 bytes
Requests per second:    5775.92 [#/sec] (mean)
Time per request:       2.078 [ms] (mean)
Time per request:       0.173 [ms] (mean, across all concurrent requests)
Transfer rate:          840.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       5
Processing:     0    2   0.7      2      21
Waiting:        0    1   0.8      1      21
Total:          0    2   0.7      2      21

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      3
  95%      3
  98%      3
  99%      4
 100%     21 (longest request)

8:go-gin-prometheus

这个是我们用Gin写程序的时候基于Prometheus的一个Exporter包,我们可以用它暴露一个接口,专门提供Prometheus监控

# 下载
go get github.com/zsais/go-gin-prometheus
package main

import (
	"github.com/gin-gonic/gin"
	ginprometheus "github.com/zsais/go-gin-prometheus"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 初始化prometheus中间件
	p := ginprometheus.NewPrometheus("gin")

	// 将gin引入
	p.Use(r)

	// 初始化监控Metrics接口
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 验证
PS D:\Codes\gin_middleware> http http://127.0.0.1/                         
HTTP/1.1 200 OK
Content-Length: 25
Content-Type: application/json; charset=utf-8
Date: Sun, 13 Aug 2023 13:06:38 GMT

{
    "message": "hello world"
}

# 验证监控,它默认是/metrics,当然,我们可以直接用p.MetricsPath来指定监控路径哈,默认是/metrics

# 验证监控接口
PS D:\Codes\gin_middleware> http http://127.0.0.1/metrics
HTTP/1.1 200 OK
Content-Type: text/plain; version=0.0.4; charset=utf-8
Date: Sun, 13 Aug 2023 13:11:26 GMT

# HELP gin_request_duration_seconds The HTTP request latencies in seconds.
# TYPE gin_request_duration_seconds summary
gin_request_duration_seconds_sum 0.0007537
gin_request_duration_seconds_count 3
# HELP gin_request_size_bytes The HTTP request sizes in bytes.
# TYPE gin_request_size_bytes summary
gin_request_size_bytes_sum 1632
gin_request_size_bytes_count 3
# HELP gin_requests_total How many HTTP requests processed, partitioned by status code and HTTP method.
# TYPE gin_requests_total counter
gin_requests_total{code="200",handler="main.main.func1",host="127.0.0.1",method="GET",url="/"} 2
gin_requests_total{code="404",handler="github.com/zsais/go-gin-prometheus.(*Prometheus).HandlerFunc.func1",host="127.0.0.1",method="GET",url="/favicon.ico"} 1
# HELP gin_response_size_bytes The HTTP response sizes in bytes.
# TYPE gin_response_size_bytes summary
gin_response_size_bytes_sum 49
gin_response_size_bytes_count 3
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 6
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 8
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.20.4"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 1.774304e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 4.39404e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 7229
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 18264
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 7.211832e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 1.774304e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 8.257536e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 4.030464e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 9809
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 7.979008e+06
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 1.2288e+07
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.6919322382780173e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 28073
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 14016
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16352
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 126560
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 130560
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.194304e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 1.673499e+06
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 294912
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 294912
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 2.1622384e+07
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 11
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.015625
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.6777216e+07
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 135
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.6252928e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.691931584e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 2.4154112e+07
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 1
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0


# 例如,如果您有一个模板化路线,并且不想为每个可能的客户名称生成时间序列,则可以向中间件提供此映射函数:/customer/:name
package main

import (
	"github.com/gin-gonic/gin"
	ginprometheus "github.com/zsais/go-gin-prometheus"
	"log"
	"strings"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 初始化prometheus中间件
	p := ginprometheus.NewPrometheus("gin")

	p.ReqCntURLLabelMappingFn = func(c *gin.Context) string {
		url := c.Request.URL.Path
		for _, p := range c.Params {
			if p.Key == "name" {
				url = strings.Replace(url, p.Value, ":name", 1)
				break
			}
		}
		return url
	}

	p.Use(r)

	r.GET("/", func(c *gin.Context) {
		c.JSON(200, "Hello world!")
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 这将映射并映射到他们的 模板,从而保持低基数 我们的指标。/customer/alice/customer/bob/customer/:name

9:ginprom

# 其实我觉得上面那个包,并不是特别的好用,我还是比较喜欢用下面这个包的

# 下载
go get -u github.com/chenjiandongx/ginprom
package main

import (
	"github.com/chenjiandongx/ginprom"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 初始化Prometheus客户端
	p := ginprom.PromMiddleware(nil)

	// 注册Prometheus监控中间件
	r.Use(p)

	// 注册Prometheus监控路由
	r.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))

	// 使用路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello World!",
		})
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 验证
PS D:\Codes\gin_middleware> http http://127.0.0.1/metrics             
HTTP/1.1 200 OK
Content-Type: text/plain; version=0.0.4; charset=utf-8
Date: Sun, 13 Aug 2023 13:42:48 GMT

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0.0005035
go_gc_duration_seconds{quantile="0.25"} 0.0005035
go_gc_duration_seconds{quantile="0.5"} 0.0005035
go_gc_duration_seconds{quantile="0.75"} 0.0005035
go_gc_duration_seconds{quantile="1"} 0.0005035
go_gc_duration_seconds_sum 0.0005035
go_gc_duration_seconds_count 1
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 7
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.20.4"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 1.70396e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 3.179688e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 7218
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 16236
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 6.565848e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 1.70396e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 4.063232e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 3.997696e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 9495
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 3.514368e+06
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 8.060928e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.6919340856959622e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 25731
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 14016
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16352
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 95840
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 97920
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.194304e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 905014
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 327680
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 327680
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 1.598096e+07
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 9
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.015625
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.6777216e+07
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 119
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.5040512e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.691934085e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 2.2925312e+07
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 0
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
# HELP service_uptime HTTP service uptime.
# TYPE service_uptime counter
service_uptime 82

# 我们请求一次/接口之后的结果

PS D:\Codes\gin_middleware> http http://127.0.0.1/metrics
HTTP/1.1 200 OK
Content-Type: text/plain; version=0.0.4; charset=utf-8
Date: Sun, 13 Aug 2023 13:44:46 GMT

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0.0005035
go_gc_duration_seconds{quantile="0.75"} 0.0005035
go_gc_duration_seconds{quantile="1"} 0.0005035
go_gc_duration_seconds_sum 0.0005035
go_gc_duration_seconds_count 2
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 7
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.20.4"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 2.59308e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 4.219792e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 7218
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 17778
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 7.114344e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 2.59308e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 3.31776e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 4.775936e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 9749
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 2.449408e+06
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 8.093696e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.6919342057001953e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 27527
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 14016
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16352
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 95840
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 97920
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 5.6048e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 946342
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 294912
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 294912
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 1.6570784e+07
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 10
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.015625
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.6777216e+07
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 128
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.6953344e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.691934085e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 2.4629248e+07
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 1
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
# HELP service_http_request_count_total Total number of HTTP requests made.
# TYPE service_http_request_count_total counter
service_http_request_count_total{endpoint="/",method="GET",status="200"} 1
service_http_request_count_total{endpoint="/metrics",method="GET",status="200"} 1
# HELP service_http_request_duration_seconds HTTP request latencies in seconds.
# TYPE service_http_request_duration_seconds histogram
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.005"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.01"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.025"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.05"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.1"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.25"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="0.5"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="1"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="2.5"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="5"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="10"} 1
service_http_request_duration_seconds_bucket{endpoint="/",method="GET",status="200",le="+Inf"} 1
service_http_request_duration_seconds_sum{endpoint="/",method="GET",status="200"} 0
service_http_request_duration_seconds_count{endpoint="/",method="GET",status="200"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.005"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.01"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.025"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.05"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.1"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.25"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="0.5"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="1"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="2.5"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="5"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="10"} 1
service_http_request_duration_seconds_bucket{endpoint="/metrics",method="GET",status="200",le="+Inf"} 1
service_http_request_duration_seconds_sum{endpoint="/metrics",method="GET",status="200"} 0.0009488
service_http_request_duration_seconds_count{endpoint="/metrics",method="GET",status="200"} 1
# HELP service_http_request_size_bytes HTTP request sizes in bytes.
# TYPE service_http_request_size_bytes summary
service_http_request_size_bytes_sum{endpoint="/",method="GET",status="200"} 65
service_http_request_size_bytes_count{endpoint="/",method="GET",status="200"} 1
service_http_request_size_bytes_sum{endpoint="/metrics",method="GET",status="200"} 72
service_http_request_size_bytes_count{endpoint="/metrics",method="GET",status="200"} 1
# HELP service_http_response_size_bytes HTTP response sizes in bytes.
# TYPE service_http_response_size_bytes summary
service_http_response_size_bytes_sum{endpoint="/",method="GET",status="200"} 26
service_http_response_size_bytes_count{endpoint="/",method="GET",status="200"} 1
service_http_response_size_bytes_sum{endpoint="/metrics",method="GET",status="200"} 1330
service_http_response_size_bytes_count{endpoint="/metrics",method="GET",status="200"} 1
# HELP service_uptime HTTP service uptime.
# TYPE service_uptime counter
service_uptime 201
名字 类型 公开的信息
service_uptime 计数器 HTTP 服务正常运行时间。
service_http_request_count_total 计数器 发出的 HTTP 请求总数。
service_http_request_duration_seconds 直方图 HTTP 请求延迟(以秒为单位)。
service_http_request_size_bytes 总结 HTTP 请求大小(以字节为单位)。
service_http_response_size_bytes 总结 HTTP 响应大小(以字节为单位)。
# 当然配合它的也有一个Grafana的配置

https://github.com/chenjiandongx/ginprom/blob/master/ginprom-service.json

# k8s的也有
https://github.com/chenjiandongx/ginprom/blob/master/ginprom-service-k8s.json

10:ginception

这个中间件能够将异常通过web帮我们展示出来

# 下载
go get -u github.com/kubastick/ginception
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/kubastick/ginception"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

    // 注册中间件
	r.Use(ginception.Middleware())
    
    // 手动触发一个报错
	r.GET("/", func(context *gin.Context) {
		panic("test panic")
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 此时其实我们直接访问路由触发报错就行了,要知道它的运行原理,我们就只需要知道中间件比正式的路由运行更靠前就行了,在运行路由前,已经运行了一个中间件了,所以这一点都奇怪,但是,我们通常不会将其注册到全局中间件,我们会把它绑定到一个指定的路由上,比如
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/kubastick/ginception"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 注册中间件
	r.GET("/", ginception.Middleware(), func(context *gin.Context) {
		panic("test panic")
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 这样,只有这一个路由报错才会触发中间件,当然了,有时我们全局报错也可能需要这个,这个由自己来决定了

11:gin-revision

# 用 Go (Golang) 编写的 Gin 框架的修订中间件,这个在Helm中应该大家都很熟悉

# 下载
go get -u github.com/appleboy/gin-revision-middleware
package main

import (
	revision "github.com/appleboy/gin-revision-middleware"
	"github.com/gin-gonic/gin"
	"log"
)

func main() {
	// 设置gin为发布模式
	gin.SetMode(gin.ReleaseMode)

	// 初始化gin
	r := gin.Default()

	// 使用REVISION中间件
	r.Use(revision.Middleware())

	// 注册中间件
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"revision": revision.Middleware(),
		})
	})

	// 启动gin
	err := r.Run(":80")
	if err != nil {
		log.Println(err)
	}
}
# 验证,我们在程序的同目录存放一个名为REVISION的文件,里面存放版本,然后我们启动并请求一下
PS D:\Codes\gin_middleware> http -f http://127.0.0.1
HTTP/1.1 200 OK
Content-Length: 26
Content-Type: application/json; charset=utf-8
Date: Sun, 13 Aug 2023 14:23:03 GMT
X-Revision: 1.0.0

{
    "message": "Hello World!"
}

# 它的主要源码如下
package revision

import (
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"log"
	"strings"
)

// GetRevision will get revision string from file.
func GetRevision(fileName string) (string, error) {
	// Revision file contents will be only loaded once per process
	data, err := ioutil.ReadFile(fileName)

	// If we cant read file, just skip to the next request handler
	// This is pretty much a NOOP middlware :)
	if err != nil {
		log.Printf("Unable to read config file '%s'", fileName)

		return "", err
	}

	// Clean up the value since it could contain line breaks
	return strings.TrimSpace(string(data)), err
}

// Middleware will auto set Revision on header.
func Middleware(args ...string) gin.HandlerFunc {
	fileName := "REVISION"

	if len(args) > 0 {
		fileName = args[0]
	}

	revision, err := GetRevision(fileName)

	if err != nil {
		return func(c *gin.Context) {
			c.Next()
		}
	}

	// Set out header value for each response
	return func(c *gin.Context) {
		c.Writer.Header().Set("X-Revision", revision)
		c.Next()
	}
}

总而言之,言而总之,这些中间件吧,版本都很低,大家可以根据自己的需求去仿写一下,希望对大家有所帮助!!!

posted @ 2023-08-14 19:33  Layzer  阅读(292)  评论(0编辑  收藏  举报