Created
October 10, 2018 15:42
-
-
Save ufoot/adb6ca03281962db5fe0ab9eb10139f5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
// A program demoing sending of async traces in go, with Datadog tracer. | |
import ( | |
"context" | |
"math/rand" | |
"net/http" | |
"time" | |
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" | |
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | |
) | |
func asyncTask(ctx context.Context, resource string) { | |
// Now there we *could* technically have unrelated tasks which | |
// do not refer to the parent *if* the parent task is finished | |
// *before* this child task is started. To avoid this, either | |
// create the span in the caller, synchronously, but finish it | |
// here, or use some synchronisation mechanism ensuring the | |
// span is created before caller returns. This is because the | |
// tracer has no way to know wether the parent has some spans | |
// until one explicit starts one. And so it might flush it | |
// before and apply different sampling decisions on different | |
// parts of the trace. It's an edge case. | |
c, _ := tracer.StartSpanFromContext( | |
ctx, // use ctx to relate this child span to parent | |
"task", | |
tracer.SpanType("custom"), | |
tracer.ResourceName(resource), | |
) | |
defer c.Finish() | |
// bonus: report as a different service to get breakdown stats | |
c.SetTag(ext.ServiceName, "async.worker") | |
// do something interesting here | |
d := 50 + rand.Int31n(50)*rand.Int31n(50)*rand.Int31n(50) | |
time.Sleep(time.Duration(d) * time.Millisecond) | |
} | |
type httpHandler struct{} | |
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
p, ctx := tracer.StartSpanFromContext( | |
context.Background(), | |
"web.handler", | |
tracer.SpanType("web"), | |
tracer.ResourceName(r.Method), | |
) | |
defer p.Finish() | |
// Delegate real jobs to other goroutines. | |
// Note the ContextWithSpan to explicitly pass the right span as a parent. | |
// When using asynchronous call this is *always* mandatory because | |
// there is no way to figure out "what is the current span" as this | |
// totally depends on which goroutine you are one. This `WithSpan` | |
// lets you control what the parent should be. | |
go asyncTask(tracer.ContextWithSpan(ctx, p), "blue") | |
go asyncTask(tracer.ContextWithSpan(ctx, p), "red") | |
// pretend there are still pending synchronous tasks | |
d := 10 + rand.Int31n(10)*rand.Int31n(10) | |
time.Sleep(time.Duration(d) * time.Millisecond) | |
} | |
func main() { | |
tracer.Start(tracer.WithDebugMode(true), tracer.WithServiceName("demo-async")) | |
defer tracer.Stop() | |
s := &http.Server{ | |
Addr: ":8080", | |
Handler: &httpHandler{}, | |
} | |
s.ListenAndServe() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment