From fb00ecd2b7bc4939bece9871fb5f3b110c942077 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sun, 13 Sep 2020 17:01:57 +0300 Subject: [PATCH] accesslog: add a blank configuration field as requested at #1627 --- middleware/accesslog/accesslog.go | 30 +++++++++++++++++++---- middleware/accesslog/accesslog_test.go | 34 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/middleware/accesslog/accesslog.go b/middleware/accesslog/accesslog.go index 99d5831a..b1ffd51a 100644 --- a/middleware/accesslog/accesslog.go +++ b/middleware/accesslog/accesslog.go @@ -143,15 +143,21 @@ type AccessLog struct { // // Defaults to "2006-01-02 15:04:05" TimeFormat string + // A text that will appear in a blank value. + // Applies to the default formatter on + // IP, RequestBody and ResponseBody fields, if enabled, so far. + // + // Defaults to nil. + Blank []byte // Round the latency based on the given duration, e.g. time.Second. // // Defaults to 0. LatencyRound time.Duration + // IP displays the remote address. // // Defaults to true. IP bool - // The number of bytes for the request body only. // Applied when BytesReceived is false. // @@ -174,7 +180,6 @@ type AccessLog struct { // They both default to false. BytesReceived bool BytesSent bool - // Enable request body logging. // Note that, if this is true then it modifies the underline request's body type. // @@ -257,6 +262,7 @@ func New(w io.Writer) *AccessLog { Clock: clockFunc(time.Now), Delim: defaultDelim, TimeFormat: defaultTimeFormat, + Blank: nil, LatencyRound: 0, Async: false, IP: true, @@ -808,7 +814,7 @@ func (ac *AccessLog) Print(ctx *context.Context, builder.WriteByte(ac.Delim) if ac.IP { - builder.WriteString(ip) + ac.writeText(builder, ip) builder.WriteByte(ac.Delim) } @@ -830,12 +836,12 @@ func (ac *AccessLog) Print(ctx *context.Context, } if ac.RequestBody { - builder.WriteString(reqBody) + ac.writeText(builder, reqBody) builder.WriteByte(ac.Delim) } if ac.ResponseBody { - builder.WriteString(respBody) + ac.writeText(builder, respBody) builder.WriteByte(ac.Delim) } @@ -848,6 +854,20 @@ func (ac *AccessLog) Print(ctx *context.Context, return } +// We could have a map of blanks per field, +// but let's don't coplicate things so much +// as the end-developer can use a custom template. +func (ac *AccessLog) writeText(buf *bytes.Buffer, s string) { + if len(s) == 0 { + if len(ac.Blank) == 0 { + return + } + buf.Write(ac.Blank) + } else { + buf.WriteString(s) + } +} + var lineBreaksReplacer = strings.NewReplacer("\n\r", " ", "\n", " ") func (ac *AccessLog) getErrorText(err error) (text string) { // caller checks for nil. diff --git a/middleware/accesslog/accesslog_test.go b/middleware/accesslog/accesslog_test.go index 612788db..c4d59fd1 100644 --- a/middleware/accesslog/accesslog_test.go +++ b/middleware/accesslog/accesslog_test.go @@ -169,6 +169,40 @@ func TestAccessLogBroker(t *testing.T) { ac.Close() } +func TestAccessLogBlank(t *testing.T) { + w := new(bytes.Buffer) + ac := New(w) + clockTime, _ := time.Parse(defaultTimeFormat, "1993-01-01 05:00:00") + ac.Clock = TClock(clockTime) + ac.Blank = []byte("") + + ac.Print( + nil, + time.Second, + defaultTimeFormat, + 200, + "GET", + "/", + "127.0.0.1", + "", + "", + 0, + 0, + nil, + nil, + nil, + ) + + ac.Close() + // the request and bodies length are enabled by-default, zero bytes length + // are written with 0 B and this cannot changed, so the request field + // should be written as "". + expected := "1993-01-01 05:00:00|1s|200|GET|/|127.0.0.1|0 B|0 B||\n" + if got := w.String(); expected != got { + t.Fatalf("expected:\n'%s'\n\nbut got:\n'%s'", expected, got) + } +} + type noOpFormatter struct{} func (*noOpFormatter) SetOutput(io.Writer) {}