diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index bde3723..c0497bf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,7 @@ --- name: Bug report about: Create a report to help us improve +labels: type:bug, status:pending, help wanted --- **Describe the bug** @@ -17,8 +18,8 @@ A clear and concise description of what you expected to happen. **Environment (please complete the following information):** -- OS: [e.g. mac, linux] -- OS version: [uname -a] +- Package version: +- Go version: **Additional context** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 422624f..bccac55 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,7 @@ --- name: Feature request about: Suggest an idea for this project +labels: type:feature, status:pending --- **Is your feature request related to a problem? Please describe.** diff --git a/Makefile b/Makefile index 6350c07..465197f 100644 --- a/Makefile +++ b/Makefile @@ -47,4 +47,4 @@ sync: @git stash && git pull --rebase && git stash pop || true .PHONY: upgrade -upgrade: sync update deps format test-with-coverage +upgrade: sync update deps refresh test-with-coverage diff --git a/README.md b/README.md index 7f18e64..4b43bbf 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Quality][icon_quality]][page_quality] [![Documentation][icon_docs]][page_docs] [![Coverage][icon_coverage]][page_coverage] +[![Awesome][icon_awesome]][page_awesome] ## 💡 Idea @@ -19,12 +20,11 @@ func Do(ctx context.Context) { } ``` -Full description of the idea is available -[here](https://www.notion.so/octolab/tracer-098c6f9fe97b41dcac4a30074463dc8f?r=0b753cbf767346f5a6fd51194829a2f3). +Full description of the idea is available [here][design]. ## 🏆 Motivation -In [Avito](https://tech.avito.ru), we use the [Jaeger](https://www.jaegertracing.io) - a distributed tracing platform. +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 @@ -37,6 +37,7 @@ For that reason, I wrote the simple solution to handle this specific case and fo ```go import ( "context" + "io" "net/http" "time" @@ -60,7 +61,11 @@ func Handle(rw http.ResponseWriter, req *http.Request) { ... call.Checkpoint("serialize") - data := FetchData(ctx, req.Body) + 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 { @@ -72,7 +77,7 @@ func Handle(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusOK) } -func FetchData(ctx context.Context, r io.Reader) Data { +func FetchData(ctx context.Context, r io.Reader) (Data, error) { defer tracer.Fetch(ctx).Start().Stop() // fetch a data into a struct @@ -88,7 +93,7 @@ func StoreIntoDatabase(ctx context.Context, data Data) error { Output: ``` -allocates at call stack: 1, detailed call stack: +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 @@ -100,28 +105,34 @@ allocates at call stack: 1, detailed call stack: 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 [dep][] or [go modules][gomod] to manage its version. +You can use [go modules](https://github.com/golang/go/wiki/Modules) or +[dep](https://golang.github.io/dep/) to manage its version. ```bash -$ dep ensure -add github.com/kamilsk/tracer - $ go get -u github.com/kamilsk/tracer + +$ dep ensure -add github.com/kamilsk/tracer ``` --- made with ❤️ for everyone -[icon_build]: https://travis-ci.org/kamilsk/tracer.svg?branch=master -[icon_coverage]: https://api.codeclimate.com/v1/badges/fb66449d1f5c64542377/test_coverage -[icon_docs]: https://godoc.org/github.com/kamilsk/tracer?status.svg -[icon_quality]: https://goreportcard.com/badge/github.com/kamilsk/tracer +[icon_awesome]: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg +[icon_build]: https://travis-ci.org/kamilsk/tracer.svg?branch=master +[icon_coverage]: https://api.codeclimate.com/v1/badges/fb66449d1f5c64542377/test_coverage +[icon_docs]: https://godoc.org/github.com/kamilsk/tracer?status.svg +[icon_quality]: https://goreportcard.com/badge/github.com/kamilsk/tracer + +[page_awesome]: https://github.com/avelino/awesome-go#performance +[page_build]: https://travis-ci.org/kamilsk/tracer +[page_coverage]: https://codeclimate.com/github/kamilsk/tracer/test_coverage +[page_docs]: https://godoc.org/github.com/kamilsk/tracer +[page_quality]: https://goreportcard.com/report/github.com/kamilsk/tracer -[page_build]: https://travis-ci.org/kamilsk/tracer -[page_coverage]: https://codeclimate.com/github/kamilsk/tracer/test_coverage -[page_docs]: https://godoc.org/github.com/kamilsk/tracer -[page_quality]: https://goreportcard.com/report/github.com/kamilsk/tracer +[design]: https://www.notion.so/octolab/tracer-098c6f9fe97b41dcac4a30074463dc8f?r=0b753cbf767346f5a6fd51194829a2f3 +[egg]: https://github.com/kamilsk/egg +[promo]: https://github.com/kamilsk/tracer -[dep]: https://golang.github.io/dep/ -[gomod]: https://github.com/golang/go/wiki/Modules -[promo]: https://github.com/kamilsk/tracer +[tmp.docs]: https://nicedoc.io/kamilsk/tracer?theme=dark +[tmp.history]: https://github.githistory.xyz/kamilsk/tracer/blob/master/README.md diff --git a/example_test.go b/example_test.go index 74db42e..d03463f 100644 --- a/example_test.go +++ b/example_test.go @@ -16,15 +16,15 @@ import ( "github.com/kamilsk/tracer" ) -type Message struct { - Title string `json:"title"` - Tagline string `json:"tagline"` +type Data struct { + Title string `json:"title"` + Subtitle string `json:"subtitle"` } func Example() { rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/message", - strings.NewReader(`{"title": "tracer", "tagline": "🧶 Simple, lightweight tracing mechanism."}`)) + strings.NewReader(`{"title": "tracer", "subtitle": "🧶 Simple, lightweight tracing mechanism."}`)) req.Header.Set("X-Request-Id", "ca7a87c4-58d0-4fdf-857c-ef49fc3bf271") handler := InjectTracer(FlushTracer(http.HandlerFunc(Handle))) @@ -32,7 +32,7 @@ func Example() { _, _ = io.Copy(os.Stdout, strings.NewReader(stabilize(rec.Body.String()))) // Output: - // allocates at call stack: 1, detailed call stack: + // allocates at call stack: 0, detailed call stack: // call Handle [ca7a87c4-58d0-4fdf-857c-ef49fc3bf271]: 12.345678ms, allocates: 2 // checkpoint [serialize]: 1.234567ms // checkpoint [store]: 1.234567ms @@ -40,17 +40,17 @@ func Example() { // call StoreIntoDatabase: 12.345678ms, allocates: 0 } -func InjectTracer(handler http.Handler) http.Handler { +func FlushTracer(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, 2))) handler.ServeHTTP(rw, req) + _, _ = rw.Write([]byte(tracer.Fetch(req.Context()).String())) }) } -func FlushTracer(handler http.Handler) http.Handler { +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) - _, _ = rw.Write([]byte(tracer.Fetch(req.Context()).String())) }) } @@ -81,16 +81,16 @@ func Handle(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusOK) } -func FetchData(ctx context.Context, r io.Reader) (Message, error) { +func FetchData(ctx context.Context, r io.Reader) (Data, error) { defer tracer.Fetch(ctx).Start().Stop() time.Sleep(time.Millisecond) - var data Message + var data Data err := json.NewDecoder(r).Decode(&data) return data, err } -func StoreIntoDatabase(ctx context.Context, data Message) error { +func StoreIntoDatabase(ctx context.Context, data Data) error { defer tracer.Fetch(ctx).Start().Stop() time.Sleep(10 * time.Millisecond)