Dead simple, lightweight tracing.
The tracer provides API to trace execution flow.
func Do(ctx context.Context) {
defer tracer.Fetch(ctx).Start().Stop()
// do some heavy job
}
A full description of the idea is available here.
At Avito, we use the Jaeger - a distributed tracing platform. It is handy in most cases, but at production, we also use sampling. So, what is a problem, you say?
I had 0.02% requests with a write: broken pipe
error and it was difficult to find the appropriate one in
the Sentry which also has trace related to it in the Jaeger.
For that reason, I wrote the simple solution to handle this specific case and found the bottleneck in our code quickly.
import (
"context"
"io"
"net/http"
"time"
"github.com/kamilsk/tracer"
)
func InjectTracer(handler http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
req = req.WithContext(tracer.Inject(req.Context(), make([]*tracer.Call, 0, 10)))
handler.ServeHTTP(rw, req)
})
}
func Handle(rw http.ResponseWriter, req *http.Request) {
ctx, cancel := context.WithTimeout(req.Context(), time.Second)
defer cancel()
call := tracer.Fetch(req.Context()).Start(req.Header.Get("X-Request-Id"))
defer call.Stop()
...
call.Checkpoint("serialize")
data, err := FetchData(ctx, req.Body)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
call.Checkpoint("store")
if err := StoreIntoDatabase(ctx, data); err != nil {
http.Error(rw,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
return
}
rw.WriteHeader(http.StatusOK)
}
func FetchData(ctx context.Context, r io.Reader) (Data, error) {
defer tracer.Fetch(ctx).Start().Stop()
// fetch a data into a struct
}
func StoreIntoDatabase(ctx context.Context, data Data) error {
defer tracer.Fetch(ctx).Start().Stop()
// store the data into a database
}
Output:
allocates at call stack: 0, detailed call stack:
call Handle [ca7a87c4-58d0-4fdf-857c-ef49fc3bf271]: 14.038083ms, allocates: 2
checkpoint [serialize]: 1.163587ms
checkpoint [store]: 2.436265ms
call FetchData: 1.192829ms, allocates: 0
call StoreIntoDatabase: 10.428663ms, allocates: 0
The library uses SemVer for versioning, and it is not BC-safe through major releases. You can use go modules to manage its version.
$ go get github.com/kamilsk/tracer@latest
made with ❤️ for everyone