Go语言jaeger和opentracing

OpenTracing开放式分布式追踪规范,常见实现:jaeger和zipkin

docker启动一个实例:

docker run  -p 5775:5775/udp    -p 16686:16686    -p 6831:6831/udp   -p 6832:6832/udp   -p 5778:5778   -p 14268:14268    jaegertracing/all-in-one:latest

go 

来一个普通的go程序

package main
 
import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
 
    "github.com/uber/jaeger-client-go"
    "github.com/uber/jaeger-lib/metrics"
 
    "github.com/opentracing/opentracing-go"
    "github.com/opentracing/opentracing-go/ext"
    "github.com/uber/jaeger-client-go/config"
)
 
var (
    tracerServer opentracing.Tracer
)
 
func TraceInit(serviceName string, samplerType string, samplerParam float64) (opentracing.Tracer, io.Closer) {
    cfg := &config.Configuration{
        ServiceName: serviceName,
        Sampler: &config.SamplerConfig{
            Type:  samplerType,
            Param: samplerParam,
        },
        Reporter: &config.ReporterConfig{
            LocalAgentHostPort: "192.168.100.21:6831",
            LogSpans:           true,
        },
    }
 
    tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger), config.Metrics(metrics.NullFactory))
    if err != nil {
        panic(fmt.Sprintf("Init failed: %v
", err))
    }
 
    return tracer, closer
}
 
func GetListProc(w http.ResponseWriter, req *http.Request) {
    spanCtx, _ := tracerServer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
    span := tracerServer.StartSpan("GetListProc", ext.RPCServerOption(spanCtx))
    defer span.Finish()
 
    fmt.Println("Get request getList")
    respList := []string{"l1", "l2", "l3", "l4", "l5"}
    respString := ""
 
    for _, v := range respList {
        respString += v + ","
    }
 
    fmt.Println(respString)
    io.WriteString(w, respString)
}
 
func sendRequest(req *http.Request) {
    resp, err := http.DefaultClient.Do(req)
 
    if err != nil {
        fmt.Printf("Do send requst failed(%s)
", err)
        return
    }
 
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("ReadAll error(%s)
", err)
        return
    }
 
    if resp.StatusCode != 200 {
        return
    }
    fmt.Printf("Response:%s
", string(body))
 
}
 
func main() {
    // server
    var closerServer io.Closer
    tracerServer, closerServer = TraceInit("Trace-Server", "const", 1)
    defer closerServer.Close()
 
    http.HandleFunc("/getList", GetListProc)
 
    go http.ListenAndServe(":8080", nil)
 
    //client
    tracerClient, closerClient := TraceInit("CS-tracing", "const", 1)
    defer closerClient.Close()
 
    opentracing.SetGlobalTracer(tracerClient)
    span := tracerClient.StartSpan("getlist trace")
    span.SetTag("trace to", "getlist")
    defer span.Finish()
 
    reqURL := "http://localhost:8080/getList"
    req, err := http.NewRequest("GET", reqURL, nil)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
 
    span.Tracer().Inject(
        span.Context(),
        opentracing.HTTPHeaders,
        opentracing.HTTPHeadersCarrier(req.Header),
    )
 
    sendRequest(req)
}

运行效果:

访问http://192.168.100.21:16686/ 如下:

GRPC

我这里用以前的项目 https://github.com/dz45693/gogrpcjwt.git, 大家可以参考grpc 拦截器【 go 和 asp.net core的实现】 这里我引用了github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc 这个包

服务端代码修改如下:

 

客户端:

普通程序日志:

有些时候 我们的方法会有很多调用和日志, 我希望把这一次api请求的日志归纳在一起【elk可以通过某个字段过滤】, 这里我们可以在api 入口创建一个apn 绑定到context, 然后每个方法都传这个context,日志读取context的traceid

package main
 
import (
    "context"
    "encoding/json"
    "fmt"
    "io"
    "runtime"
    "strings"
    "time"
 
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    "github.com/uber/jaeger-client-go/config"
    "github.com/uber/jaeger-lib/metrics"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)
 
func init() {
    tracerClient, closerClient := TraceInit("CS-tracing", "const", 1)
    defer closerClient.Close()
 
    opentracing.SetGlobalTracer(tracerClient)
}
 
func main() {
    span := opentracing.GlobalTracer().StartSpan("gavintest")
    ctx := opentracing.ContextWithSpan(context.Background(), span)
    log(ctx, "gavin test")
}
 
func log(ctx context.Context, format string, args ...interface{}) {
    traceId, spanId := GetTraceId(ctx)
 
    logerData := JsonLogger{
        TraceId:  traceId,
        SpanId:   spanId,
        Content:  fmt.Sprintf(format, args...),
        CallPath: GetCallPath(),
        Level:    zap.InfoLevel,
        LogTime:  time.Now().Format("2006-01-02T15:04:05.000+08:00"),
    }
 
    jsonData, _ := json.Marshal(logerData)
 
    fmt.Println("---------------------")
    fmt.Println(string(jsonData))
}
 
func TraceInit(serviceName string, samplerType string, samplerParam float64) (opentracing.Tracer, io.Closer) {
    cfg := &config.Configuration{
        ServiceName: serviceName,
        Sampler: &config.SamplerConfig{
            Type:  samplerType,
            Param: samplerParam,
        },
        Reporter: &config.ReporterConfig{
            LocalAgentHostPort: "192.168.100.30:6831",
            LogSpans:           true,
        },
    }
 
    tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger), config.Metrics(metrics.NullFactory))
    if err != nil {
        panic(fmt.Sprintf("Init failed: %v
", err))
    }
 
    return tracer, closer
}
 
func GetTraceId(ctx context.Context) (string, uint64) {
    span := opentracing.SpanFromContext(ctx)
    if span == nil {
        return "", 0
    }
 
    if sc, ok := span.Context().(jaeger.SpanContext); ok {
 
        return fmt.Sprintf("%v", sc.TraceID()), uint64(sc.SpanID())
    }
    return "", 0
}
 
func GetCallPath() string {
    _, file, lineno, ok := runtime.Caller(2)
    if ok {
        return strings.Replace(fmt.Sprintf("%s:%d", stringTrim(file, ""), lineno), "%2e", ".", -1)
    }
    return ""
}
 
func stringTrim(s, cut string) string {
    ss := strings.SplitN(s, cut, 2)
    if len(ss) == 1 {
        return ss[0]
    }
    return ss[1]
}
 
type JsonLogger struct {
    TraceId  string        `json:"traceId"`
    SpanId   uint64        `json:"spanId"`
    Content  interface{}   `json:"content"`
    CallPath interface{}   `json:"callPath"`
    LogTime  string        `json:"logdate"`
    Level    zapcore.Level `json:"level"`
}

运行效果:

windows技术爱好者
原文地址:https://www.cnblogs.com/majiang/p/14417352.html