Skip to content

Commit bfcebd7

Browse files
henrybarretogustavosbarreto
authored andcommitted
feat(pkg): add logging on each request and response from internal http client
1 parent 68f0f36 commit bfcebd7

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

pkg/api/internalclient/client.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
resty "github.com/go-resty/resty/v2"
1010
"github.com/shellhub-io/shellhub/pkg/worker"
11-
"github.com/sirupsen/logrus"
11+
log "github.com/sirupsen/logrus"
1212
)
1313

1414
type Client interface {
@@ -35,7 +35,7 @@ type Config struct {
3535

3636
type client struct {
3737
http *resty.Client
38-
logger *logrus.Logger
38+
logger *log.Logger
3939
worker worker.Client
4040

4141
Config *Config
@@ -88,6 +88,32 @@ func NewClient(opts ...clientOption) (Client, error) {
8888
return r.StatusCode() >= http.StatusInternalServerError && r.StatusCode() != http.StatusNotImplemented
8989
})
9090

91+
httpClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
92+
// NOTE: Add a unique request ID to each request for better traceability.
93+
r.Header.Set("X-Request-Id", randomString(32))
94+
95+
log.WithFields(log.Fields{
96+
"id": r.Header.Get("X-Request-Id"),
97+
"attempt": r.Attempt,
98+
"method": r.Method,
99+
"url": r.URL,
100+
}).Info("internal client request send")
101+
102+
return nil
103+
})
104+
105+
httpClient.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
106+
log.WithFields(log.Fields{
107+
"id": r.Header().Get("X-Request-Id"),
108+
"attempt": r.Request.Attempt,
109+
"method": r.Request.Method,
110+
"url": r.Request.URL,
111+
"status": r.StatusCode(),
112+
}).Info("internal client response received")
113+
114+
return nil
115+
})
116+
91117
return c, nil
92118
}
93119

pkg/api/internalclient/util.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package internalclient
2+
3+
// NOTE: Code adapted from github.com/labstack/echo/[email protected]/middleware/util.go.
4+
5+
import (
6+
"bufio"
7+
"crypto/rand"
8+
"io"
9+
"sync"
10+
)
11+
12+
// https://tip.golang.org/doc/go1.19#:~:text=Read%20no%20longer%20buffers%20random%20data%20obtained%20from%20the%20operating%20system%20between%20calls
13+
var randomReaderPool = sync.Pool{New: func() interface{} {
14+
return bufio.NewReader(rand.Reader)
15+
}}
16+
17+
const (
18+
randomStringCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
19+
randomStringCharsetLen = 52 // len(randomStringCharset)
20+
randomStringMaxByte = 255 - (256 % randomStringCharsetLen)
21+
)
22+
23+
func randomString(length uint8) string {
24+
reader := randomReaderPool.Get().(*bufio.Reader)
25+
defer randomReaderPool.Put(reader)
26+
27+
b := make([]byte, length)
28+
r := make([]byte, length+(length/4)) // perf: avoid read from rand.Reader many times
29+
var i uint8 = 0
30+
31+
// security note:
32+
// we can't just simply do b[i]=randomStringCharset[rb%len(randomStringCharset)],
33+
// len(len(randomStringCharset)) is 52, and rb is [0, 255], 256 = 52 * 4 + 48.
34+
// make the first 48 characters more possibly to be generated then others.
35+
// So we have to skip bytes when rb > randomStringMaxByte
36+
37+
for {
38+
_, err := io.ReadFull(reader, r)
39+
if err != nil {
40+
panic("unexpected error happened when reading from bufio.NewReader(crypto/rand.Re der)")
41+
}
42+
for _, rb := range r {
43+
if rb > randomStringMaxByte {
44+
// Skip this number to avoid bias.
45+
continue
46+
}
47+
b[i] = randomStringCharset[rb%randomStringCharsetLen]
48+
i++
49+
if i == length {
50+
return string(b)
51+
}
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)