foreword
Link tracking is a must-have tool for every microservice architecture. Of course, go-zero has already been considered for us, and it can be used only by adding configuration in the configuration.
About the principle of how go-zero is tracked, some students have shared it before, so I won’t say more here. If you want to know more about it, go to https://mp.weixin.qq.com/s/hJEWcWc3PnGfWfbPCHfM9g All right. By default, tracking will be added to the middleware of the api and the interceptor of the rpc. If you don’t know how go-zero uses the default link tracking by default, please move to my open source project go-zero-looklook document https://github. com/Mikaelemmmm/go-zero-looklook/blob/main/doc/chinese/12-%E9%93%BE%E8%B7%AF%E8%BF%BD%E8%B8%AA.md.
What I want to talk about today is that, in addition to the link tracking that go-zero has integrated for us by default in the middleware of the api and the interceptor of the rpc, we want to add the link tracking code in some local methods or we want to send a When the message is sent to mq service, I want to connect the whole link including mq’s producer and consumer. How to do it in go-zero.
Scenes
Let’s briefly talk about the scene of our small demo, a request comes in to call the api Login
method, first call the rpc in the Login method GetUserByMobile
method, and then call the api local local
method, followed by calling rabbitmq
Pass message to mq service.
go-zero integrates jaeger and zinpink by default, here we take jaeger as an example
The link we want to see is
type LoginLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic { return &LoginLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } type MsgBody struct { Carrier *propagation.HeaderCarrier Msg string } func (l *LoginLogic) Login(req *types.RegisterReq) (*types.AccessTokenResp, error) { resp, err := l.svcCtx.UserRpc.GetUserByMobile(l.ctx, &usercenter.GetUserByMobileReq{ Mobile: req.Mobile, }) if err != nil { return &types.AccessTokenResp{}, nil } l.local() tracer := otel.GetTracerProvider().Tracer(trace.TraceName) spanCtx, span := tracer.Start(l.ctx, "send_msg_mq", oteltrace.WithSpanKind(oteltrace.SpanKindProducer)) carrier := &propagation.HeaderCarrier{} otel.GetTextMapPropagator().Inject(spanCtx, carrier) producer := rabbit.NewRabbitmqPublisher(RabbitmqDNS) msg := &MsgBody{ Carrier: carrier, Msg: req.Mobile, } b, err := json.Marshal(msg) if err != nil{ panic(err) } if err := producer.Publish(spanCtx, ExchangeName, RoutineKeys, b); err != nil { logx.Errorf("Publish Fail , msg :%s , err:%v", msg, err) } span.End() return &types.AccessTokenResp{ AccessExpire: resp.User.Id, }, err } func (l *LoginLogic) local() { tracer := otel.GetTracerProvider().Tracer(trace.TraceName) _ , span := tracer.Start(l.ctx, "local", oteltrace.WithSpanKind(oteltrace.SpanKindInternal)) defer span.End() // 执行你的代码 ..... }
2. In rpc GetUserByMobile
the code
func (s *Logic) GetUserByMobile(context.Context, *usercenterPb.GetUserByMobileReq) (*usercenterPb.GetUserByMobileResp, error) {
vo := &usercenterPb.UserVo{
Id: 1,
}
return &usercenterPb.GetUserByMobileResp{
User: vo,
}, nil
}
3. In mq Consumer
the code
type MsgBody struct {
Carrier *propagation.HeaderCarrier
Msg string
}
func (c *consumer) Consumer(ctx context.Context, data []byte) error {
var msg MsgBody
if err := json.Unmarshal(data, &msg); err != nil {
logx.Errorf(" consumer err : %v", err)
} else {
logx.Infof("consumerOne Consumer , msg:%+v", msg)
wireContext := otel.GetTextMapPropagator().Extract(ctx, msg.Carrier)
tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
_, span := tracer.Start(wireContext, "mq_consumer_msg", oteltrace.WithSpanKind(oteltrace.SpanKindConsumer))
defer span.End()
}
return nil
}
Detailed code
1. go-zero default integration
When a request enters the api, we can see https://github.com/zeromicro/go-zero/blob/master/rest/engine.go#L92 in the go-zero source code. go-zero has helped us add the first layer of trace in the middleware of the api. When entering the Login method, we call the rpc GetUserByMobile
Method, through the source code of go-zero https://github.com/zeromicro/go-zero/blob/master/zrpc/internal/rpcserver.go#L55, you can see that the interceptor in rpc is also added by default for us. These two layers are done by go-zero for us by default.
2. Local methods
When the rpc is called GetUserByMobile
After that, the api calls the local local
if we want to reflect it on the entire link and call the local local
method, the default go-zero does not help us, we need to add it manually.
tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
_ , span := tracer.Start(l.ctx, "local", oteltrace.WithSpanKind(oteltrace.SpanKindInternal))
defer span.End()
// 执行你的代码 .....
We get the tracer through the above code, open a local span after ctx, because the parent span will be obtained from ctx at the time of start, so the parent-child call relationship will be connected in series between the local method and Login, so this operation will be added to this link
3. Mq producer to mq consumer
How do we connect this link in series in mq delivery?that is to form api.Login->api.producer->mq.Consumer
.
Think about the principle, although across the network, api can pass header
pass, rpc can pass metadata
pass, then mq can also pass header
,body
Just pass it on. Let’s take a look at my code according to this idea.
tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
spanCtx , span := tracer.Start(l.ctx, "send_msg_mq", oteltrace.WithSpanKind(oteltrace.SpanKindProducer))
carrier := &propagation.HeaderCarrier{}
otel.GetTextMapPropagator().Inject(spanCtx,carrier)
producer := rabbit.NewRabbitmqPublisher(RabbitmqDNS)
msg := &MsgBody{
Carrier: carrier,
Msg: req.Mobile,
}
b , err := json.Marshal(msg)
if err != nil{
panic(err)
}
if err := producer.Publish(spanCtx, ExchangeName, RoutineKeys, b); err != nil {
logx.Errorf("Publish Fail, msg :%s, err:%v", msg, err)
}
span.End()
First get the global tracer
then turn on a producer
of span
,and local
In the same way, we turn on producer
of span
time also passes ctx
Get to the parent of the previous level span
so that the producer
of span
and Login
form father and son span
call relation, then we want to producer
of span
with mq consumer
middle span
How to form call parent-child relationship?We will api.producer
of spanCtx
injected into carrier
In, here we pass mq’s body
Will carrier
send to consumer
sending complete our stop
our producer
,So producer
This link is complete.
then we’ll see mq-consumer
received body
What to do after the news.
type MsgBody struct {
Carrier *propagation.HeaderCarrier
Msg string
}
func (c *consumer) Consumer(ctx context.Context, data []byte) error {
var msg MsgBody
if err := json.Unmarshal(data, &msg); err != nil {
logx.Errorf(" consumer err : %v", err)
} else {
logx.Infof("consumerOne Consumer , msg:%+v", msg)
wireContext := otel.GetTextMapPropagator().Extract(ctx, msg.Carrier)
tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
_, span := tracer.Start(wireContext, "mq_consumer_msg", oteltrace.WithSpanKind(oteltrace.SpanKindConsumer))
defer span.End()
}
return nil
}
consumer
After receiving the message, deserialize it out Carrier *propagation.HeaderCarrier
then pass otel.GetTextMapPropagator().Extract
take out api.producer
injected wireContext
after passing tracer.Start
,wireContext
create consumer
of span
,so consumer
that is api.producer
son span
the call link relationship is formed, and finally the relationship we get is
project address
go-zero microservice framework: https://github.com/zeromicro/go-zero
https://gitee.com/kevwan/go-zero
go-zero microservice best practice project: https://github.com/Mikaelemmmm/go-zero-looklook
welcome go-zero
and star Support us!
WeChat exchange group
focus on”Microservice Practice』Official account and click Exchange group Obtain the QR code of the community group.
#Fun #link #tracking #kevwans #personal #space #News Fast Delivery