Skip to content

Commit d416f5e

Browse files
committed
Replace github.com/op/go-logging with go.uber.org/zap
go-logging is unmaintained since 2016 and has significant reentrancy problems causing crashes. See for example: op/go-logging#75 op/go-logging#102 op/go-logging#105 To fix this we introduce a wrapper for a subset of the go-logging library mapped on to Uber's zap logging library and switch to using that.
1 parent 9e5daf8 commit d416f5e

File tree

24 files changed

+344
-28
lines changed

24 files changed

+344
-28
lines changed

aeron/aeron.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import (
2020
"github.com/lirm/aeron-go/aeron/broadcast"
2121
"github.com/lirm/aeron-go/aeron/counters"
2222
"github.com/lirm/aeron-go/aeron/driver"
23+
"github.com/lirm/aeron-go/aeron/logging"
2324
rb "github.com/lirm/aeron-go/aeron/ringbuffer"
2425
"github.com/lirm/aeron-go/aeron/util/memmap"
25-
logging "github.com/op/go-logging"
2626
)
2727

2828
// NewPublicationHandler is the handler type for new publication notification from the media driver

aeron/clientconductor.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
"github.com/lirm/aeron-go/aeron/driver"
3131
"github.com/lirm/aeron-go/aeron/idlestrategy"
3232
"github.com/lirm/aeron-go/aeron/logbuffer"
33-
logging "github.com/op/go-logging"
33+
"github.com/lirm/aeron-go/aeron/logging"
3434
)
3535

3636
var RegistrationStatus = struct {

aeron/counters/counters.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"errors"
2121
"fmt"
2222

23-
logging "github.com/op/go-logging"
23+
"github.com/lirm/aeron-go/aeron/logging"
2424

2525
"github.com/lirm/aeron-go/aeron/atomic"
2626
"github.com/lirm/aeron-go/aeron/flyweight"

aeron/driver/listeneradapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
package driver
1818

1919
import (
20-
logging "github.com/op/go-logging"
20+
"github.com/lirm/aeron-go/aeron/logging"
2121

2222
"github.com/lirm/aeron-go/aeron/atomic"
2323
"github.com/lirm/aeron-go/aeron/broadcast"

aeron/logbuffer/logbuffers.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ package logbuffer
1818

1919
import (
2020
"github.com/lirm/aeron-go/aeron/atomic"
21+
"github.com/lirm/aeron-go/aeron/logging"
2122
"github.com/lirm/aeron-go/aeron/util/memmap"
22-
"github.com/op/go-logging"
2323
"unsafe"
2424
)
2525

aeron/logbuffer/logbuffers_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ package logbuffer
1919
import (
2020
"fmt"
2121
"github.com/lirm/aeron-go/aeron/atomic"
22+
"github.com/lirm/aeron-go/aeron/logging"
2223
"github.com/lirm/aeron-go/aeron/util"
2324
"github.com/lirm/aeron-go/aeron/util/memmap"
24-
"github.com/op/go-logging"
2525
"testing"
2626
"unsafe"
2727
)

aeron/logging/logging.go

+232
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// Copyright (C) 2021 Talos, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Provides a transition layer from "github.com/op/go-logging" to
16+
// "go.uber.org/zap" to simply resolve some reentrancy issues in go-logging.
17+
//
18+
// This provides a largely api compatible layer so we can quickly
19+
// drop in a replacement.
20+
package logging
21+
22+
import (
23+
"go.uber.org/zap"
24+
"go.uber.org/zap/zapcore"
25+
"sync"
26+
)
27+
28+
// Zaplogger is a container to wrap zap logging with the parts of the go-logging API we use
29+
type ZapLogger struct {
30+
name string
31+
sugar *zap.SugaredLogger
32+
logger *zap.Logger
33+
config zap.Config
34+
}
35+
36+
// Mapping of go-logging to zap log levels. It's imperfect but good enough
37+
const (
38+
DEBUG = zapcore.DebugLevel
39+
INFO = zapcore.InfoLevel
40+
WARNING = zapcore.WarnLevel
41+
NOTICE = zapcore.InfoLevel // Map to info
42+
ERROR = zapcore.ErrorLevel
43+
CRITICAL = zapcore.DPanicLevel
44+
)
45+
46+
// The go-logging package creates named loggers and allows them to be
47+
// accessed by name This is used in aeron to allow parent code to set
48+
// the logging level of library components so we need to provide a
49+
// mechanism for that
50+
var namedLoggers sync.Map // [string]*ZapLogger
51+
52+
// MustGetLogger returns a new logger or panic()s
53+
func MustGetLogger(name string) *ZapLogger {
54+
z := new(ZapLogger)
55+
z.name = name
56+
57+
z.config = aeronLoggingConfig()
58+
logger, err := z.config.Build()
59+
if err != nil {
60+
panic("Failed to make logger")
61+
}
62+
z.logger = logger.Named(name)
63+
z.sugar = z.logger.Sugar()
64+
65+
// Keep a reference
66+
namedLoggers.Store(name, z)
67+
68+
return z
69+
}
70+
71+
// newAeronEncoderConfig returns a default opinionated EncoderConfig for aeron
72+
func newAeronEncoderConfig() zapcore.EncoderConfig {
73+
return zapcore.EncoderConfig{
74+
TimeKey: "ts",
75+
LevelKey: "level",
76+
NameKey: "logger",
77+
CallerKey: "caller",
78+
FunctionKey: zapcore.OmitKey,
79+
MessageKey: "msg",
80+
StacktraceKey: "stacktrace",
81+
LineEnding: zapcore.DefaultLineEnding,
82+
EncodeLevel: zapcore.LowercaseLevelEncoder,
83+
EncodeTime: zapcore.ISO8601TimeEncoder,
84+
EncodeDuration: zapcore.SecondsDurationEncoder,
85+
EncodeCaller: zapcore.ShortCallerEncoder,
86+
}
87+
}
88+
89+
// Default config
90+
func aeronLoggingConfig() zap.Config {
91+
return zap.Config{
92+
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
93+
Development: false,
94+
Sampling: &zap.SamplingConfig{
95+
Initial: 100,
96+
Thereafter: 100,
97+
},
98+
Encoding: "console",
99+
EncoderConfig: newAeronEncoderConfig(),
100+
OutputPaths: []string{"stderr"},
101+
ErrorOutputPaths: []string{"stderr"},
102+
}
103+
}
104+
105+
// SetConfigAndRebuild so you can replace the default config
106+
func (z *ZapLogger) SetConfigAndRebuild(c zap.Config) error {
107+
z.config = c
108+
logger, err := z.config.Build()
109+
if err != nil {
110+
return err
111+
}
112+
113+
z.logger = logger.Named(z.name)
114+
z.sugar = z.logger.Sugar()
115+
return nil
116+
}
117+
118+
// SetLevel on a named logger
119+
func SetLevel(l zapcore.Level, name string) {
120+
z, ok := namedLoggers.Load(name)
121+
if ok {
122+
zlogger := z.(*ZapLogger)
123+
zlogger.SetLevel(l)
124+
}
125+
}
126+
127+
// GetLevel on a named logger
128+
func GetLevel(name string) zapcore.Level {
129+
z, ok := namedLoggers.Load(name)
130+
if ok {
131+
zlogger := z.(*ZapLogger)
132+
return zlogger.GetLevel()
133+
}
134+
135+
// Bogus return but that's the API we are emulating and shouldn't happen
136+
return zapcore.InfoLevel
137+
}
138+
139+
// Sugar returns the internal Sugared logger
140+
func (z *ZapLogger) Sugar() *zap.SugaredLogger {
141+
return z.sugar
142+
}
143+
144+
// SetSugar sets our internal Sugared logger
145+
func (z *ZapLogger) SetSugar(s *zap.SugaredLogger) {
146+
z.sugar = s
147+
}
148+
149+
// Logger returns the internal zap logger
150+
func (z *ZapLogger) Logger() *zap.Logger {
151+
return z.logger
152+
}
153+
154+
// SetLogger sets the internal zap logger
155+
func (z *ZapLogger) SetLogger(l *zap.Logger) {
156+
z.logger = l
157+
}
158+
159+
// SetLevel sets the log level at which we will log
160+
func (z *ZapLogger) SetLevel(l zapcore.Level) {
161+
z.config.Level.SetLevel(l)
162+
}
163+
164+
// GetLevel returns the log level at which we will log
165+
func (z *ZapLogger) GetLevel() zapcore.Level {
166+
return z.config.Level.Level()
167+
}
168+
169+
// IsEnabledFor returns true if logging is enabled for the specified level
170+
func (z *ZapLogger) IsEnabledFor(level zapcore.Level) bool {
171+
return level <= z.GetLevel()
172+
}
173+
174+
// Fatalf logs a formatted string at log level Fatal and will then always exit()
175+
func (z *ZapLogger) Fatalf(template string, args ...interface{}) {
176+
z.sugar.Fatalf(template, args)
177+
}
178+
179+
// Errorf logs a formatted string at log level Error
180+
func (z *ZapLogger) Errorf(template string, args ...interface{}) {
181+
z.sugar.Errorf(template, args)
182+
}
183+
184+
// Warningf logs a formatted string at log level Warning
185+
func (z *ZapLogger) Warningf(template string, args ...interface{}) {
186+
z.sugar.Warnf(template, args)
187+
}
188+
189+
// Infof logs a formatted string at log level Info
190+
func (z *ZapLogger) Infof(template string, args ...interface{}) {
191+
z.sugar.Infof(template, args)
192+
}
193+
194+
// Noticef logs a formatted string at log level *Info*
195+
func (z *ZapLogger) Noticef(template string, args ...interface{}) {
196+
z.sugar.Infof(template, args)
197+
}
198+
199+
// Debugf logs a formatted string at log level Debug
200+
func (z *ZapLogger) Debugf(template string, args ...interface{}) {
201+
z.sugar.Debugf(template, args)
202+
}
203+
204+
// Fatal logs it's arguments at log level Fatal
205+
func (z *ZapLogger) Fatal(args ...interface{}) {
206+
z.sugar.Fatal(args)
207+
}
208+
209+
// Error logs it's arguments at log level Error
210+
func (z *ZapLogger) Error(args ...interface{}) {
211+
z.sugar.Error(args)
212+
}
213+
214+
// Warning logs it's arguments at log level Warning
215+
func (z *ZapLogger) Warning(args ...interface{}) {
216+
z.sugar.Warn(args)
217+
}
218+
219+
// Info logs it's arguments at log level Info
220+
func (z *ZapLogger) Info(args ...interface{}) {
221+
z.sugar.Info(args)
222+
}
223+
224+
// Notice logs it's arguments at log level *Info*
225+
func (z *ZapLogger) Notice(args ...interface{}) {
226+
z.sugar.Info(args)
227+
}
228+
229+
// Debug logs it's arguments at log level Debug
230+
func (z *ZapLogger) Debug(args ...interface{}) {
231+
z.sugar.Debug(args)
232+
}

aeron/logging/logging_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package logging
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"testing"
6+
)
7+
8+
const (
9+
logname = "logtest"
10+
)
11+
12+
func TestLogLevels(t *testing.T) {
13+
assert := assert.New(t)
14+
logger := MustGetLogger(logname)
15+
16+
// We initialzie to INFO
17+
assert.EqualValues(INFO, GetLevel("logtest"))
18+
assert.EqualValues(INFO, logger.GetLevel())
19+
20+
// Set to Warning (via name)
21+
SetLevel(WARNING, logname)
22+
assert.EqualValues(WARNING, GetLevel("logtest"))
23+
assert.EqualValues(WARNING, logger.GetLevel())
24+
25+
// Set to Info (via logger)
26+
logger.SetLevel(INFO)
27+
assert.EqualValues(INFO, GetLevel("logtest"))
28+
assert.EqualValues(INFO, logger.GetLevel())
29+
30+
// logger.Fatal("Log at Fatal")
31+
logger.Error("Log at Error")
32+
logger.Warning("Log at Warning")
33+
logger.Info("Log at Info")
34+
logger.Debug("Log at Debug") // Silent
35+
36+
}

aeron/publication.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import (
2222
"github.com/lirm/aeron-go/aeron/atomic"
2323
"github.com/lirm/aeron-go/aeron/logbuffer"
2424
"github.com/lirm/aeron-go/aeron/logbuffer/term"
25+
"github.com/lirm/aeron-go/aeron/logging"
2526
"github.com/lirm/aeron-go/aeron/util"
26-
logging "github.com/op/go-logging"
2727
)
2828

2929
const (

aeron/publication_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ package aeron
1818

1919
import (
2020
"github.com/lirm/aeron-go/aeron/atomic"
21-
"github.com/lirm/aeron-go/aeron/util"
2221
"github.com/lirm/aeron-go/aeron/counters"
2322
"github.com/lirm/aeron-go/aeron/driver"
2423
"github.com/lirm/aeron-go/aeron/logbuffer"
24+
"github.com/lirm/aeron-go/aeron/logging"
2525
"github.com/lirm/aeron-go/aeron/ringbuffer"
26+
"github.com/lirm/aeron-go/aeron/util"
2627
"github.com/lirm/aeron-go/aeron/util/memmap"
27-
"github.com/op/go-logging"
2828
"os"
2929
"testing"
3030
"time"

aeron/util/memmap/memmap.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
"unsafe"
2525

2626
mapper "github.com/edsrzf/mmap-go"
27-
"github.com/op/go-logging"
27+
"github.com/lirm/aeron-go/aeron/logging"
2828
)
2929

3030
// File is the wrapper around memory mapped file

archive/archive.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
"fmt"
2121
"github.com/lirm/aeron-go/aeron"
2222
"github.com/lirm/aeron-go/aeron/atomic"
23+
"github.com/lirm/aeron-go/aeron/logging"
2324
"github.com/lirm/aeron-go/archive/codecs"
24-
logging "github.com/op/go-logging"
2525
"sync"
2626
"time"
2727
)

archive/archive_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"flag"
1919
"github.com/lirm/aeron-go/aeron"
2020
"github.com/lirm/aeron-go/aeron/idlestrategy"
21-
logging "github.com/op/go-logging"
21+
"github.com/lirm/aeron-go/aeron/logging"
2222
"log"
2323
"math/rand"
2424
"os"

archive/examples/basic_recording_publisher/basic_recording_publisher.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
"github.com/lirm/aeron-go/aeron"
2222
"github.com/lirm/aeron-go/aeron/atomic"
2323
"github.com/lirm/aeron-go/aeron/idlestrategy"
24+
"github.com/lirm/aeron-go/aeron/logging"
2425
"github.com/lirm/aeron-go/archive"
2526
"github.com/lirm/aeron-go/archive/examples"
26-
logging "github.com/op/go-logging"
2727
"os"
2828
"time"
2929
)

0 commit comments

Comments
 (0)