Skip to content

Commit

Permalink
Add bool64/ctxd adapter (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop authored Jan 29, 2021
1 parent b0a6382 commit a951a0a
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x]
go-version: [1.13.x, 1.14.x, 1.15.x]
runs-on: ubuntu-latest
steps:
- name: Install Go
Expand Down
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ issues:
- linters:
- gomnd
- goconst
- noctx
path: "_test.go"
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ They are useful for last mile observability of logs.

* High performance and low resource consumption.
* Adapter for [`go.uber.org/zap`](./zzap).
* Adapter for [`github.com/bool64/ctxd`](./ctxz).
* HTTP handler to serve aggregated messages.

![Screenshot](./_examples/screenshot.png)

## Example
## Example for `go.uber.org/zap`

```go
zc := zap.NewDevelopmentConfig()
Expand All @@ -46,3 +47,30 @@ if err != nil {
l.Fatal(err.Error())
}
```

## Example for `github.com/bool64/ctxd`

```go
var logger ctxd.Logger

lz := ctxz.NewObserver(logger, logz.Config{
MaxCardinality: 100,
MaxSamples: 50,
DistRetentionPeriod: 72 * time.Hour,
})
logger = lz

ctx := context.TODO()

logger.Debug(ctx, "starting example")
logger.Info(ctx, "sample info", "one", 1, "two", 2)
logger.Error(ctx, "unexpected end of the world")

logger.Important(ctx, "starting server at http://localhost:6060/")

err := http.ListenAndServe("0.0.0.0:6060", logzpage.Handler(lz.LevelObservers()...))
if err != nil {
logger.Error(ctx, err.Error())
os.Exit(1)
}
```
38 changes: 38 additions & 0 deletions ctxz/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ctxz_test

import (
"context"
"net/http"
"os"
"time"

"github.com/bool64/ctxd"
"github.com/bool64/logz"
"github.com/bool64/logz/ctxz"
"github.com/bool64/logz/logzpage"
)

func ExampleNewObserver() {
var logger ctxd.Logger

lz := ctxz.NewObserver(logger, logz.Config{
MaxCardinality: 100,
MaxSamples: 50,
DistRetentionPeriod: 72 * time.Hour,
})
logger = lz

ctx := context.TODO()

logger.Debug(ctx, "starting example")
logger.Info(ctx, "sample info", "one", 1, "two", 2)
logger.Error(ctx, "unexpected end of the world")

logger.Important(ctx, "starting server at http://localhost:6060/")

err := http.ListenAndServe("0.0.0.0:6060", logzpage.Handler(lz.LevelObservers()...))
if err != nil {
logger.Error(ctx, err.Error())
os.Exit(1)
}
}
123 changes: 123 additions & 0 deletions ctxz/observer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Package ctxz implements wrapper to report aggregated messages for github.com/bool64/ctxd.Logger.
package ctxz

import (
"context"
"encoding/json"

"github.com/bool64/ctxd"
"github.com/bool64/logz"
)

// Observer keeps track of logged messages.
type Observer struct {
debug *logz.Observer
info *logz.Observer
important *logz.Observer
warn *logz.Observer
error *logz.Observer
logger ctxd.Logger
}

type tuples struct {
ctx context.Context
kv []interface{}
}

func (t tuples) MarshalJSON() ([]byte, error) {
kv := t.kv[0:len(t.kv):len(t.kv)]

ctxFields := ctxd.Fields(t.ctx)
if len(ctxFields) > 0 {
kv = append(kv, ctxFields...)
}

m := make(map[string]interface{}, len(kv))

var (
label string
ok bool
)

for i, l := range kv {
if label == "" {
label, ok = l.(string)
if !ok {
m["malformedFields"] = kv[i:]

break
}
} else {
m[label] = l
label = ""
}
}

return json.Marshal(m)
}

// Debug logs debug message.
func (o Observer) Debug(ctx context.Context, msg string, keysAndValues ...interface{}) {
o.debug.ObserveMessage(msg, tuples{ctx: ctx, kv: keysAndValues})
o.logger.Debug(ctx, msg, keysAndValues...)
}

// Info logs informational message.
func (o Observer) Info(ctx context.Context, msg string, keysAndValues ...interface{}) {
o.info.ObserveMessage(msg, tuples{ctx: ctx, kv: keysAndValues})
o.logger.Info(ctx, msg, keysAndValues...)
}

// Important logs important information.
func (o Observer) Important(ctx context.Context, msg string, keysAndValues ...interface{}) {
o.important.ObserveMessage(msg, tuples{ctx: ctx, kv: keysAndValues})
o.logger.Important(ctx, msg, keysAndValues...)
}

// Warn logs a warning.
func (o Observer) Warn(ctx context.Context, msg string, keysAndValues ...interface{}) {
o.warn.ObserveMessage(msg, tuples{ctx: ctx, kv: keysAndValues})
o.logger.Warn(ctx, msg, keysAndValues...)
}

// Error logs an error.
func (o Observer) Error(ctx context.Context, msg string, keysAndValues ...interface{}) {
o.error.ObserveMessage(msg, tuples{ctx: ctx, kv: keysAndValues})
o.logger.Error(ctx, msg, keysAndValues...)
}

// LevelObservers returns .
func (o Observer) LevelObservers() []*logz.Observer {
return []*logz.Observer{o.debug, o.info, o.important, o.warn, o.error}
}

// CtxdLogger is a service provider.
func (o Observer) CtxdLogger() ctxd.Logger {
return o
}

// NewObserver initializes Observer instance.
func NewObserver(logger ctxd.Logger, conf ...logz.Config) Observer {
o := Observer{
logger: logger,
}

cfg := logz.Config{}

if len(conf) == 1 {
cfg = conf[0]
}

cfg.Name = "Debug"
o.debug = &logz.Observer{Config: cfg}
cfg.Name = "Info"
o.info = &logz.Observer{Config: cfg}
cfg.Name = "Important"
o.important = &logz.Observer{Config: cfg}
cfg.Name = "Warning"
o.warn = &logz.Observer{Config: cfg}
cfg.Name = "Error"
o.error = &logz.Observer{Config: cfg}

return o
}
41 changes: 41 additions & 0 deletions ctxz/observer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ctxz_test

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/bool64/ctxd"
"github.com/bool64/logz/ctxz"
"github.com/bool64/logz/logzpage"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewObserver(t *testing.T) {
logger := ctxd.NoOpLogger{}
o := ctxz.NewObserver(logger)

assert.Equal(t, o, o.CtxdLogger())

ctx := ctxd.AddFields(context.Background(), "shared", 123)

o.Debug(ctx, "debug", "foo", "bar")
o.Info(ctx, "info", "foo", "bar")
o.Important(ctx, "important", "foo", "bar")
o.Warn(ctx, "warn", "foo", "bar")
o.Error(ctx, "error", "foo", "bar")

req, err := http.NewRequest(http.MethodGet, "/debug/logz?level=Info&msg=info", nil)
require.NoError(t, err)

rw := httptest.NewRecorder()

logzpage.Handler(o.LevelObservers()...).ServeHTTP(rw, req)

assert.Contains(t, rw.Body.String(), `{
"foo": "bar",
"shared": 123
}`)
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ module github.com/bool64/logz
go 1.13

require (
github.com/bool64/ctxd v0.1.3
github.com/bool64/dev v0.1.13
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.6.1
github.com/vearutop/dynhist-go v1.0.0
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0
Expand Down
11 changes: 10 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/bool64/ctxd v0.1.3 h1:n+aQ6UdoZXlltETFXqIhZR2DoMxhMYE2CW9BQn8aNBY=
github.com/bool64/ctxd v0.1.3/go.mod h1:rhUkoNE4mKFSJmo9l+78u2j+FVQifRCj0MHRhyZ2GDA=
github.com/bool64/dev v0.1.0/go.mod h1:pn52JC52uSgpazChx9CeXyG+S3sW2V36HHoLNBbscdg=
github.com/bool64/dev v0.1.10/go.mod h1:pn52JC52uSgpazChx9CeXyG+S3sW2V36HHoLNBbscdg=
github.com/bool64/dev v0.1.13 h1:edfquat4DBM1FBVMtm+z4Ksf1Du/S+qiAjslmE3xdIM=
github.com/bool64/dev v0.1.13/go.mod h1:pn52JC52uSgpazChx9CeXyG+S3sW2V36HHoLNBbscdg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -19,8 +23,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/swaggest/usecase v0.0.0-20200928062416-27f47131b0f8 h1:XGJJai6ngqYpy/cTMvGreiO+jradIn1uq7Q5hY2OCF4=
github.com/swaggest/usecase v0.0.0-20200928062416-27f47131b0f8/go.mod h1:rcngDv7OaBXZyEXdEtimcDeNon7sq3iqLm9hxT06s3c=
github.com/vearutop/dynhist-go v1.0.0 h1:SLYGcQMzmIoWnuqtF9lV8ULUBC735A56M5nL2CNth4c=
github.com/vearutop/dynhist-go v1.0.0/go.mod h1:7Cgyu5Ww8FwdB+Y+zawRz9cQT5oXAxw294L9lQ+JI/k=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
Expand Down Expand Up @@ -58,5 +65,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

0 comments on commit a951a0a

Please sign in to comment.