๐Ÿ“ฆ go-chi / traceid

๐Ÿ“„ README.md ยท 100 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100# TraceId

Go pkg to propagate `TraceId` header across multiple services.

- Enables simple tracing capabilities and log grouping.
- The value can be exposed to end-users in case of an error.
- The value is [UUIDv7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7), which lets you [infer the timestamp](https://github.com/go-chi/traceid?tab=readme-ov-file#get-time-from-uuidv7-value).
- Unlike [OTEL](https://pkg.go.dev/go.opentelemetry.io/otel), this package doesn't trace spans or metrics, doesn't require any backend and doesn't have large dependencies (GRPC).

## Example - HTTP middleware

```go
package main

import (
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/httplog/v2"
	"github.com/go-chi/traceid"
)

func main() {
	r := chi.NewRouter()

	r.Use(traceid.Middleware)
	r.Use(httplog.RequestLogger(logger()))
	r.Use(middleware.Recoverer)

	r.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx := r.Context()

			// Log traceId to request logger.
			traceID := traceid.FromContext(r.Context())
			httplog.LogEntrySetField(ctx, "traceId", slog.StringValue(traceID))

			next.ServeHTTP(w, r.WithContext(ctx))
		})
	})
```

See [example/main.go](./example/main.go)

## Example: Send HTTP request with TraceId header

```go
import (
	"github.com/go-chi/traceid"
)

func main() {
	// Set TraceId in context, if not set from parent ctx yet.
	ctx := traceid.NewContext(context.Background())

	// Make a request with TraceId header.
	req, _ := http.NewRequestWithContext(ctx, "GET", "http://localhost:3333/proxy", nil)
	traceid.SetHeader(ctx, req)

	resp, err := http.DefaultClient.Do(req)
	//...
}
```

## Example: Set TraceId header in all outgoing HTTP requests globally

```go
import (
	"github.com/go-chi/traceid"
	"github.com/go-chi/transport"
)

func main() {
	// Send TraceId in all outgoing HTTP requests.
	http.DefaultTransport = transport.Chain(
		http.DefaultTransport,
		transport.SetHeader("User-Agent", "my-app/v1.0.0"),
		traceid.Transport,
	)
	
	// This will automatically send TraceId header.
	req, _ := http.NewRequest("GET", "http://localhost:3333/proxy", nil)
	_, _ = http.DefaultClient.Do(req)
}
```

## Get time from UUIDv7 value

```
$ go run github.com/go-chi/traceid/cmd/traceid 018e0ee7-3605-7d75-b344-01062c6fd8bc
2024-03-05 14:56:57.477 +0100 CET
```

You can also create a new UUIDv7:
```
$ go run github.com/go-chi/traceid/cmd/traceid
018e0ee7-3605-7d75-b344-01062c6fd8bc
```

## License
[MIT](./LICENSE)