Skip to content

Commit

Permalink
zax package
Browse files Browse the repository at this point in the history
  • Loading branch information
yuseferi committed Jun 8, 2023
1 parent 5e921a8 commit 806c202
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @yuseferi
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Check & Build
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
qa:
name: Quality check
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v4
- name: Linter
uses: golangci/golangci-lint-action@v3
with:
version: v1.53.2
- name: Tests
run: go mod download; go test -race ./...
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
- name: Build
run: go mod download; go build -v ./...
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@

# Go workspace file
go.work
.vs/
.idea/
63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,61 @@
# zax
Zap logger with context
# Zax (zap with context)

Basically this adds context to [Zap Logger](https://github.com/uber-go/zap), and make it easier to for the Gophers to do not generate logger boiler plates.
Passing logger as a parameter to function increase parameters functionalities and worse than couple lots of methods with a explicit dependency.


### Installation

```shell
go get -u github.com/yuseferi/zax
```

### Usage:
when you add something to context and would like to carry with context , you just need to add it to context with calling `zap.Set`

ctx = zax.Set(ctx, logger, []zap.Field{zap.String("trace_id", "my-trace-id")})

and when you want to log context fields, just use

zax.Get(ctx)



##### example:
you want to generate a tracer on entry point of your system and want to keep it until the process finished.

```Go
func main() {
logger, _ := zap.NewProduction()
ctx := context.Background()
s := NewServiceA(logger)
ctx = zax.Set(ctx, logger, []zap.Field{zap.String("trace_id", "my-trace-id")})
s.funcA(ctx)
}

type ServiceA struct {
logger *zap.Logger
}

func NewServiceA(logger *zap.Logger) *ServiceA {
return &ServiceA{
logger: logger,
}
}

func (s *ServiceA) funcA(ctx context.Context) {
s.logger.Info("func A") // it does not contain trace_id, you need to add it manually
zax.Get(ctx).Info("func A") // it will logged with "trace_id" = "my-trace-id"
}

```

### Contributing
I strongly believe in open-source :), feel free to make it better with raising issues and PRs.


Released under the [GNU GENERAL PUBLIC LICENSE](LICENSE).




16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module zax

go 1.20

require (
github.com/stretchr/testify v1.8.0
go.uber.org/zap v1.24.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
25 changes: 25 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
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/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
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/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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
29 changes: 29 additions & 0 deletions zax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Package zax provides contextual field logging around the uber-zap logger.

package zax

import (
"context"
"go.uber.org/zap"
)

type Key string

// Key name which used for save logger in context
const loggerKey = Key("zax")

// Set Add passed fields to logger and store zap.Logger as variable in context
func Set(ctx context.Context, logger *zap.Logger, fields []zap.Field) context.Context {
if len(fields) > 0 {
logger = logger.With(fields...)
}
return context.WithValue(ctx, loggerKey, logger)
}

// Get zap.Logger from context
func Get(ctx context.Context) *zap.Logger {
if logger, ok := ctx.Value(loggerKey).(*zap.Logger); ok {
return logger
}
return zap.L()
}
123 changes: 123 additions & 0 deletions zax_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package zax

import (
"context"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest/observer"
)

type Logger struct {
logger *zap.Logger
recorded *observer.ObservedLogs
t *testing.T
}

func NewLogger(t *testing.T) *Logger {
core, recorded := observer.New(zapcore.DebugLevel)
logger := &Logger{
logger: zap.New(core),
recorded: recorded,
t: t,
}
return logger
}

func (l *Logger) GetZapLogger() *zap.Logger {
return l.logger
}

func (l *Logger) GetRecordedLogs() []observer.LoggedEntry {
return l.recorded.All()
}

func (l *Logger) AssertLogEntryExist(t assert.TestingT, key, value string) bool {
for _, log := range l.recorded.All() {
for _, r := range log.Context {
if r.Key == key && r.String == value {
return true
}
}
}
return assert.Fail(t, fmt.Sprintf("log entry does not exist with, %s = %s", key, value))
}

func (l *Logger) AssertLogEntryKeyExist(t assert.TestingT, key string) bool {
for _, log := range l.recorded.All() {
for _, r := range log.Context {
if r.Key == key {
return true
}
}
}
return assert.Fail(t, fmt.Sprintf("log entry does not exist with key = %s ", key))
}

const traceIDKey = "trace_id"

func TestSet(t *testing.T) {
testLog := NewLogger(t)
testTraceID := "test-trace-id-3333"
testTraceID2 := "test-trace-id-new"
ctx := context.Background()
tests := map[string]struct {
context context.Context
expectedLoggerKey string
expectedLoggerValue string
}{
"context with trace-id": {
context: Set(ctx, testLog.logger, []zap.Field{zap.String(traceIDKey, testTraceID)}),
expectedLoggerKey: traceIDKey,
expectedLoggerValue: testTraceID,
},
"context with trace-id with new value(to check it will be updated)": {
context: Set(ctx, testLog.logger, []zap.Field{zap.String(traceIDKey, testTraceID2)}),
expectedLoggerKey: traceIDKey,
expectedLoggerValue: testTraceID2,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
ctx := tc.context
logger := ctx.Value(loggerKey).(*zap.Logger)
logger.Info("just a test record")
assert.NotNil(t, logger)
testLog.AssertLogEntryExist(t, tc.expectedLoggerKey, tc.expectedLoggerValue)
})
}
}

func TestGet(t *testing.T) {
testLog := NewLogger(t)
testTraceID := "test-trace-id-3333"
traceIDKey := traceIDKey
ctx := context.Background()
tests := map[string]struct {
context context.Context
expectedLoggerKey *string
}{
"context with trace-id": {
context: context.TODO(),
expectedLoggerKey: nil,
},
"context with trace-id with new value(to check it will be updated)": {
context: Set(ctx, testLog.logger, []zap.Field{zap.String(traceIDKey, testTraceID)}),
expectedLoggerKey: &traceIDKey,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
ctx := tc.context
Get(ctx).Info("just a test record")
if tc.expectedLoggerKey != nil {
testLog.AssertLogEntryKeyExist(t, *tc.expectedLoggerKey)
}
})
}
}

0 comments on commit 806c202

Please sign in to comment.