Hello,
I’m auditing http request and response by dumping each right into a flat file which works in the mean time. Nevertheless, I’ve a sense this may be improved as a result of so far as I see, useful resource utilization is excessive (RAM and so on.).
Do you suppose there’s higher method or can we enhance this code? Notably excited about AUDIT REQUEST
and AUDIT RESPONSE
blocks.
Thanks
Bench outcomes under displays 100 concurrent customers sending requests for 10 seconds.
Alloc = 12 MiB TotalAlloc = 534 MiB Sys = 27 MiB NumGC = 190
Alloc = 2 MiB TotalAlloc = 309 MiB Sys = 15 MiB NumGC = 148
Alloc = 4 MiB TotalAlloc = 348 MiB Sys = 11 MiB NumGC = 172
Alloc = 10 MiB TotalAlloc = 223 MiB Sys = 23 MiB NumGC = 39
Alloc = 3 MiB TotalAlloc = 167 MiB Sys = 11 MiB NumGC = 76
...
bundle xhttp
import (
"bytes"
"context"
"fmt"
"io"
"internet/http"
"internet/http/httputil"
"os"
"path/filepath"
"github.com/google/uuid"
)
sort Consumer struct {
Consumer http.RoundTripper
}
func (c Consumer) Request(ctx context.Context, met, url string, bdy io.Reader, hdrs map[string]string) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, met, url, bdy)
if err != nil {
return nil, err
}
for ok, v := vary hdrs {
req.Header.Add(ok, v)
}
id := uuid.NewString()
// AUDIT REQUEST -----------------------------------------------------------
reqCopy := req.Clone(req.Context())
if req.Physique != nil || req.Physique != http.NoBody {
var buff bytes.Buffer
if _, err := io.Copy(&buff, req.Physique); err == nil {
req.Physique = io.NopCloser(bytes.NewReader(buff.Bytes()))
reqCopy.Physique = io.NopCloser(bytes.NewReader(buff.Bytes()))
}
}
go LogRequest(reqCopy, id)
// -------------------------------------------------------------------------
res, err := c.Consumer.RoundTrip(req)
if err != nil {
return nil, err
}
// AUDIT RESPONSE ----------------------------------------------------------
resCopy := *res
if res.Physique != nil || res.Physique != http.NoBody {
var buff bytes.Buffer
if _, err := io.Copy(&buff, res.Physique); err == nil {
res.Physique = io.NopCloser(bytes.NewReader(buff.Bytes()))
resCopy.Physique = io.NopCloser(bytes.NewReader(buff.Bytes()))
}
}
go LogResponse(&resCopy, req, id)
// -------------------------------------------------------------------------
return res, nil
}
func LogRequest(req *http.Request, id string) {
dump, err := httputil.DumpRequest(req, true)
if err != nil {
fmt.Println("dump request", err)
return
}
path := id + "_request.log"
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
fmt.Println("mkdir all:", err)
return
}
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0600))
if err != nil {
fmt.Println("open file:", err)
return
}
defer file.Shut()
if _, err := file.Write(dump); err != nil {
fmt.Println("file write:", err)
return
}
}
func LogResponse(res *http.Response, req *http.Request, id string) {
dump, err := httputil.DumpResponse(res, true)
if err != nil {
fmt.Println("dump response", err)
return
}
defer res.Physique.Shut()
technique := http.MethodGet
if req.Methodology != "" {
technique = req.Methodology
}
uri := req.RequestURI
if uri == "" {
uri = req.URL.RequestURI()
}
dump = append(
[]byte(fmt.Sprintf("%s %s HTTP/%d.%dnHost: %sn", technique, uri, req.ProtoMajor, req.ProtoMinor, req.URL.Host)),
dump...,
)
path := id + "_response.log"
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
fmt.Println("mkdir all:", err)
return
}
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0600))
if err != nil {
fmt.Println("open file:", err)
return
}
defer file.Shut()
if _, err := file.Write(dump); err != nil {
fmt.Println("file write:", err)
return
}
}