Skip to content

Commit

Permalink
Merge pull request #7 from nrfta/feature/seng-804
Browse files Browse the repository at this point in the history
chore: add slog http middleware
  • Loading branch information
josemarluedke authored Nov 14, 2023
2 parents 52691fe + 4794509 commit 9fbab9b
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 5 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches:
- main
- 'v*'
- "v*"
pull_request: {}
release:
types: [published]
Expand All @@ -14,13 +14,17 @@ jobs:
name: Tests
runs-on: ubuntu-latest

strategy:
matrix:
go-version: [1.14.x, 1.21.x]

steps:
- uses: actions/checkout@v2

- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: ${{matrix.go-version}}

- name: Install Dependencies
run: go mod download
Expand Down
4 changes: 3 additions & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package log

import "context"

type logContextType string

// ContextKeyLogFields is the key for the logging fields context value.
const ContextKeyLogFields = "nrfta/go-log/Fields"
const ContextKeyLogFields logContextType = "nrfta/go-log/Fields"

// WithContext initializes context with a logging fields stack with the given fields. If the given
// context has already bene initialized, then the fields are pushed onto the existing stack.
Expand Down
15 changes: 14 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/nrfta/go-log

go 1.14
go 1.21

require (
github.com/go-chi/chi v4.1.2+incompatible
Expand All @@ -9,3 +9,16 @@ require (
github.com/onsi/gomega v1.10.1
github.com/sirupsen/logrus v1.6.0
)

require (
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/nxadm/tail v1.4.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 // indirect
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
Expand Down
43 changes: 43 additions & 0 deletions slog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//go:build go1.21
// +build go1.21

package log

import (
"log/slog"
"net/http"
"time"

"github.com/go-chi/chi/middleware"
)

// NewSLogChiMiddleware is used to log http request information. It takes
// a pointer to an slog.Logger to use. If `l` is nil, it uses the
// default logger
func NewSLogChiMiddleware(l *slog.Logger) func(http.Handler) http.Handler {
if l == nil {
l = slog.Default()
}

return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)

defer func(start time.Time) {
l.LogAttrs(
r.Context(),
slog.LevelInfo,
"HTTP Request Served",
slog.String("proto", r.Proto),
slog.String("path", r.URL.Path),
slog.Duration("duration", time.Since(start)),
slog.Int("status", ww.Status()),
slog.Int("size", ww.BytesWritten()),
slog.String("ip", r.RemoteAddr),
)
}(time.Now())

next.ServeHTTP(ww, r)
})
}
}
62 changes: 62 additions & 0 deletions slog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//go:build go1.21
// +build go1.21

package log_test

import (
"bytes"
"encoding/json"
"log/slog"
"net/http"
"net/http/httptest"
"strings"

"github.com/nrfta/go-log"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Logger", func() {
Describe("NewSlogHTTPMiddleware", func() {
It("should log http request information", func() {
var (
buf bytes.Buffer
logger = slog.New(slog.NewJSONHandler(&buf, nil))
mw = log.NewSLogChiMiddleware(logger)
res = "test"
hf = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(res))
})
)

ts := httptest.NewServer(mw(hf))
defer ts.Close()

_, err := http.Get(ts.URL)
Expect(err).To(Succeed())

type logOutput struct {
Msg string `json:"msg"`
Proto string `json:"proto"`
Path string `json:"path"`
Duration int `json:"duration"`
Status int `json:"status"`
Size int `json:"size"`
IP string `json:"ip"`
}

var lo logOutput
err = json.Unmarshal(buf.Bytes(), &lo)
Expect(err).To(Succeed())

Expect(lo.Msg).To(Equal("HTTP Request Served"))
Expect(lo.Proto).To(Equal("HTTP/1.1"))
Expect(lo.Path).To(Equal("/"))
Expect(lo.Duration).To(BeNumerically(">", 0))
Expect(lo.Status).To(Equal(200))
Expect(lo.Size).To(Equal(len(res)))
Expect(strings.Split(lo.IP, ":")[0]).To(Equal("127.0.0.1"))
})
})
})

0 comments on commit 9fbab9b

Please sign in to comment.