繁体   English   中英

为什么我的 opentelemetry 事件在跨通道时打印,而不是来自主 goroutine 的事件

[英]Why are my opentelemetry events printing when ranging over a channel, but not events from the main goroutine

我很困惑为什么我的事件只在一个通道内的循环内打印,而不是来自主 goroutine 的那些。 看来我只能做

我有一种感觉我错误地使用了上下文

希望我能够做到:

  • 从主 goroutine 中创建的跨度打印到标准输出
  • 从称为请求的通道中创建的跨度打印到标准输出,每个请求一个

最终:

  • 从我从每个入站请求中获得的 traceid 创建一个跨度,因此与 main 中初始化的跟踪分开; 并有一个持久的主要跟踪。 允许从主跟踪中确定正常运行时间,然后为入站请求创建的跨度请求生命周期

这是我的完整代码:


import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "math/rand"
    "os"
    "path/filepath"
    "runtime"
    "sync"
    "time"

    "github.com/nats-io/nats.go"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/codes"
    stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
    "go.opentelemetry.io/otel/propagation"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
    "go.opentelemetry.io/otel/trace"
)

var (
    natsURL = "localhost:4222"
    subject = "listen.to.refresher"
    sub     *nats.Subscription
)

type NewRequest struct {
    Requestid    string `json: "requestid"`
}

func main() {

    ctx := context.Background()
    execName, _ := os.Executable()
    stdoutExporter, err := stdout.New(stdout.WithPrettyPrint())
    if err != nil {
        log.Fatal(err)
    }

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(stdoutExporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String(filepath.Base(execName)),
            semconv.ServiceVersionKey.String("v1.0.0"),
            attribute.String("environment", "dev"),
        )),
    )

    defer func() { _ = tp.Shutdown(ctx) }()

    otel.SetTracerProvider(tp) // sets globally. I believe this is correct
    otel.SetTextMapPropagator(
        propagation.NewCompositeTextMapPropagator(
            propagation.TraceContext{},
            propagation.Baggage{},
        ),
    )

    var mainSpan trace.Span
    ctx, mainSpan = otel.Tracer("main").Start(ctx, "mainSpan") // should I initialise the tracer with no name?
    defer mainSpan.End()

    mainSpan.AddEvent("WHY DOESN'T THIS PRINT?") //HERE!!!!!!

    nc, err := nats.Connect(natsURL)
    if err != nil {
        log.Fatal(err)
    }

    requests := make(chan NewRequest)
    var wg sync.WaitGroup
    _, err = nc.QueueSubscribe(subject, subject, func(msg *nats.Msg) { // here is where requests come in. This is a go routine waiting on inbound nats messages to come in, before adding them to a channel
        wg.Add(1)
        nr := new(NewRequest)
        err := json.Unmarshal(msg.Data, &nr)
        if err != nil {
            mainSpan.RecordError(err)
            mainSpan.SetStatus(codes.Error, err.Error())
            log.Fatal(err)
        }
        response := fmt.Sprintf("response from the subscriber! requestid: %s", nr.Requestid)
        msg.Respond([]byte(response))
        requests <- *nr
    })
    if err != nil {
        mainSpan.RecordError(err)
        mainSpan.SetStatus(codes.Error, err.Error())
    }

    for request := range requests { // processing each request in the channel
        tracer := otel.GetTracerProvider().Tracer("requests")
        requesterSpan := trace.SpanFromContext(ctx)
        requestCtx := trace.ContextWithSpan(ctx, requesterSpan)
        var requestInLoopSpan trace.Span
        requestCtxChild, requestInLoopSpan := tracer.Start(requestCtx, "requestInLoopSpan")
        requestInLoopSpan.AddEvent("processing....") // THIS PRINTS TO STDOUT

        go func(requestCtxChild context.Context, request NewRequest) {
            mainCtx2, _ = callDatabase2(requestCtxChild, request)
            defer requestInLoopSpan.End()
            defer wg.Done()
        }(requestCtxChild, request)
        requestCtxChild.Done()
    }

    wg.Wait()
    runtime.Goexit()
}

func callDatabase2(ctx context.Context, request NewRequest) (context.Context, string) {
    minTime := 1.0
    maxTime := 2.0

    var callDatabase2Span trace.Span
    ctx, callDatabase2Span = otel.Tracer("").Start(ctx, "callDatabase2")
    defer callDatabase2Span.End()

    time.Sleep(time.Second * (time.Duration(minTime + rand.Float64()*(maxTime-minTime)))) // simulate db doing something
    callDatabase2Span.AddEvent("finished!") // THIS DOES PRINT TO STDOUT

    return ctx, request.Requestid
}`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM