beego服务未出现在skywalking ui是因默认不走标准http.servemux且不自动识别sw8头,导致http请求生成独立trace、拓扑图无实例;需在main()首行调用sw.init(),用sw.httpserverinterceptor包装handler,禁用autorender/recoverpanic,filter中避免提前读body,并在prepare()获取span、finishrouter()结束span。

Beego服务根本没出现在SkyWalking UI里
Beego默认不走标准net/http的http.ServeMux,也不会自动识别sw8上下文头,所以哪怕OAP连通、探针初始化成功,服务名也注册上去了,但所有HTTP请求都生成独立Trace,且Beego实例在拓扑图里压根不显示。
-
sw.Init()必须放在main()第一行,早于beego.Run()和任何go协程启动,否则探针未激活就进入监听状态,后续埋点全部失效 - 别用
beego.BeeApp.Handlers或beego.Router直接注册handler——要先用sw.HttpServerInterceptor包装原始handler函数 - Beego 2.x的
Controller方法内无法自动继承父Span,必须显式从context.Context中提取:用sw.ContinuedFromContext(r.Context())获取活跃span再操作 - 检查
req.Header.Get("sw8")是否非空;若为空,说明上游(比如网关)没透传头,或Beego中间件顺序错乱导致sw.HttpServerInterceptor没生效
HTTP链路在Beego里断成多个独立Span
Beego的Router和Filter机制绕过了标准http.Handler接口契约,sw.HttpServerInterceptor只包装了最外层Handler,但Beego内部会多次重写ResponseWriter、提前读取req.Body,导致span上下文丢失或重复创建。
- 在
main.go里不要直接http.Handle("/", ...),而是构造一个符合http.Handler接口的wrapper:
func main() {
sw.Init(&sw.Config{
ServiceName: "beego-order-service",
BackendAddress: "127.0.0.1:11800",
})
// 包装Beego默认Handler
wrapped := sw.HttpServerInterceptor(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
beego.BeeApp.Handlers.ServeHTTP(w, r)
}))
http.ListenAndServe(":8080", wrapped)
}
- 禁用Beego的
AutoRender和RecoverPanic过滤器——它们会提前消费req.Body,让sw.HttpServerInterceptor拿不到原始请求体,跳过上下文解析 - 若必须用Beego Filter,确保
sw.HttpServerInterceptor是第一个执行的Filter,且Filter内不调用r.ParseForm()或r.Body.Read()
自定义Tag写入后UI里查不到
Beego Controller里用ctx.Input.Ctx.Request.Context()拿到的context不是span绑定的context,直接传给sw.Tag会静默失败;更常见的是在FinishRouter之后才写Tag,此时span已End(),数据被丢弃。
- 所有
span.Tag()、span.Log()必须在span.End()前调用,且span必须来自sw.ContinuedFromContext()或sw.CreateEntrySpan() - 推荐在
Prepare()方法开头获取span,在FinishRouter()结尾调用span.End(),中间任意位置写Tag:
func (c *OrderController) Prepare() {
span, _ := sw.ContinuedFromContext(c.Ctx.Request.Context())
c.Data["span"] = span
}
func (c *OrderController) FinishRouter() {
if s, ok := c.Data["span"].(sw.Span); ok {
s.Tag("order_id", c.GetString("id"))
s.End() // 必须放最后
}
}
- 别在goroutine里操作span——Beego的异步逻辑(如
c.TplName渲染后回调)容易脱离原始context,跨协程必须用sw.WithContext()重新绑定
gRPC接口上报失败或报context deadline exceeded
Beego本身不原生支持gRPC,但很多项目会混用beego.Controller处理HTTP + grpc.Server暴露gRPC接口。这时若gRPC拦截器版本不匹配,会导致整个服务启动卡死或上报超时。
- 确认
google.golang.org/grpc和github.com/SkyAPM/go2sky版本兼容:用grpc-go v1.54.0配go2sky v0.8.0,或grpc-go v1.60.0+配go2sky v0.10.0+ - gRPC Server拦截器只能用
sw.GRPCServerInterceptor(),不能和HTTP拦截器混用;且必须在grpc.NewServer()时传入,不能事后server.RegisterService()再加 - 别在
grpc.NewServer()里加grpc.WithBlock()——OAP网络抖动时会阻塞服务启动;改用grpc.WithInsecure()+ 启动后手动调用sw.Reporter().HealthCheck() - 验证gRPC上报:用
grpcurl -plaintext localhost:9090 list确认服务可访问,再查OAP日志是否有"reporter: send segment to backend"
sw8头一旦在Filter或Prepare阶段被误读、重写或丢弃,整条链路就断了;而span生命周期又严格绑定End()调用时机,晚一毫秒写Tag就等于没写。











