~poldi1405/glog

ad160a183db673bec295816bd4b63b704ff970db — Moritz Poldrack 2 years ago 3758f15
added first work on logformats
4 files changed, 188 insertions(+), 0 deletions(-)

A formats/common-log-format.go
A formats/common-log-format_test.go
A formats/go.mod
A formats/go.sum
A formats/common-log-format.go => formats/common-log-format.go +119 -0
@@ 0,0 1,119 @@
package formats

import (
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"git.sr.ht/~poldi1405/glog"
	"github.com/valyala/fasthttp"
)

// Common log format as described in https://wikiless.org/wiki/Common_Log_Format?lang=en

func CommonLogFormat(lvl glog.Level, t time.Time, caller string, message string) string {
	return fmt.Sprintf(message, t.Format("02/Jan/2006:15:04:05 -0700"))
}

// CLFormatFromRequest allows passing a net/http.Request to generate the
// message needed for proper CLF
func CLFormatFromRequest(r *http.Request, bodySize int64, userIdentifier ...string) string {
	buf := &strings.Builder{}
	res := csv.NewWriter(buf)

	user, _, ok := r.BasicAuth()
	if !ok {
		user = "-"
	}

	userIdentifier = append(userIdentifier, "-")

	res.Comma = ' '
	res.Write([]string{
		r.RemoteAddr,
		userIdentifier[0],
		user,
		"[%s]",
		fmt.Sprintf("%s %s %s", r.Method, r.URL.Path, r.Proto),
		strconv.Itoa(r.Response.StatusCode),
		strconv.FormatInt(bodySize, 10),
	})

	return buf.String()
}

// CLFormatFromRequest allows passing a github.com/valyala/fasthttp.RequestCtx
// to generate the message needed for proper CLF
func CLFormatFromRequestCtx(ctx *fasthttp.RequestCtx, userIdentifier ...string) string {
	buf := bytes.NewBuffer([]byte{})
	res := csv.NewWriter(buf)

	var user string
	auth := ctx.Request.Header.Peek("Authorization")
	if len(auth) == 0 {
		user = "-"
	} else {
		// shamelessly stolen from net/http/request.go
		// dont look at it{{{
		// seriously, don't.{{{
		// okay, you've been warned.{{{
		u, _, _ := func(auth string) (username, password string, ok bool) {
			const prefix = "Basic "
			username = "-"
			lower := func(b byte) byte {
				if 'A' <= b && b <= 'Z' {
					return b + ('a' - 'A')
				}
				return b
			}

			// Case insensitive prefix match. See Issue 22736.
			if len(auth) < len(prefix) || !func(s, t string) bool {
				if len(s) != len(t) {
					return false
				}
				for i := 0; i < len(s); i++ {
					if lower(s[i]) != lower(t[i]) {
						return false
					}
				}
				return true
			}(auth[:len(prefix)], prefix) {
				return
			}
			c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
			if err != nil {
				return
			}
			cs := string(c)
			s := strings.IndexByte(cs, ':')
			if s < 0 {
				return
			}
			return cs[:s], cs[s+1:], true
		}(string(auth)) // }}}}}}}}}
		user = u
	}

	userIdentifier = append(userIdentifier, "-")

	res.Comma = ' '
	res.Write([]string{
		ctx.RemoteAddr().String(),
		userIdentifier[0],
		user,
		"[%s]",
		fmt.Sprintf("%s %s %s", string(ctx.Method()), string(ctx.Request.URI().Path()), ctx.Request.Header.Protocol()),
		strconv.Itoa(ctx.Response.StatusCode()),
		strconv.Itoa(len(ctx.Response.Body())),
	})

	return buf.String()
}

var _ glog.FormatFunction = CommonLogFormat

A formats/common-log-format_test.go => formats/common-log-format_test.go +30 -0
@@ 0,0 1,30 @@
package formats

import (
	"fmt"
	"net/http"
	"net/url"
	"testing"

	"git.sr.ht/~poldi1405/glog"
)

func TestCLF(t *testing.T) {
	req := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Path: "/some-file.txt",
		},
		Proto:      "HTTP",
		ProtoMajor: 1,
		ProtoMinor: 0,
		RemoteAddr: "127.0.0.1",
		Response: &http.Response{
			StatusCode: 200,
		},
	}
	glog.LogLevel = glog.INFO
	glog.LogFormatter = CommonLogFormat
	fmt.Println(CLFormatFromRequest(req, 1234))
	glog.Info(CLFormatFromRequest(req, 1234))
}

A formats/go.mod => formats/go.mod +15 -0
@@ 0,0 1,15 @@
module mpldr.codes/glog-formats

go 1.17

require (
	git.sr.ht/~poldi1405/glog v1.0.0
	github.com/valyala/fasthttp v1.31.0
)

require (
	git.sr.ht/~poldi1405/go-ansi v1.4.1 // indirect
	github.com/andybalholm/brotli v1.0.2 // indirect
	github.com/klauspost/compress v1.13.4 // indirect
	github.com/valyala/bytebufferpool v1.0.0 // indirect
)

A formats/go.sum => formats/go.sum +24 -0
@@ 0,0 1,24 @@
git.sr.ht/~poldi1405/glog v1.0.0 h1:nrIhLr7Y3V1mvfmDT59H1fo0cmUumVQHHd3sjp0p62M=
git.sr.ht/~poldi1405/glog v1.0.0/go.mod h1:1EruLJndk4xogOSzbLIrpbW4bdzB/vA8DX+Rr0z76Vo=
git.sr.ht/~poldi1405/go-ansi v1.4.1 h1:Lo/Z8/ZUHbVpTGbg2gicvcb1upzhgGOpu7L0hZe3lU0=
git.sr.ht/~poldi1405/go-ansi v1.4.1/go.mod h1:CUyHf6iVnIVCN0Nv7616s4wxnOF3gFAhFLrsMstyg3Q=
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.31.0 h1:lrauRLII19afgCs2fnWRJ4M5IkV0lo2FqA61uGkNBfE=
github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=