README.md
> # 🧶 tracer
>
> Dead simple, lightweight tracing.
[![Build][build.icon]][build.page]
[![Documentation][docs.icon]][docs.page]
[![Quality][quality.icon]][quality.page]
[![Template][template.icon]][template.page]
[![Coverage][coverage.icon]][coverage.page]
[![Awesome][awesome.icon]][awesome.page]
## 💡 Idea
The tracer provides API to trace execution flow.
```go
func Do(ctx context.Context) {
defer tracer.Fetch(ctx).Start().Stop()
// do some heavy job
}
```
A full description of the idea is available [here][design.page].
## 🏆 Motivation
At [Avito](https://tech.avito.ru), we use the [Jaeger](https://www.jaegertracing.io) - 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](https://sentry.io) which also has trace related to it in the [Jaeger](https://www.jaegertracing.io).
For that reason, I wrote the simple solution to handle this specific case and found the bottleneck in our code quickly.
## 🤼♂️ How to
```go
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
```
## 🧩 Integration
The library uses [SemVer](https://semver.org) for versioning, and it is not
[BC](https://en.wikipedia.org/wiki/Backward_compatibility)-safe through major releases.
You can use [go modules](https://github.com/golang/go/wiki/Modules) to manage its version.
```bash
$ go get github.com/kamilsk/tracer@latest
```
---
made with ❤️ for everyone
[awesome.page]: https://github.com/avelino/awesome-go#performance
[awesome.icon]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg
[build.page]: https://travis-ci.com/kamilsk/tracer
[build.icon]: https://travis-ci.com/kamilsk/tracer.svg?branch=master
[coverage.page]: https://codeclimate.com/github/kamilsk/tracer/test_coverage
[coverage.icon]: https://api.codeclimate.com/v1/badges/fb66449d1f5c64542377/test_coverage
[design.page]: https://www.notion.so/octolab/tracer-098c6f9fe97b41dcac4a30074463dc8f?r=0b753cbf767346f5a6fd51194829a2f3
[docs.page]: https://pkg.go.dev/github.com/kamilsk/tracer
[docs.icon]: https://img.shields.io/badge/docs-pkg.go.dev-blue
[promo.page]: https://github.com/kamilsk/tracer
[quality.page]: https://goreportcard.com/report/github.com/kamilsk/tracer
[quality.icon]: https://goreportcard.com/badge/github.com/kamilsk/tracer
[template.page]: https://github.com/octomation/go-module
[template.icon]: https://img.shields.io/badge/template-go--module-blue