Commit 9c3c4f7
Changed files (7)
pkg/log/context.go
@@ -0,0 +1,17 @@
+package log
+
+import (
+ "context"
+
+ "github.com/rs/zerolog"
+)
+
+func WithFields(ctx context.Context, fields Fields) {
+ From(ctx).UpdateContext(func(c zerolog.Context) zerolog.Context {
+ return c.Fields(fields.ToMap())
+ })
+}
+
+func From(ctx context.Context) *zerolog.Logger {
+ return zerolog.Ctx(ctx)
+}
pkg/log/fields.go
@@ -0,0 +1,7 @@
+package log
+
+type Fields map[string]interface{}
+
+func (f Fields) ToMap() map[string]interface{} {
+ return map[string]interface{}(f)
+}
pkg/log/log.go
@@ -0,0 +1,19 @@
+package log
+
+import (
+ "io"
+
+ "github.com/rs/zerolog"
+ "github.com/xlgmokha/x/pkg/convert"
+)
+
+func New(writer io.Writer, fields Fields) *zerolog.Logger {
+ return convert.ToPtr(
+ zerolog.
+ New(writer).
+ With().
+ Timestamp().
+ Fields(fields.ToMap()).
+ Logger(),
+ )
+}
pkg/log/log_test.go
@@ -0,0 +1,83 @@
+package log
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/rs/zerolog"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/xlgmokha/x/pkg/serde"
+)
+
+func TestLog(t *testing.T) {
+ t.Run("New", func(t *testing.T) {
+ var b bytes.Buffer
+ writer := bufio.NewWriter(&b)
+
+ log := New(writer, Fields{"env": "test"})
+ log.Print()
+
+ require.NoError(t, writer.Flush())
+
+ items, err := serde.FromJSON[map[string]string](bufio.NewReader(&b))
+ require.NoError(t, err)
+
+ assert.Equal(t, "test", items["env"])
+ assert.Equal(t, "debug", items["level"])
+ assert.NotEmpty(t, items["time"])
+ })
+
+ t.Run("WithFields", func(t *testing.T) {
+ var b bytes.Buffer
+ writer := bufio.NewWriter(&b)
+
+ log := New(writer, Fields{"env": "test"})
+ ctx := log.WithContext(context.Background())
+ WithFields(ctx, Fields{"ip": "127.0.0.1"})
+ zerolog.Ctx(ctx).Print()
+ log.Print()
+
+ require.NoError(t, writer.Flush())
+
+ items, err := serde.FromJSON[map[string]string](bufio.NewReader(&b))
+ require.NoError(t, err)
+
+ assert.Equal(t, "test", items["env"])
+ assert.Equal(t, "debug", items["level"])
+ assert.Equal(t, "127.0.0.1", items["ip"])
+ })
+
+ t.Run("WithMiddleware", func(t *testing.T) {
+ var b bytes.Buffer
+ writer := bufio.NewWriter(&b)
+ log := New(writer, Fields{"env": "test"})
+
+ server := httptest.NewServer(Middleware(log)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusTeapot)
+ })))
+ defer server.Close()
+
+ response, err := http.Get(server.URL)
+ require.NoError(t, err)
+ assert.Equal(t, http.StatusTeapot, response.StatusCode)
+
+ require.NoError(t, writer.Flush())
+ items, err := serde.FromJSON[map[string]interface{}](bufio.NewReader(&b))
+ require.NoError(t, err)
+
+ fmt.Printf("%v\n", items)
+ assert.Equal(t, "test", items["env"])
+ assert.Equal(t, "debug", items["level"])
+ assert.NotEmpty(t, items["time"])
+ assert.Equal(t, float64(http.StatusTeapot), items["status"])
+ assert.Equal(t, "GET", items["method"])
+ assert.Equal(t, "/", items["path"])
+ assert.Contains(t, items["remote_host"], "127.0.0.1")
+ })
+}
pkg/log/middleware.go
@@ -0,0 +1,29 @@
+package log
+
+import (
+ "net/http"
+
+ "github.com/go-chi/chi/v5/middleware"
+ "github.com/rs/zerolog"
+)
+
+func Middleware(logger *zerolog.Logger) func(http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ctx := logger.WithContext(r.Context())
+ ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
+
+ defer func() {
+ WithFields(ctx, Fields{
+ "status": ww.Status(),
+ "method": r.Method,
+ "path": r.URL.Path,
+ "remote_host": r.RemoteAddr,
+ })
+ zerolog.Ctx(ctx).Print()
+ }()
+
+ next.ServeHTTP(ww, r.WithContext(ctx))
+ })
+ }
+}
go.mod
@@ -3,13 +3,18 @@ module github.com/xlgmokha/x
go 1.18
require (
+ github.com/go-chi/chi/v5 v5.2.1
github.com/google/jsonapi v1.0.0
- github.com/stretchr/testify v1.8.0
+ github.com/rs/zerolog v1.34.0
+ github.com/stretchr/testify v1.8.1
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ golang.org/x/sys v0.12.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
go.sum
@@ -1,15 +1,34 @@
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
+github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/jsonapi v1.0.0 h1:qIGgO5Smu3yJmSs+QlvhQnrscdZfFhiV6S8ryJAglqU=
github.com/google/jsonapi v1.0.0/go.mod h1:YYHiRPJT8ARXGER8In9VuLv4qvLfDmA9ULQqptbLE4s=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
+github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=