Skip to content

Commit cea6e1a

Browse files
authored
Merge pull request #233 from go-faster/feat/zapencoder
feat(zapencoder): init
2 parents 56872a5 + afdb188 commit cea6e1a

File tree

16 files changed

+2267
-1
lines changed

16 files changed

+2267
-1
lines changed

.golangci.yml

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
version: "2"
2+
linters:
3+
default: none
4+
enable:
5+
- dogsled
6+
- errcheck
7+
- goconst
8+
- gocritic
9+
- gosec
10+
- govet
11+
- ineffassign
12+
- misspell
13+
- nakedret
14+
- revive
15+
- staticcheck
16+
- unconvert
17+
- unparam
18+
- whitespace
19+
- errcheck
20+
settings:
21+
dupl:
22+
threshold: 120
23+
goconst:
24+
min-len: 2
25+
min-occurrences: 3
26+
gocritic:
27+
disabled-checks:
28+
- hugeParam
29+
- rangeValCopy
30+
- exitAfterDefer
31+
- whyNoLint
32+
- singleCaseSwitch
33+
- commentedOutCode
34+
- appendAssign
35+
- unnecessaryBlock
36+
- redundantSprint
37+
- octalLiteral
38+
enabled-tags:
39+
- diagnostic
40+
- experimental
41+
- opinionated
42+
- performance
43+
- style
44+
gocyclo:
45+
min-complexity: 15
46+
lll:
47+
line-length: 140
48+
misspell:
49+
locale: US
50+
revive:
51+
rules:
52+
- name: unused-parameter
53+
disabled: true
54+
exclusions:
55+
paths-except:
56+
- internal/otel-iface-gen
57+
generated: lax
58+
rules:
59+
- linters:
60+
- dupl
61+
- errcheck
62+
- funlen
63+
- gocognit
64+
- goconst
65+
- gocyclo
66+
- gosec
67+
- lll
68+
- scopelint
69+
path: _test\.go
70+
- linters:
71+
- gocritic
72+
path: _test\.go
73+
text: Combine
74+
- linters:
75+
- gocritic
76+
path: _test\.go
77+
text: dupArg
78+
source: (assert|require).+Equal
79+
- linters:
80+
- govet
81+
text: declaration of "(err|ctx|log|lg|c)"
82+
- linters:
83+
- revive
84+
text: 'receiver-naming: receiver name \S+ should be consistent with previous receiver name \S+ for invalid-type'
85+
- linters:
86+
- funlen
87+
- gocognit
88+
- goconst
89+
- gocyclo
90+
path: main\.go
91+
- linters:
92+
- gosec
93+
path: main\.go
94+
text: G307
95+
- linters:
96+
- staticcheck
97+
text: ST1003
98+
source: func Fuzz.+\(f \*testing\.F\)
99+
- linters:
100+
- revive
101+
path: (internal|cmd)
102+
text: package-comments
103+
- linters:
104+
- gosec
105+
path: (install)
106+
text: G204
107+
- linters:
108+
- gosec
109+
text: G115
110+
- linters:
111+
- revive
112+
text: comment on exported const .+ should be of the form
113+
- linters:
114+
- gocritic
115+
text: "importShadow: shadow of imported from 'github.com/stretchr/testify/suite' package 'suite'"
116+
paths:
117+
- third_party$
118+
- builtin$
119+
- examples$
120+
formatters:
121+
enable:
122+
- gofmt
123+
- goimports
124+
settings:
125+
goimports:
126+
local-prefixes:
127+
- github.com/go-faster/sdk
128+
exclusions:
129+
generated: lax
130+
paths:
131+
- third_party$
132+
- builtin$
133+
- examples$

app/app.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import (
99
"os"
1010
"os/signal"
1111
"strconv"
12+
"sync"
1213
"time"
1314

1415
"github.com/KimMachineGun/automemlimit/memlimit"
1516
"github.com/go-faster/errors"
17+
"github.com/go-faster/sdk/internal/zapencoder"
1618
slogzap "github.com/samber/slog-zap/v2"
1719
"go.opentelemetry.io/otel/sdk/resource"
1820
"go.uber.org/automaxprocs/maxprocs"
@@ -42,8 +44,17 @@ func Go(f func(ctx context.Context, t *Telemetry) error, op ...Option) {
4244
}, op...)
4345
}
4446

47+
var _registerZapEncoder sync.Once
48+
4549
func defaultZapConfig() zap.Config {
4650
cfg := zap.NewProductionConfig()
51+
const encoderName = "github.com/go-faster/sdk/zapencoder.JSON"
52+
_registerZapEncoder.Do(func() {
53+
_ = zap.RegisterEncoder(encoderName, func(config zapcore.EncoderConfig) (zapcore.Encoder, error) {
54+
return zapencoder.New(config), nil
55+
})
56+
})
57+
cfg.Encoding = encoderName
4758
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
4859
return cfg
4960
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ require (
3535
go.opentelemetry.io/otel/sdk/metric v1.38.0
3636
go.opentelemetry.io/otel/trace v1.38.0
3737
go.uber.org/automaxprocs v1.6.0
38+
go.uber.org/multierr v1.11.0
3839
go.uber.org/zap v1.27.0
3940
golang.org/x/sync v0.17.0
4041
google.golang.org/grpc v1.76.0
@@ -74,7 +75,6 @@ require (
7475
go.opentelemetry.io/contrib/propagators/ot v1.38.0 // indirect
7576
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
7677
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
77-
go.uber.org/multierr v1.11.0 // indirect
7878
go.yaml.in/yaml/v2 v2.4.2 // indirect
7979
golang.org/x/net v0.43.0 // indirect
8080
golang.org/x/sys v0.35.0 // indirect

internal/bufferpool/bufferpool.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2016 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
// Package bufferpool houses zap's shared internal buffer pool. Third-party
22+
// packages can recreate the same functionality with buffers.NewPool.
23+
package bufferpool
24+
25+
import "go.uber.org/zap/buffer"
26+
27+
var (
28+
_pool = buffer.NewPool()
29+
// Get retrieves a buffer from the pool, creating one if necessary.
30+
Get = _pool.Get
31+
)

internal/pool/pool.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) 2023 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
// Package pool provides internal pool utilities.
22+
package pool
23+
24+
import (
25+
"sync"
26+
)
27+
28+
// A Pool is a generic wrapper around [sync.Pool] to provide strongly-typed
29+
// object pooling.
30+
//
31+
// Note that SA6002 (ref: https://staticcheck.io/docs/checks/#SA6002) will
32+
// not be detected, so all internal pool use must take care to only store
33+
// pointer types.
34+
type Pool[T any] struct {
35+
pool sync.Pool
36+
}
37+
38+
// New returns a new [Pool] for T, and will use fn to construct new Ts when
39+
// the pool is empty.
40+
func New[T any](fn func() T) *Pool[T] {
41+
return &Pool[T]{
42+
pool: sync.Pool{
43+
New: func() any {
44+
return fn()
45+
},
46+
},
47+
}
48+
}
49+
50+
// Get gets a T from the pool, or creates a new one if the pool is empty.
51+
func (p *Pool[T]) Get() T {
52+
return p.pool.Get().(T)
53+
}
54+
55+
// Put returns x into the pool.
56+
func (p *Pool[T]) Put(x T) {
57+
p.pool.Put(x)
58+
}

internal/pool/pool_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (c) 2023 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package pool_test
22+
23+
import (
24+
"runtime/debug"
25+
"sync"
26+
"testing"
27+
28+
"github.com/go-faster/sdk/internal/pool"
29+
"github.com/stretchr/testify/require"
30+
)
31+
32+
type pooledValue[T any] struct {
33+
value T
34+
}
35+
36+
func TestNew(t *testing.T) {
37+
// Disable GC to avoid the victim cache during the test.
38+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
39+
40+
p := pool.New(func() *pooledValue[string] {
41+
return &pooledValue[string]{
42+
value: "new",
43+
}
44+
})
45+
46+
// Probabilistically, 75% of sync.Pool.Put calls will succeed when -race
47+
// is enabled (see ref below); attempt to make this quasi-deterministic by
48+
// brute force (i.e., put significantly more objects in the pool than we
49+
// will need for the test) in order to avoid testing without race enabled.
50+
//
51+
// ref: https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/sync/pool.go;l=100-103
52+
for i := 0; i < 1_000; i++ {
53+
p.Put(&pooledValue[string]{
54+
value: t.Name(),
55+
})
56+
}
57+
58+
// Ensure that we always get the expected value. Note that this must only
59+
// run a fraction of the number of times that Put is called above.
60+
for i := 0; i < 10; i++ {
61+
func() {
62+
x := p.Get()
63+
defer p.Put(x)
64+
require.Equal(t, t.Name(), x.value)
65+
}()
66+
}
67+
68+
// Depool all objects that might be in the pool to ensure that it's empty.
69+
for i := 0; i < 1_000; i++ {
70+
p.Get()
71+
}
72+
73+
// Now that the pool is empty, it should use the value specified in the
74+
// underlying sync.Pool.New func.
75+
require.Equal(t, "new", p.Get().value)
76+
}
77+
78+
func TestNew_Race(t *testing.T) {
79+
p := pool.New(func() *pooledValue[int] {
80+
return &pooledValue[int]{
81+
value: -1,
82+
}
83+
})
84+
85+
var wg sync.WaitGroup
86+
defer wg.Wait()
87+
88+
// Run a number of goroutines that read and write pool object fields to
89+
// tease out races.
90+
for i := 0; i < 1_000; i++ {
91+
i := i
92+
93+
wg.Add(1)
94+
go func() {
95+
defer wg.Done()
96+
97+
x := p.Get()
98+
defer p.Put(x)
99+
100+
// Must both read and write the field.
101+
if n := x.value; n >= -1 {
102+
x.value = i
103+
}
104+
}()
105+
}
106+
}

internal/zapencoder/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# zapencoder
2+
3+
This package is partially vendored from `zapcore`
4+
Probably we can use `jx` here in the future.
5+
6+
Changed code is located in `patch.go` file.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"level":"info","ts":"2024-01-02T15:04:05Z","msg":"With context"}
2+
{"level":"info","ts":"2024-01-02T15:04:05Z","msg":"With span","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7"}

0 commit comments

Comments
 (0)