Skip to content

Instantly share code, notes, and snippets.

@ufoot
Created October 10, 2018 15:42
Show Gist options
  • Save ufoot/adb6ca03281962db5fe0ab9eb10139f5 to your computer and use it in GitHub Desktop.
Save ufoot/adb6ca03281962db5fe0ab9eb10139f5 to your computer and use it in GitHub Desktop.
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