Skip to content

Commit

Permalink
rename request-id in correlation-id (#19)
Browse files Browse the repository at this point in the history
* rename request-id in correlation-id

* fixup tripperware correlation from req.context
  • Loading branch information
instabledesign authored Oct 11, 2019
1 parent 3c74fbd commit ae8a6b4
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 123 deletions.
21 changes: 21 additions & 0 deletions correlation_id/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package correlation_id

import (
"net/http"
)

const HeaderName = "Correlation-Id"

type Config struct {
HeaderName string
IdGenerator func(*http.Request) string
}

func NewConfig() *Config {
return &Config{
HeaderName: HeaderName,
IdGenerator: func(_ *http.Request) string {
return DefaultIdGenerator.Generate(10)
},
}
}
19 changes: 19 additions & 0 deletions correlation_id/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package correlation_id_test

import (
"math/rand"
"testing"

"github.com/stretchr/testify/assert"

"github.com/gol4ng/httpware/correlation_id"
)

func TestNewConfig(t *testing.T) {
defaultRand := rand.New(correlation_id.NewLockedSource(rand.NewSource(1)))
correlation_id.DefaultIdGenerator = correlation_id.NewRandomIdGenerator(defaultRand)

for _, expectedId := range []string{"p1LGIehp1s", "uqtCDMLxiD"} {
assert.Equal(t, expectedId, correlation_id.NewConfig().IdGenerator(nil))
}
}
27 changes: 14 additions & 13 deletions request_id/generator.go → correlation_id/generator.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package request_id
package correlation_id

import (
"math/rand"
"net/http"
"time"
"unsafe"
)
Expand All @@ -16,14 +15,13 @@ const (
)

type RandomIdGenerator struct {
r *rand.Rand
length int
r *rand.Rand
}

func (rg *RandomIdGenerator) Generate(_ *http.Request) string {
b := make([]byte, rg.length)
func (rg *RandomIdGenerator) Generate(length int) string {
b := make([]byte, length)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := rg.length-1, rg.r.Int63(), letterIdxMax; i >= 0; {
for i, cache, remain := length-1, rg.r.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = rg.r.Int63(), letterIdxMax
}
Expand All @@ -37,15 +35,18 @@ func (rg *RandomIdGenerator) Generate(_ *http.Request) string {
return *(*string)(unsafe.Pointer(&b))
}

var DefaultRand = rand.New(NewLockedSource(rand.NewSource(time.Now().UTC().UnixNano())))
var DefaultIdGenerator = NewRandomIdGenerator(
DefaultRand,
10,
rand.New(
NewLockedSource(
rand.NewSource(
time.Now().UTC().UnixNano(),
),
),
),
)

func NewRandomIdGenerator(rand *rand.Rand, length int) *RandomIdGenerator {
func NewRandomIdGenerator(rand *rand.Rand) *RandomIdGenerator {
return &RandomIdGenerator{
r: rand,
length: length,
r: rand,
}
}
22 changes: 22 additions & 0 deletions correlation_id/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package correlation_id_test

import (
"math/rand"
"testing"

"github.com/stretchr/testify/assert"

"github.com/gol4ng/httpware/correlation_id"
)

func Test_Random(t *testing.T) {
assert.Equal(t, 10, len(correlation_id.DefaultIdGenerator.Generate(10)))
}

func Test_Random_NewSource(t *testing.T) {
r := rand.New(correlation_id.NewLockedSource(rand.NewSource(1)))
rg := correlation_id.NewRandomIdGenerator(r)
for _, expectedId := range []string{"DHIMG9FpXzp1LGIehp1s", "zAHyfjXUlrGhblT7txWd"} {
assert.Equal(t, expectedId, rg.Generate(20))
}
}
2 changes: 1 addition & 1 deletion request_id/rand.go → correlation_id/rand.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package request_id
package correlation_id

import (
"math/rand"
Expand Down
13 changes: 7 additions & 6 deletions request_id/rand_test.go → correlation_id/rand_test.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
package request_id_test
package correlation_id_test

import (
"github.com/stretchr/testify/assert"
"math/rand"
"testing"

"github.com/gol4ng/httpware/request_id"
"github.com/stretchr/testify/assert"

"github.com/gol4ng/httpware/correlation_id"
)

func Test_LockedSource_Int63(t *testing.T) {
s := request_id.NewLockedSource(rand.NewSource(1))
s := correlation_id.NewLockedSource(rand.NewSource(1))

for _, v := range []int64{5577006791947779410, 8674665223082153551} {
assert.Equal(t, v, s.Int63())
}
}

func Test_LockedSource_Uint64(t *testing.T) {
s := request_id.NewLockedSource(rand.NewSource(1))
s := correlation_id.NewLockedSource(rand.NewSource(1))

for _, v := range []uint64{0x4d65822107fcfd52, 0x78629a0f5f3f164f} {
assert.Equal(t, v, s.Uint64())
}
}

func Test_LockedSource_Seed(t *testing.T) {
s := request_id.NewLockedSource(rand.NewSource(1))
s := correlation_id.NewLockedSource(rand.NewSource(1))

for _, v := range []uint64{0x4d65822107fcfd52, 0x78629a0f5f3f164f} {
assert.Equal(t, v, s.Uint64())
Expand Down
6 changes: 3 additions & 3 deletions middleware/request_id.go → middleware/correlation_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import (
"net/http"

"github.com/gol4ng/httpware"
"github.com/gol4ng/httpware/request_id"
"github.com/gol4ng/httpware/correlation_id"
)

// RequestId middleware get request id header if provided or generate a request id
// CorrelationId middleware get request id header if provided or generate a request id
// It will add the request ID to request context and add it to response header to
func RequestId(config *request_id.Config) httpware.Middleware {
func CorrelationId(config *correlation_id.Config) httpware.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
id := req.Header.Get(config.HeaderName)
Expand Down
52 changes: 13 additions & 39 deletions middleware/request_id_test.go → middleware/correlation_id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,69 +10,43 @@ import (
"github.com/stretchr/testify/assert"

"github.com/gol4ng/httpware"
"github.com/gol4ng/httpware/correlation_id"
"github.com/gol4ng/httpware/middleware"
"github.com/gol4ng/httpware/request_id"
)

func TestRequestId(t *testing.T) {
request_id.DefaultRand = rand.New(request_id.NewLockedSource(rand.NewSource(1)))
request_id.DefaultIdGenerator = request_id.NewRandomIdGenerator(
request_id.DefaultRand,
10,
func TestCorrelationId(t *testing.T) {
correlation_id.DefaultIdGenerator = correlation_id.NewRandomIdGenerator(
rand.New(correlation_id.NewLockedSource(rand.NewSource(1))),
)

var handlerReq *http.Request
req := httptest.NewRequest(http.MethodGet, "http://fake-addr", nil)
responseWriter := &httptest.ResponseRecorder{}

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// not equal because req.WithContext create another request object
assert.NotEqual(t, req, r)
assert.Equal(t, "p1LGIehp1s", r.Header.Get(request_id.HeaderName))
assert.Equal(t, "p1LGIehp1s", r.Header.Get(correlation_id.HeaderName))
handlerReq = r
})

middleware.RequestId(request_id.NewConfig())(handler).ServeHTTP(responseWriter, req)
respHeaderValue := responseWriter.Header().Get(request_id.HeaderName)
reqContextValue := handlerReq.Context().Value(request_id.HeaderName).(string)
assert.Equal(t, "p1LGIehp1s", req.Header.Get(request_id.HeaderName))
middleware.CorrelationId(correlation_id.NewConfig())(handler).ServeHTTP(responseWriter, req)
respHeaderValue := responseWriter.Header().Get(correlation_id.HeaderName)
reqContextValue := handlerReq.Context().Value(correlation_id.HeaderName).(string)
assert.Equal(t, "p1LGIehp1s", req.Header.Get(correlation_id.HeaderName))
assert.True(t, len(respHeaderValue) == 10)
assert.True(t, len(reqContextValue) == 10)
assert.True(t, respHeaderValue == reqContextValue)
}

func TestRequestIdCustom(t *testing.T) {
var handlerReq *http.Request
req := httptest.NewRequest(http.MethodGet, "http://fake-addr", nil)
responseWriter := &httptest.ResponseRecorder{}

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// not equal because req.WithContext create another request object
assert.NotEqual(t, req, r)
assert.Equal(t, "my_fake_request_id", r.Header.Get(request_id.HeaderName))
handlerReq = r
})
config := request_id.NewConfig()
config.IdGenerator = func(request *http.Request) string {
return "my_fake_request_id"
}

middleware.RequestId(config)(handler).ServeHTTP(responseWriter, req)
headerValue := responseWriter.Header().Get(request_id.HeaderName)
reqContextValue := handlerReq.Context().Value(request_id.HeaderName).(string)
assert.NotEqual(t, "", req.Header.Get(request_id.HeaderName))
assert.Equal(t, "my_fake_request_id", headerValue)
assert.Equal(t, "my_fake_request_id", reqContextValue)
assert.True(t, headerValue == reqContextValue)
}

// =====================================================================================================================
// ========================================= EXAMPLES ==================================================================
// =====================================================================================================================

func ExampleRequestId() {
func ExampleCorrelationId() {
port := ":5001"

config := request_id.NewConfig()
config := correlation_id.NewConfig()
// you can override default header name
config.HeaderName = "my-personal-header-name"
// you can override default id generator
Expand All @@ -83,7 +57,7 @@ func ExampleRequestId() {
// we recommend to use MiddlewareStack to simplify managing all wanted middlewares
// caution middleware order matters
stack := httpware.MiddlewareStack(
middleware.RequestId(config),
middleware.CorrelationId(config),
)

srv := http.NewServeMux()
Expand Down
19 changes: 0 additions & 19 deletions request_id/config.go

This file was deleted.

22 changes: 0 additions & 22 deletions request_id/generator_test.go

This file was deleted.

12 changes: 9 additions & 3 deletions tripperware/request_id.go → tripperware/correlation_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ import (
"net/http"

"github.com/gol4ng/httpware"
"github.com/gol4ng/httpware/request_id"
"github.com/gol4ng/httpware/correlation_id"
)

// RequestId tripperware gets request id header if provided or generates a request id
// CorrelationId tripperware gets request id header if provided or generates a request id
// It will add the request ID to request context
func RequestId(config *request_id.Config) httpware.Tripperware {
func CorrelationId(config *correlation_id.Config) httpware.Tripperware {
return func(next http.RoundTripper) http.RoundTripper {
return httpware.RoundTripFunc(func(req *http.Request) (resp *http.Response, err error) {
if v, ok := req.Context().Value(config.HeaderName).(string); ok {
req.Header.Add(config.HeaderName, v)
return next.RoundTrip(req)
}

var id string
if req.Header != nil {
id = req.Header.Get(config.HeaderName)
}

if id == "" {
id = config.IdGenerator(req)
// add requestId header to current request
Expand Down
Loading

0 comments on commit ae8a6b4

Please sign in to comment.