Commit db9ab4aa authored by Adam Reese's avatar Adam Reese

(feat): http request logging

parent 145d5e0c
......@@ -22,6 +22,8 @@ type Client struct {
Host string
// The protocol. Currently only http and https are supported.
Protocol string
// Transport
Transport http.RoundTripper
}
// NewClient creates a new DM client. Host name is required.
......@@ -30,6 +32,7 @@ func NewClient(host string) *Client {
HTTPTimeout: DefaultHTTPTimeout,
Protocol: "https",
Host: host,
Transport: NewDebugTransport(nil),
}
}
......@@ -71,6 +74,7 @@ func (c *Client) callHttp(path, method, action string, reader io.ReadCloser) (st
client := http.Client{
Timeout: time.Duration(time.Duration(DefaultHTTPTimeout) * time.Second),
Transport: c.Transport,
}
response, err := client.Do(request)
......
package dm
import (
"fmt"
"io"
"net/http"
"net/http/httputil"
"os"
)
type debugTransport struct {
// Writer is the logging destination
Writer io.Writer
http.RoundTripper
}
func NewDebugTransport(rt http.RoundTripper) http.RoundTripper {
return debugTransport{
RoundTripper: rt,
Writer: os.Stderr,
}
}
func (tr debugTransport) CancelRequest(req *http.Request) {
type canceler interface {
CancelRequest(*http.Request)
}
if cr, ok := tr.transport().(canceler); ok {
cr.CancelRequest(req)
}
}
func (tr debugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
tr.logRequest(req)
resp, err := tr.transport().RoundTrip(req)
if err != nil {
return nil, err
}
tr.logResponse(resp)
return resp, err
}
func (tr debugTransport) transport() http.RoundTripper {
if tr.RoundTripper != nil {
return tr.RoundTripper
}
return http.DefaultTransport
}
func (tr debugTransport) logRequest(req *http.Request) {
dump, err := httputil.DumpRequestOut(req, true)
if err != nil {
fmt.Fprintf(tr.Writer, "%s: %s\n", "could not dump request", err)
}
fmt.Fprint(tr.Writer, string(dump))
}
func (tr debugTransport) logResponse(resp *http.Response) {
dump, err := httputil.DumpResponse(resp, true)
if err != nil {
fmt.Fprintf(tr.Writer, "%s: %s\n", "could not dump response", err)
}
fmt.Fprint(tr.Writer, string(dump))
}
package dm
import (
"bytes"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestDebugTransport(t *testing.T) {
handler := func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"awesome"}`))
}
server := httptest.NewServer(http.HandlerFunc(handler))
defer server.Close()
var output bytes.Buffer
client := &http.Client{
Transport: debugTransport{
Writer: &output,
},
}
_, err := client.Get(server.URL)
if err != nil {
t.Fatal(err.Error())
}
expected := []string{
"GET / HTTP/1.1",
"Accept-Encoding: gzip",
"HTTP/1.1 200 OK",
"Content-Length: 20",
"Content-Type: application/json",
`{"status":"awesome"}`,
}
actual := output.String()
for _, match := range expected {
if !strings.Contains(actual, match) {
t.Errorf("Expected %s to contain %s", actual, match)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment