Skip to content

Commit

Permalink
enhance echoserver to log out headers
Browse files Browse the repository at this point in the history
  • Loading branch information
tednaleid committed Jul 27, 2024
1 parent 79dc93a commit f293298
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 26 deletions.
20 changes: 15 additions & 5 deletions cli/cli_echoserver_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package cli

import (
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"github.com/tednaleid/ganda/echoserver"
"github.com/urfave/cli/v3"
"golang.org/x/net/context"
"io"
Expand Down Expand Up @@ -54,11 +56,19 @@ func TestAllTogetherNow(t *testing.T) {

runResults, _ := RunGanda([]string{"ganda"}, strings.NewReader(url+"\n"))

runResults.assert(
t,
"hello/world\n",
"Response: 200 "+url+"\n",
)
assert.Equal(t, "Response: 200 "+url+"\n", runResults.stderr, "expected logger stderr")

var logEntry echoserver.LogEntry
if err := json.Unmarshal([]byte(runResults.stdout), &logEntry); err != nil {
t.Fatalf("failed to unmarshal response body: %v", err)
}

assert.Equal(t, "GET", logEntry.Method, "expected method")
assert.Equal(t, "/hello/world", logEntry.URI, "expected URI")
assert.Equal(t, "Go-http-client/1.1", logEntry.UserAgent, "expected user agent")
assert.Equal(t, 200, logEntry.Status, "expected status")
assert.Contains(t, logEntry.Headers, "Accept-Encoding", "expected headers to contain Accept-Encoding")
assert.Contains(t, logEntry.Headers, "User-Agent", "expected headers to contain User-Agent")

shutdownFunc()
}
Expand Down
72 changes: 55 additions & 17 deletions echoserver/echoserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,55 @@ package echoserver

import (
"context"
"encoding/json"
"fmt"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"io"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
)

type LogEntry struct {
Time string `json:"time"`
ID string `json:"id"`
RemoteIP string `json:"remote_ip"`
Host string `json:"host"`
Method string `json:"method"`
URI string `json:"uri"`
UserAgent string `json:"user_agent"`
Status int `json:"status"`
Headers map[string]string `json:"headers"`
RequestBody string `json:"request_body"`
}

func Echoserver(port int64, out io.Writer) (func() error, error) {
e := echo.New()
e.HideBanner = true
e.HidePort = true

e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Output: out,
e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {
logEntryJSON := createLogEntry(c, reqBody)
fmt.Fprintf(out, "%s\n", logEntryJSON)
}))

e.Use(middleware.Logger())
e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {}))
e.Use(middleware.Recover())
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: 5,
}))

e.GET("/*", getResult)
e.POST("/*", postResult)

s := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: e,
Addr: fmt.Sprintf(":%d", port),
Handler: e,
ReadTimeout: 5 * time.Minute,
WriteTimeout: 5 * time.Minute,
}

go func() {
Expand All @@ -53,21 +73,39 @@ func Echoserver(port int64, out io.Writer) (func() error, error) {
}

func getResult(c echo.Context) error {
id := c.Param("*")
return c.String(http.StatusOK, id)
reqBody, _ := io.ReadAll(c.Request().Body)
logEntryJSON := createLogEntry(c, reqBody)
return c.JSONBlob(http.StatusOK, logEntryJSON)
}

func postResult(c echo.Context) error {
if c.Request().Body != nil {
reqBody, _ := io.ReadAll(c.Request().Body)
reqString := string(reqBody)
reqBody, _ := io.ReadAll(c.Request().Body)
logEntryJSON := createLogEntry(c, reqBody)
return c.JSONBlob(http.StatusOK, logEntryJSON)
}

if len(reqString) > 0 {
println(reqString)
return c.String(http.StatusOK, reqString)
}
func createLogEntry(c echo.Context, reqBody []byte) []byte {
headers := formatHeaders(c.Request().Header)
logEntry := LogEntry{
Time: time.Now().Format(time.RFC3339),
ID: c.Response().Header().Get(echo.HeaderXRequestID),
RemoteIP: c.RealIP(),
Host: c.Request().Host,
Method: c.Request().Method,
URI: c.Request().RequestURI,
UserAgent: c.Request().UserAgent(),
Status: c.Response().Status,
Headers: headers,
RequestBody: string(reqBody),
}
logEntryJSON, _ := json.Marshal(logEntry)
return logEntryJSON
}

id := c.Param("*")
return c.String(http.StatusOK, id)
func formatHeaders(headers http.Header) map[string]string {
formattedHeaders := make(map[string]string)
for key, values := range headers {
formattedHeaders[key] = strings.Join(values, ", ")
}
return formattedHeaders
}
51 changes: 47 additions & 4 deletions echoserver/echoserver_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package echoserver

import (
"encoding/json"
"io"
"net"
"net/http"
Expand Down Expand Up @@ -59,8 +60,29 @@ func TestEchoserverGET(t *testing.T) {
t.Fatal(err)
}

if string(body) != "foobar" {
t.Errorf("expected body 'foobar', got '%s'", body)
var logEntry LogEntry
if err := json.Unmarshal(body, &logEntry); err != nil {
t.Fatalf("failed to unmarshal response body: %v", err)
}

if logEntry.URI != "/foobar" {
t.Errorf("expected uri '/foobar', got '%s'", logEntry.URI)
}

if logEntry.Method != "GET" {
t.Errorf("expected method 'GET', got '%s'", logEntry.Method)
}

if logEntry.Status != 200 {
t.Errorf("expected status 200, got %d", logEntry.Status)
}

if logEntry.RequestBody != "" {
t.Errorf("expected request_body to be empty, got '%s'", logEntry.RequestBody)
}

if logEntry.Headers["User-Agent"] != "Go-http-client/1.1" {
t.Errorf("expected User-Agent header to be set")
}
})
}
Expand All @@ -85,8 +107,29 @@ func TestEchoserverPOST(t *testing.T) {
t.Fatal(err)
}

if string(body) != jsonBody {
t.Errorf("expected body '%s', got '%s'", jsonBody, body)
var logEntry LogEntry
if err := json.Unmarshal(body, &logEntry); err != nil {
t.Fatalf("failed to unmarshal response body: %v", err)
}

if logEntry.URI != "/foobar" {
t.Errorf("expected uri '/foobar', got '%s'", logEntry.URI)
}

if logEntry.Method != "POST" {
t.Errorf("expected method 'GET', got '%s'", logEntry.Method)
}

if logEntry.Status != 200 {
t.Errorf("expected status 200, got %d", logEntry.Status)
}

if logEntry.RequestBody != jsonBody {
t.Errorf("expected request_body to be empty, got '%s'", logEntry.RequestBody)
}

if logEntry.Headers["User-Agent"] != "Go-http-client/1.1" {
t.Errorf("expected User-Agent header to be set")
}
})
}

0 comments on commit f293298

Please sign in to comment.