Gin 接入 OpenTelemetry 和 Prometheus
# Gin 接入 OpenTelemetry 和 Prometheus
项目地址:https://github.com/xuqil/observability/tree/main/trace/gin/middleware
# 接入 OpenTelemetry
package opentelemetry
import (
"github.com/gin-gonic/gin"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)
const instrumentationName = "github.com/xuqil/observability/trace/gin/middlewares/opentelemetry"
type MiddlewareBuilder struct {
Tracer trace.Tracer
}
func (m MiddlewareBuilder) Build() gin.HandlerFunc {
if m.Tracer == nil {
m.Tracer = otel.GetTracerProvider().Tracer(instrumentationName)
}
return func(ctx *gin.Context) {
reqCtx := ctx.Request.Context()
// 尝试和客户端的 trace 结合在一起
reqCtx = otel.GetTextMapPropagator().Extract(reqCtx, propagation.HeaderCarrier(ctx.Request.Header))
reqCtx, span := m.Tracer.Start(reqCtx, "unknown")
defer span.End()
span.SetAttributes(attribute.String("http.method", ctx.Request.Method))
span.SetAttributes(attribute.String("http.url", ctx.Request.URL.String()))
span.SetAttributes(attribute.String("http.scheme", ctx.Request.URL.Scheme))
span.SetAttributes(attribute.String("http.host", ctx.Request.Host))
ctx.Request = ctx.Request.WithContext(reqCtx)
ctx.Next()
span.SetName(ctx.FullPath())
span.SetAttributes(attribute.Int("http.status", ctx.Writer.Status()))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 接入 Prometheus
package prometheus
import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"strconv"
"time"
)
type MiddlewareBuilder struct {
Namespace string
Subsystem string
Name string
Help string
}
func (m MiddlewareBuilder) Build() gin.HandlerFunc {
vector := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: m.Name,
Subsystem: m.Subsystem,
Namespace: m.Namespace,
Help: m.Help,
Objectives: map[float64]float64{
0.5: 0.01,
0.75: 0.01,
0.90: 0.01,
0.99: 0.001,
0.999: 0.0001,
},
}, []string{"pattern", "method", "status"})
prometheus.MustRegister(vector)
return func(ctx *gin.Context) {
startTime := time.Now()
defer func() {
duration := time.Now().Sub(startTime).Milliseconds()
pattern := ctx.FullPath()
if pattern == "" {
pattern = "unknown"
}
vector.WithLabelValues(pattern, ctx.Request.Method,
strconv.Itoa(ctx.Writer.Status())).Observe(float64(duration))
}()
ctx.Next()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
评论
上次更新: 2024/05/29, 14:25:22