Skip to content

Commit 90cae92

Browse files
authored
Merge pull request #5 from aaronvb/add-details-flag
Add details flag
2 parents 3ee18a0 + 3614f1c commit 90cae92

File tree

7 files changed

+133
-7
lines changed

7 files changed

+133
-7
lines changed

cmd/protocol.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func init() {
2020
}
2121

2222
func http(cmd *cobra.Command, args []string) {
23-
renderer := &renderer.Printer{Port: Port, Addr: Address, BuildInfo: BuildInfo}
23+
renderer := &renderer.Printer{Port: Port, Addr: Address, BuildInfo: BuildInfo, Details: Details}
2424
httpServer := server.Http{Addr: Address, Port: Port, ResponseCode: ResponseCode, Output: renderer}
2525
httpServer.Start()
2626
}

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var (
88
Port int
99
ResponseCode int
1010
BuildInfo map[string]string
11+
Details bool
1112
)
1213

1314
var rootCmd = &cobra.Command{
@@ -26,4 +27,5 @@ func init() {
2627
rootCmd.PersistentFlags().IntVarP(&Port, "port", "p", 8080, "sets the port for the endpoint")
2728
rootCmd.PersistentFlags().StringVarP(&Address, "address", "a", "localhost", "sets the address for the endpoint")
2829
rootCmd.PersistentFlags().IntVarP(&ResponseCode, "response_code", "r", 200, "sets the response code")
30+
rootCmd.PersistentFlags().BoolVar(&Details, "details", false, "shows header details in the request")
2931
}

pkg/renderer/printer.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"log"
66
"os"
7+
"sort"
8+
"strings"
79

810
"github.com/aaronvb/logrequest"
911
"github.com/pterm/pterm"
@@ -21,6 +23,9 @@ type Printer struct {
2123

2224
// Contains build info
2325
BuildInfo map[string]string
26+
27+
// Determines if header details should be shown with the request
28+
Details bool
2429
}
2530

2631
// Start renders the initial header and the spinner. The Spinner should be consistent during
@@ -46,6 +51,11 @@ func (p *Printer) startText() string {
4651
Sprintf(p.BuildInfo["version"])
4752

4853
text := fmt.Sprintf("%s %s\nListening on http://%s:%d", primary, version, p.Addr, p.Port)
54+
55+
if p.Details {
56+
text = fmt.Sprintf("%s\nDetails: %t", text, p.Details)
57+
}
58+
4959
return text
5060
}
5161

@@ -63,7 +73,7 @@ func (p *Printer) Fatal(err error) {
6373
}
6474

6575
// IncomingRequest handles the output for incoming requests to the server.
66-
func (p *Printer) IncomingRequest(fields logrequest.RequestFields, params string) {
76+
func (p *Printer) IncomingRequest(fields logrequest.RequestFields, params string, headers map[string][]string) {
6777
p.Spinner.Stop()
6878
prefix := pterm.Prefix{
6979
Text: fields.Method,
@@ -72,6 +82,12 @@ func (p *Printer) IncomingRequest(fields logrequest.RequestFields, params string
7282

7383
text := p.incomingRequestText(fields, params)
7484
pterm.Info.WithPrefix(prefix).Println(text)
85+
86+
if p.Details {
87+
table := p.incomingRequestHeadersTable(headers)
88+
pterm.Printf("%s\n\n", table)
89+
}
90+
7591
p.startSpinner()
7692
}
7793

@@ -85,6 +101,35 @@ func (p *Printer) incomingRequestText(fields logrequest.RequestFields, params st
85101
return text
86102
}
87103

104+
// incomingRequestHeadersTable constructs the headers table string.
105+
// This takes the headers map from the request and sorts it alphabetically by key.
106+
func (p *Printer) incomingRequestHeadersTable(headers map[string][]string) string {
107+
keys := make([]string, 0, len(headers))
108+
for key := range headers {
109+
keys = append(keys, key)
110+
}
111+
112+
sort.Strings(keys)
113+
114+
var headersFormatted [][]string
115+
116+
headerRow := []string{"Header", "Value"}
117+
headersFormatted = append(headersFormatted, headerRow)
118+
119+
for _, key := range keys {
120+
value := strings.Join(headers[key], ",")
121+
headersRow := []string{key, value}
122+
headersFormatted = append(headersFormatted, headersRow)
123+
}
124+
125+
headersTable, err := pterm.DefaultTable.WithHasHeader().WithData(headersFormatted).Srender()
126+
if err != nil {
127+
pterm.Error.WithShowLineNumber(false).Println(err)
128+
}
129+
130+
return headersTable
131+
}
132+
88133
// Create the spinner which will be displayed at the bottom.
89134
func (p *Printer) startSpinner() {
90135
listeningText := pterm.DefaultBasicText.

pkg/renderer/printer_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ func TestStartText(t *testing.T) {
1919
}
2020
}
2121

22+
func TestStartTextWithDetails(t *testing.T) {
23+
pterm.DisableColor()
24+
printer := Printer{
25+
Addr: "localhost",
26+
Port: 8080,
27+
BuildInfo: map[string]string{"version": "dev"},
28+
Details: true}
29+
result := printer.startText()
30+
expected := fmt.Sprintf(
31+
"Request Hole %s\nListening on http://%s:%d\nDetails: %t", "dev",
32+
printer.Addr, printer.Port, printer.Details)
33+
34+
if result != expected {
35+
t.Errorf("Expected %s, got %s", expected, result)
36+
}
37+
}
38+
2239
func TestIncomingRequestText(t *testing.T) {
2340
pterm.DisableColor()
2441
printer := Printer{}
@@ -34,3 +51,27 @@ func TestIncomingRequestText(t *testing.T) {
3451
t.Errorf("Expected %s, got %s", expected, result)
3552
}
3653
}
54+
55+
func TestIncomingRequestHeadersTables(t *testing.T) {
56+
pterm.DisableColor()
57+
printer := Printer{}
58+
headers := map[string][]string{
59+
"hello": {"world", "foobar"},
60+
"foo": {"bar"},
61+
}
62+
result := printer.incomingRequestHeadersTable(headers)
63+
64+
headersForTable := [][]string{}
65+
headersForTable = append(headersForTable, []string{"Header", "Value"})
66+
headersForTable = append(headersForTable, []string{"foo", "bar"})
67+
headersForTable = append(headersForTable, []string{"hello", "world,foobar"})
68+
69+
expected, err := pterm.DefaultTable.WithHasHeader().WithData(headersForTable).Srender()
70+
if err != nil {
71+
t.Error(err)
72+
}
73+
74+
if result != expected {
75+
t.Errorf("Expected %s, got %s", expected, result)
76+
}
77+
}

pkg/renderer/renderer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ type Renderer interface {
1818
// Fatal is used when we need to display a message and should always exit the CLI.
1919
Fatal(error)
2020

21-
IncomingRequest(logrequest.RequestFields, string)
21+
IncomingRequest(logrequest.RequestFields, string, map[string][]string)
2222
}

pkg/server/http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@ func (s *Http) logRequest(next http.Handler) http.Handler {
6363
lr := logrequest.LogRequest{Request: r, Writer: w, Handler: next}
6464
fields := lr.ToFields()
6565
params := logparams.LogParams{Request: r, HidePrefix: true}
66-
s.Output.IncomingRequest(fields, params.ToString())
66+
s.Output.IncomingRequest(fields, params.ToString(), r.Header)
6767
})
6868
}

pkg/server/http_test.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ import (
1212
)
1313

1414
type MockPrinter struct {
15-
fields logrequest.RequestFields
16-
params string
15+
fields logrequest.RequestFields
16+
params string
17+
headers map[string][]string
1718
}
1819

1920
func (mp *MockPrinter) Fatal(error) {}
2021
func (mp *MockPrinter) Start() {}
2122
func (mp *MockPrinter) ErrorLogger() *log.Logger { return log.New(os.Stderr, "", 0) }
22-
func (mp *MockPrinter) IncomingRequest(fields logrequest.RequestFields, params string) {
23+
func (mp *MockPrinter) IncomingRequest(fields logrequest.RequestFields, params string, headers map[string][]string) {
2324
mp.fields = fields
2425
mp.params = params
26+
mp.headers = headers
2527
}
2628

2729
func TestResponseCodeFlag(t *testing.T) {
@@ -97,3 +99,39 @@ func TestLogRequest(t *testing.T) {
9799
}
98100
}
99101
}
102+
103+
func TestLogRequestHeaders(t *testing.T) {
104+
headers := map[string]string{
105+
"Content-Type": "application/json",
106+
"Foo": "bar",
107+
"Bearer": "hello!",
108+
}
109+
110+
renderer := &MockPrinter{}
111+
httpServer := Http{ResponseCode: 200, Output: renderer}
112+
srv := httptest.NewServer(httpServer.routes())
113+
defer srv.Close()
114+
115+
req, err := http.NewRequest(http.MethodGet, srv.URL, nil)
116+
if err != nil {
117+
t.Error(err)
118+
}
119+
120+
for key, value := range headers {
121+
req.Header.Set(key, value)
122+
}
123+
124+
resp, err := http.DefaultClient.Do(req)
125+
if err != nil {
126+
t.Error(err)
127+
}
128+
129+
defer resp.Body.Close()
130+
131+
for key, value := range headers {
132+
result := renderer.headers[key][0]
133+
if value != result {
134+
t.Errorf("Expected %s, got %s", value, result)
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)