1、[Jaeger]是Uber开发的一套分布式追踪系统,已在Uber大规模使用。

官网地址:https://www.jaegertracing.io/

2、docker安装
all-in-one 是Uber官方打包好的镜像,可以直接部署使用,但是只能用于测试环境,不能用于线上,因为它把数据放入了内存

docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one

运行成功后,访问:http://192.168.1.178:16686/

4、micro服务端和客户端安装如下第三方库

go get -u github.com/opentracing/opentracing-go
go get -u github.com/uber/jaeger-client-go

5、服务端代码

package main

import (
    "github.com/micro/go-micro"
    "github.com/micro/go-micro/registry"
    "github.com/micro/go-micro/registry/etcd"
    "github.com/micro/go-plugins/wrapper/trace/opentracing"
    goTracing "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    "github.com/uber/jaeger-client-go/config"
    "io"
    "log"
    "micro-api/service/controller"
    services "micro-api/service/model"
    "time"
)

//新增
func newTracer(service string) (goTracing.Tracer, io.Closer, error) {
    cfg := &config.Configuration{
        ServiceName: service,
        Sampler: &config.SamplerConfig{
            Type:  jaeger.SamplerTypeConst,
            Param: 1,
        },
        Reporter: &config.ReporterConfig{
            LogSpans:            true,
            BufferFlushInterval: 1 * time.Second,
            LocalAgentHostPort:  "192.168.1.178:6831",
        },
    }

    tracer, closer, err := cfg.NewTracer()

    return tracer, closer, err
}

func main() {

    //新增
    tracer, closer, err := newTracer("jaeger-server")
    if err != nil {
        log.Fatal(err)
    }

    defer closer.Close()
    goTracing.SetGlobalTracer(tracer)

    registerEtcd := etcd.NewRegistry(func(options *registry.Options) {
        options.Addrs = []string{
            "192.168.1.171:2379",
        }
    })

    service := micro.NewService(
        micro.Name("service.student"),
        micro.Registry(registerEtcd),
        micro.WrapHandler(opentracing.NewHandlerWrapper(goTracing.GlobalTracer())),//这里是服务端,所以这里必须是WrapHandler,opentracing.NewHandlerWrapper
    )
    if err := services.RegisterStudentListServiceHandler(service.Server(), new(controller.StudentService)); err != nil {

    }
    service.Init()

    service.Run()
}

6、客户端

package main



import (

    "context"

    "github.com/afex/hystrix-go/hystrix"

    "github.com/gin-gonic/gin"

    "github.com/micro/go-micro"

    "github.com/micro/go-micro/client"

    "github.com/micro/go-micro/registry"

    "github.com/micro/go-micro/registry/etcd"

    "github.com/micro/go-micro/web"

    "github.com/micro/go-plugins/wrapper/trace/opentracing"

    goTracing "github.com/opentracing/opentracing-go"

    "github.com/uber/jaeger-client-go"

    "github.com/uber/jaeger-client-go/config"

    "io"

    "log"

    services "micro-home/service/model"

    "strconv"

    "time"

)



//新增

func newTracer(service string) (goTracing.Tracer, io.Closer, error) {

    cfg := &config.Configuration{

        ServiceName: service,

        Sampler: &config.SamplerConfig{

            Type:  jaeger.SamplerTypeConst,

            Param: 1,

        },

        Reporter: &config.ReporterConfig{

            LogSpans:            true,

            BufferFlushInterval: 1 * time.Second,

            LocalAgentHostPort:  "192.168.1.178:6831",

        },

    }



    tracer, closer, err := cfg.NewTracer()



    return tracer, closer, err

}



func InitMiddleware(service services.StudentListService) gin.HandlerFunc {

    return func(context *gin.Context) {

        context.Keys = make(map[string]interface{})

        context.Keys["student_service"] = service

        context.Next()

    }

}



type logWrapper struct {

    client.Client

}





func (c *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {

    log.Print("请求")

    return c.Client.Call(ctx, req, rsp)

}

func NewLogWrapper(c client.Client) client.Client {

    return &logWrapper{c}

}



func main() {

    //新增

    tracer, closer, err := newTracer("jaeger-client")

    if err != nil {

        log.Fatal(err)

    }



    defer closer.Close()

    goTracing.SetGlobalTracer(tracer)



    register := etcd.NewRegistry(func(options *registry.Options) {

        options.Addrs = []string{

            "192.168.1.171:2379",

        }

    })

    homeService := micro.NewService(

        micro.Name("micro-home-client"),

        micro.Registry(register),

        micro.WrapClient(NewLogWrapper),

        micro.WrapClient(opentracing.NewClientWrapper(goTracing.GlobalTracer())),//这里是客户端,所以这里需要使用WrapClient,opentracing.NewClientWrapper

    )

    studentListService := services.NewStudentListService("service.student", homeService.Client())



    routers := gin.Default()



    routers.Use(InitMiddleware(studentListService)) //使用中间件,将服务传递到context中



    routers.GET("/", func(context *gin.Context) {

        service := context.Keys["student_service"].(services.StudentListService)

        number := context.DefaultQuery("number", "0")

        num, err := strconv.Atoi(number)

        if err != nil {

            num = 1

        }

        if num <= 0 {

            num = 1

        }

        hystrix.ConfigureCommand("student-service", hystrix.CommandConfig{

            Timeout: 1000,

        })

        var studentListResponse *services.StudentListResponse

        err = hystrix.Do("student-service", func() error {

            studentListResponse, err = service.GetStudentListService(context, &services.StudentListRequest{

                Num: int32(num),

            })

            return err

        }, func(e error) error {

            var studentModel []*services.StudentModel

            studentModel = append(studentModel, &services.StudentModel{

                Id:   0,

                Name: "熔断返回" + err.Error(),

                Sex:  "女",

            })

            studentListResponse = &services.StudentListResponse{

                Status: 200,

                Data:   studentModel,

            }

            return nil

        })

        if err != nil {

            context.JSON(400, gin.H{

                "status": "",

                "data":   err.Error(),

            })

        } else {

            context.JSON(200, gin.H{

                "status": studentListResponse.Status,

                "data":   studentListResponse.Data,

            })

        }

    })



    service := web.NewService(

        web.Name("home-service-api"),

        web.Address(":8081"),

        web.Handler(routers),

        web.Registry(register),

    )



    service.Run()

}