67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
package otel
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/propagation"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// Middleware 返回 Gin 中间件,用于自动创建 span
|
|
func Middleware(serviceName string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
// 从请求头提取 trace context
|
|
ctx := c.Request.Context()
|
|
propagator := propagation.NewCompositeTextMapPropagator(
|
|
propagation.TraceContext{},
|
|
propagation.Baggage{},
|
|
)
|
|
ctx = propagator.Extract(ctx, propagation.HeaderCarrier(c.Request.Header))
|
|
|
|
// 创建 span
|
|
spanName := c.Request.Method + " " + c.FullPath()
|
|
if c.FullPath() == "" {
|
|
spanName = c.Request.Method + " " + c.Request.URL.Path
|
|
}
|
|
|
|
ctx, span := Tracer().Start(ctx, spanName,
|
|
trace.WithSpanKind(trace.SpanKindServer),
|
|
trace.WithAttributes(
|
|
semconv.HTTPRequestMethodKey.String(c.Request.Method),
|
|
semconv.URLFull(c.Request.URL.String()),
|
|
semconv.HTTPRoute(c.FullPath()),
|
|
semconv.ServerAddress(c.Request.Host),
|
|
attribute.String("http.client_ip", c.ClientIP()),
|
|
),
|
|
)
|
|
defer span.End()
|
|
|
|
// 将新的 context 放入请求
|
|
c.Request = c.Request.WithContext(ctx)
|
|
|
|
// 记录开始时间
|
|
start := time.Now()
|
|
|
|
// 执行后续处理
|
|
c.Next()
|
|
|
|
// 记录响应信息
|
|
duration := time.Since(start)
|
|
statusCode := c.Writer.Status()
|
|
|
|
span.SetAttributes(
|
|
semconv.HTTPResponseStatusCode(statusCode),
|
|
attribute.Int64("http.response_size", int64(c.Writer.Size())),
|
|
attribute.Float64("http.duration_ms", float64(duration.Milliseconds())),
|
|
)
|
|
|
|
// 如果有错误,记录错误信息
|
|
if len(c.Errors) > 0 {
|
|
span.SetAttributes(attribute.String("error.message", c.Errors.String()))
|
|
}
|
|
}
|
|
}
|