planetscale 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.yml +21 -0
- data/.licenses/go/github.com/planetscale/planetscale-go/planetscale.dep.yml +56 -3
- data/.licenses/go/github.com/planetscale/sql-proxy/proxy.dep.yml +205 -172
- data/.licenses/go/go.uber.org/zap.dep.yml +1 -1
- data/.licenses/go/go.uber.org/zap/buffer.dep.yml +1 -1
- data/.licenses/go/go.uber.org/zap/internal/bufferpool.dep.yml +1 -1
- data/.licenses/go/go.uber.org/zap/internal/color.dep.yml +1 -1
- data/.licenses/go/go.uber.org/zap/internal/exit.dep.yml +1 -1
- data/.licenses/go/go.uber.org/zap/zapcore.dep.yml +1 -1
- data/README.md +8 -7
- data/controller.go +23 -10
- data/go.mod +3 -3
- data/go.sum +22 -23
- data/lib/generators/planetscale/install_generator.rb +5 -5
- data/lib/planetscale.rb +12 -12
- data/lib/planetscale/version.rb +1 -1
- data/planetscale.gemspec +1 -1
- data/proxy/planetscale-darwin.so +0 -0
- data/proxy/planetscale-linux.so +0 -0
- data/vendor/github.com/planetscale/planetscale-go/LICENSE +202 -0
- data/vendor/github.com/planetscale/planetscale-go/planetscale/audit_logs.go +136 -0
- data/vendor/github.com/planetscale/planetscale-go/planetscale/branches.go +5 -3
- data/vendor/github.com/planetscale/planetscale-go/planetscale/certs.go +40 -16
- data/vendor/github.com/planetscale/planetscale-go/planetscale/client.go +13 -6
- data/vendor/github.com/planetscale/planetscale-go/planetscale/databases.go +2 -0
- data/vendor/github.com/planetscale/planetscale-go/planetscale/regions.go +52 -0
- data/vendor/github.com/planetscale/planetscale-go/planetscale/service_tokens.go +1 -1
- data/vendor/github.com/planetscale/sql-proxy/LICENSE +202 -0
- data/vendor/github.com/planetscale/sql-proxy/proxy/client.go +17 -8
- data/vendor/go.uber.org/zap/CHANGELOG.md +60 -0
- data/vendor/go.uber.org/zap/CONTRIBUTING.md +0 -6
- data/vendor/go.uber.org/zap/FAQ.md +8 -0
- data/vendor/go.uber.org/zap/Makefile +13 -3
- data/vendor/go.uber.org/zap/README.md +4 -4
- data/vendor/go.uber.org/zap/buffer/buffer.go +18 -0
- data/vendor/go.uber.org/zap/field.go +10 -0
- data/vendor/go.uber.org/zap/go.mod +7 -6
- data/vendor/go.uber.org/zap/go.sum +25 -27
- data/vendor/go.uber.org/zap/http_handler.go +75 -24
- data/vendor/go.uber.org/zap/logger.go +11 -7
- data/vendor/go.uber.org/zap/options.go +8 -0
- data/vendor/go.uber.org/zap/sugar.go +21 -10
- data/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go +188 -0
- data/vendor/go.uber.org/zap/zapcore/clock.go +50 -0
- data/vendor/go.uber.org/zap/zapcore/console_encoder.go +1 -1
- data/vendor/go.uber.org/zap/zapcore/entry.go +2 -2
- data/vendor/go.uber.org/zap/zapcore/error.go +18 -1
- data/vendor/go.uber.org/zap/zapcore/field.go +7 -1
- data/vendor/go.uber.org/zap/zapcore/write_syncer.go +1 -2
- data/vendor/modules.txt +3 -3
- metadata +11 -5
- data/vendor/go.uber.org/zap/.travis.yml +0 -23
@@ -26,7 +26,6 @@ import (
|
|
26
26
|
"os"
|
27
27
|
"runtime"
|
28
28
|
"strings"
|
29
|
-
"time"
|
30
29
|
|
31
30
|
"go.uber.org/zap/zapcore"
|
32
31
|
)
|
@@ -42,14 +41,17 @@ type Logger struct {
|
|
42
41
|
core zapcore.Core
|
43
42
|
|
44
43
|
development bool
|
44
|
+
addCaller bool
|
45
|
+
onFatal zapcore.CheckWriteAction // default is WriteThenFatal
|
46
|
+
|
45
47
|
name string
|
46
48
|
errorOutput zapcore.WriteSyncer
|
47
49
|
|
48
|
-
|
49
|
-
addStack zapcore.LevelEnabler
|
50
|
+
addStack zapcore.LevelEnabler
|
50
51
|
|
51
52
|
callerSkip int
|
52
|
-
|
53
|
+
|
54
|
+
clock zapcore.Clock
|
53
55
|
}
|
54
56
|
|
55
57
|
// New constructs a new Logger from the provided zapcore.Core and Options. If
|
@@ -70,6 +72,7 @@ func New(core zapcore.Core, options ...Option) *Logger {
|
|
70
72
|
core: core,
|
71
73
|
errorOutput: zapcore.Lock(os.Stderr),
|
72
74
|
addStack: zapcore.FatalLevel + 1,
|
75
|
+
clock: zapcore.DefaultClock,
|
73
76
|
}
|
74
77
|
return log.WithOptions(options...)
|
75
78
|
}
|
@@ -84,6 +87,7 @@ func NewNop() *Logger {
|
|
84
87
|
core: zapcore.NewNopCore(),
|
85
88
|
errorOutput: zapcore.AddSync(ioutil.Discard),
|
86
89
|
addStack: zapcore.FatalLevel + 1,
|
90
|
+
clock: zapcore.DefaultClock,
|
87
91
|
}
|
88
92
|
}
|
89
93
|
|
@@ -269,7 +273,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
|
|
269
273
|
// log message will actually be written somewhere.
|
270
274
|
ent := zapcore.Entry{
|
271
275
|
LoggerName: log.name,
|
272
|
-
Time:
|
276
|
+
Time: log.clock.Now(),
|
273
277
|
Level: lvl,
|
274
278
|
Message: msg,
|
275
279
|
}
|
@@ -306,7 +310,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
|
|
306
310
|
if log.addCaller {
|
307
311
|
frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset)
|
308
312
|
if !defined {
|
309
|
-
fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n",
|
313
|
+
fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", ent.Time.UTC())
|
310
314
|
log.errorOutput.Sync()
|
311
315
|
}
|
312
316
|
|
@@ -334,7 +338,7 @@ func getCallerFrame(skip int) (frame runtime.Frame, ok bool) {
|
|
334
338
|
const skipOffset = 2 // skip getCallerFrame and Callers
|
335
339
|
|
336
340
|
pc := make([]uintptr, 1)
|
337
|
-
numFrames := runtime.Callers(skip+skipOffset, pc
|
341
|
+
numFrames := runtime.Callers(skip+skipOffset, pc)
|
338
342
|
if numFrames < 1 {
|
339
343
|
return
|
340
344
|
}
|
@@ -138,3 +138,11 @@ func OnFatal(action zapcore.CheckWriteAction) Option {
|
|
138
138
|
log.onFatal = action
|
139
139
|
})
|
140
140
|
}
|
141
|
+
|
142
|
+
// WithClock specifies the clock used by the logger to determine the current
|
143
|
+
// time for logged entries. Defaults to the system clock with time.Now.
|
144
|
+
func WithClock(clock zapcore.Clock) Option {
|
145
|
+
return optionFunc(func(log *Logger) {
|
146
|
+
log.clock = clock
|
147
|
+
})
|
148
|
+
}
|
@@ -222,19 +222,30 @@ func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interf
|
|
222
222
|
return
|
223
223
|
}
|
224
224
|
|
225
|
-
|
226
|
-
msg := template
|
227
|
-
if msg == "" && len(fmtArgs) > 0 {
|
228
|
-
msg = fmt.Sprint(fmtArgs...)
|
229
|
-
} else if msg != "" && len(fmtArgs) > 0 {
|
230
|
-
msg = fmt.Sprintf(template, fmtArgs...)
|
231
|
-
}
|
232
|
-
|
225
|
+
msg := getMessage(template, fmtArgs)
|
233
226
|
if ce := s.base.Check(lvl, msg); ce != nil {
|
234
227
|
ce.Write(s.sweetenFields(context)...)
|
235
228
|
}
|
236
229
|
}
|
237
230
|
|
231
|
+
// getMessage format with Sprint, Sprintf, or neither.
|
232
|
+
func getMessage(template string, fmtArgs []interface{}) string {
|
233
|
+
if len(fmtArgs) == 0 {
|
234
|
+
return template
|
235
|
+
}
|
236
|
+
|
237
|
+
if template != "" {
|
238
|
+
return fmt.Sprintf(template, fmtArgs...)
|
239
|
+
}
|
240
|
+
|
241
|
+
if len(fmtArgs) == 1 {
|
242
|
+
if str, ok := fmtArgs[0].(string); ok {
|
243
|
+
return str
|
244
|
+
}
|
245
|
+
}
|
246
|
+
return fmt.Sprint(fmtArgs...)
|
247
|
+
}
|
248
|
+
|
238
249
|
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
|
239
250
|
if len(args) == 0 {
|
240
251
|
return nil
|
@@ -255,7 +266,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
|
|
255
266
|
|
256
267
|
// Make sure this element isn't a dangling key.
|
257
268
|
if i == len(args)-1 {
|
258
|
-
s.base.
|
269
|
+
s.base.Error(_oddNumberErrMsg, Any("ignored", args[i]))
|
259
270
|
break
|
260
271
|
}
|
261
272
|
|
@@ -276,7 +287,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
|
|
276
287
|
|
277
288
|
// If we encountered any invalid key-value pairs, log an error.
|
278
289
|
if len(invalid) > 0 {
|
279
|
-
s.base.
|
290
|
+
s.base.Error(_nonStringKeyErrMsg, Array("invalid", invalid))
|
280
291
|
}
|
281
292
|
return fields
|
282
293
|
}
|
@@ -0,0 +1,188 @@
|
|
1
|
+
// Copyright (c) 2021 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 zapcore
|
22
|
+
|
23
|
+
import (
|
24
|
+
"bufio"
|
25
|
+
"sync"
|
26
|
+
"time"
|
27
|
+
|
28
|
+
"go.uber.org/multierr"
|
29
|
+
)
|
30
|
+
|
31
|
+
const (
|
32
|
+
// _defaultBufferSize specifies the default size used by Buffer.
|
33
|
+
_defaultBufferSize = 256 * 1024 // 256 kB
|
34
|
+
|
35
|
+
// _defaultFlushInterval specifies the default flush interval for
|
36
|
+
// Buffer.
|
37
|
+
_defaultFlushInterval = 30 * time.Second
|
38
|
+
)
|
39
|
+
|
40
|
+
// A BufferedWriteSyncer is a WriteSyncer that buffers writes in-memory before
|
41
|
+
// flushing them to a wrapped WriteSyncer after reaching some limit, or at some
|
42
|
+
// fixed interval--whichever comes first.
|
43
|
+
//
|
44
|
+
// BufferedWriteSyncer is safe for concurrent use. You don't need to use
|
45
|
+
// zapcore.Lock for WriteSyncers with BufferedWriteSyncer.
|
46
|
+
type BufferedWriteSyncer struct {
|
47
|
+
// WS is the WriteSyncer around which BufferedWriteSyncer will buffer
|
48
|
+
// writes.
|
49
|
+
//
|
50
|
+
// This field is required.
|
51
|
+
WS WriteSyncer
|
52
|
+
|
53
|
+
// Size specifies the maximum amount of data the writer will buffered
|
54
|
+
// before flushing.
|
55
|
+
//
|
56
|
+
// Defaults to 256 kB if unspecified.
|
57
|
+
Size int
|
58
|
+
|
59
|
+
// FlushInterval specifies how often the writer should flush data if
|
60
|
+
// there have been no writes.
|
61
|
+
//
|
62
|
+
// Defaults to 30 seconds if unspecified.
|
63
|
+
FlushInterval time.Duration
|
64
|
+
|
65
|
+
// Clock, if specified, provides control of the source of time for the
|
66
|
+
// writer.
|
67
|
+
//
|
68
|
+
// Defaults to the system clock.
|
69
|
+
Clock Clock
|
70
|
+
|
71
|
+
// unexported fields for state
|
72
|
+
mu sync.Mutex
|
73
|
+
initialized bool // whether initialize() has run
|
74
|
+
writer *bufio.Writer
|
75
|
+
ticker *time.Ticker
|
76
|
+
stop chan struct{} // closed when flushLoop should stop
|
77
|
+
stopped bool // whether Stop() has run
|
78
|
+
done chan struct{} // closed when flushLoop has stopped
|
79
|
+
}
|
80
|
+
|
81
|
+
func (s *BufferedWriteSyncer) initialize() {
|
82
|
+
size := s.Size
|
83
|
+
if size == 0 {
|
84
|
+
size = _defaultBufferSize
|
85
|
+
}
|
86
|
+
|
87
|
+
flushInterval := s.FlushInterval
|
88
|
+
if flushInterval == 0 {
|
89
|
+
flushInterval = _defaultFlushInterval
|
90
|
+
}
|
91
|
+
|
92
|
+
if s.Clock == nil {
|
93
|
+
s.Clock = DefaultClock
|
94
|
+
}
|
95
|
+
|
96
|
+
s.ticker = s.Clock.NewTicker(flushInterval)
|
97
|
+
s.writer = bufio.NewWriterSize(s.WS, size)
|
98
|
+
s.stop = make(chan struct{})
|
99
|
+
s.done = make(chan struct{})
|
100
|
+
s.initialized = true
|
101
|
+
go s.flushLoop()
|
102
|
+
}
|
103
|
+
|
104
|
+
// Write writes log data into buffer syncer directly, multiple Write calls will be batched,
|
105
|
+
// and log data will be flushed to disk when the buffer is full or periodically.
|
106
|
+
func (s *BufferedWriteSyncer) Write(bs []byte) (int, error) {
|
107
|
+
s.mu.Lock()
|
108
|
+
defer s.mu.Unlock()
|
109
|
+
|
110
|
+
if !s.initialized {
|
111
|
+
s.initialize()
|
112
|
+
}
|
113
|
+
|
114
|
+
// To avoid partial writes from being flushed, we manually flush the existing buffer if:
|
115
|
+
// * The current write doesn't fit into the buffer fully, and
|
116
|
+
// * The buffer is not empty (since bufio will not split large writes when the buffer is empty)
|
117
|
+
if len(bs) > s.writer.Available() && s.writer.Buffered() > 0 {
|
118
|
+
if err := s.writer.Flush(); err != nil {
|
119
|
+
return 0, err
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
return s.writer.Write(bs)
|
124
|
+
}
|
125
|
+
|
126
|
+
// Sync flushes buffered log data into disk directly.
|
127
|
+
func (s *BufferedWriteSyncer) Sync() error {
|
128
|
+
s.mu.Lock()
|
129
|
+
defer s.mu.Unlock()
|
130
|
+
|
131
|
+
var err error
|
132
|
+
if s.initialized {
|
133
|
+
err = s.writer.Flush()
|
134
|
+
}
|
135
|
+
|
136
|
+
return multierr.Append(err, s.WS.Sync())
|
137
|
+
}
|
138
|
+
|
139
|
+
// flushLoop flushes the buffer at the configured interval until Stop is
|
140
|
+
// called.
|
141
|
+
func (s *BufferedWriteSyncer) flushLoop() {
|
142
|
+
defer close(s.done)
|
143
|
+
|
144
|
+
for {
|
145
|
+
select {
|
146
|
+
case <-s.ticker.C:
|
147
|
+
// we just simply ignore error here
|
148
|
+
// because the underlying bufio writer stores any errors
|
149
|
+
// and we return any error from Sync() as part of the close
|
150
|
+
_ = s.Sync()
|
151
|
+
case <-s.stop:
|
152
|
+
return
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
// Stop closes the buffer, cleans up background goroutines, and flushes
|
158
|
+
// remaining unwritten data.
|
159
|
+
func (s *BufferedWriteSyncer) Stop() (err error) {
|
160
|
+
var stopped bool
|
161
|
+
|
162
|
+
// Critical section.
|
163
|
+
func() {
|
164
|
+
s.mu.Lock()
|
165
|
+
defer s.mu.Unlock()
|
166
|
+
|
167
|
+
if !s.initialized {
|
168
|
+
return
|
169
|
+
}
|
170
|
+
|
171
|
+
stopped = s.stopped
|
172
|
+
if stopped {
|
173
|
+
return
|
174
|
+
}
|
175
|
+
s.stopped = true
|
176
|
+
|
177
|
+
s.ticker.Stop()
|
178
|
+
close(s.stop) // tell flushLoop to stop
|
179
|
+
<-s.done // and wait until it has
|
180
|
+
}()
|
181
|
+
|
182
|
+
// Don't call Sync on consecutive Stops.
|
183
|
+
if !stopped {
|
184
|
+
err = s.Sync()
|
185
|
+
}
|
186
|
+
|
187
|
+
return err
|
188
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
// Copyright (c) 2021 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 zapcore
|
22
|
+
|
23
|
+
import (
|
24
|
+
"time"
|
25
|
+
)
|
26
|
+
|
27
|
+
// DefaultClock is the default clock used by Zap in operations that require
|
28
|
+
// time. This clock uses the system clock for all operations.
|
29
|
+
var DefaultClock = systemClock{}
|
30
|
+
|
31
|
+
// Clock is a source of time for logged entries.
|
32
|
+
type Clock interface {
|
33
|
+
// Now returns the current local time.
|
34
|
+
Now() time.Time
|
35
|
+
|
36
|
+
// NewTicker returns *time.Ticker that holds a channel
|
37
|
+
// that delivers "ticks" of a clock.
|
38
|
+
NewTicker(time.Duration) *time.Ticker
|
39
|
+
}
|
40
|
+
|
41
|
+
// systemClock implements default Clock that uses system time.
|
42
|
+
type systemClock struct{}
|
43
|
+
|
44
|
+
func (systemClock) Now() time.Time {
|
45
|
+
return time.Now()
|
46
|
+
}
|
47
|
+
|
48
|
+
func (systemClock) NewTicker(duration time.Duration) *time.Ticker {
|
49
|
+
return time.NewTicker(duration)
|
50
|
+
}
|
@@ -56,7 +56,7 @@ type consoleEncoder struct {
|
|
56
56
|
// encoder configuration, it will omit any element whose key is set to the empty
|
57
57
|
// string.
|
58
58
|
func NewConsoleEncoder(cfg EncoderConfig) Encoder {
|
59
|
-
if
|
59
|
+
if cfg.ConsoleSeparator == "" {
|
60
60
|
// Use a default delimiter of '\t' for backwards compatibility
|
61
61
|
cfg.ConsoleSeparator = "\t"
|
62
62
|
}
|
@@ -208,7 +208,7 @@ func (ce *CheckedEntry) Write(fields ...Field) {
|
|
208
208
|
// If the entry is dirty, log an internal error; because the
|
209
209
|
// CheckedEntry is being used after it was returned to the pool,
|
210
210
|
// the message may be an amalgamation from multiple call sites.
|
211
|
-
fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n",
|
211
|
+
fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", ce.Time, ce.Entry)
|
212
212
|
ce.ErrorOutput.Sync()
|
213
213
|
}
|
214
214
|
return
|
@@ -221,7 +221,7 @@ func (ce *CheckedEntry) Write(fields ...Field) {
|
|
221
221
|
}
|
222
222
|
if ce.ErrorOutput != nil {
|
223
223
|
if err != nil {
|
224
|
-
fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n",
|
224
|
+
fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", ce.Time, err)
|
225
225
|
ce.ErrorOutput.Sync()
|
226
226
|
}
|
227
227
|
}
|
@@ -22,6 +22,7 @@ package zapcore
|
|
22
22
|
|
23
23
|
import (
|
24
24
|
"fmt"
|
25
|
+
"reflect"
|
25
26
|
"sync"
|
26
27
|
)
|
27
28
|
|
@@ -42,7 +43,23 @@ import (
|
|
42
43
|
// ...
|
43
44
|
// ],
|
44
45
|
// }
|
45
|
-
func encodeError(key string, err error, enc ObjectEncoder) error {
|
46
|
+
func encodeError(key string, err error, enc ObjectEncoder) (retErr error) {
|
47
|
+
// Try to capture panics (from nil references or otherwise) when calling
|
48
|
+
// the Error() method
|
49
|
+
defer func() {
|
50
|
+
if rerr := recover(); rerr != nil {
|
51
|
+
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
|
52
|
+
// error that fails to guard against nil or a nil pointer for a
|
53
|
+
// value receiver, and in either case, "<nil>" is a nice result.
|
54
|
+
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
|
55
|
+
enc.AddString(key, "<nil>")
|
56
|
+
return
|
57
|
+
}
|
58
|
+
|
59
|
+
retErr = fmt.Errorf("PANIC=%v", rerr)
|
60
|
+
}
|
61
|
+
}()
|
62
|
+
|
46
63
|
basic := err.Error()
|
47
64
|
enc.AddString(key, basic)
|
48
65
|
|
@@ -92,6 +92,10 @@ const (
|
|
92
92
|
ErrorType
|
93
93
|
// SkipType indicates that the field is a no-op.
|
94
94
|
SkipType
|
95
|
+
|
96
|
+
// InlineMarshalerType indicates that the field carries an ObjectMarshaler
|
97
|
+
// that should be inlined.
|
98
|
+
InlineMarshalerType
|
95
99
|
)
|
96
100
|
|
97
101
|
// A Field is a marshaling operation used to add a key-value pair to a logger's
|
@@ -115,6 +119,8 @@ func (f Field) AddTo(enc ObjectEncoder) {
|
|
115
119
|
err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
|
116
120
|
case ObjectMarshalerType:
|
117
121
|
err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
|
122
|
+
case InlineMarshalerType:
|
123
|
+
err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc)
|
118
124
|
case BinaryType:
|
119
125
|
enc.AddBinary(f.Key, f.Interface.([]byte))
|
120
126
|
case BoolType:
|
@@ -167,7 +173,7 @@ func (f Field) AddTo(enc ObjectEncoder) {
|
|
167
173
|
case StringerType:
|
168
174
|
err = encodeStringer(f.Key, f.Interface, enc)
|
169
175
|
case ErrorType:
|
170
|
-
encodeError(f.Key, f.Interface.(error), enc)
|
176
|
+
err = encodeError(f.Key, f.Interface.(error), enc)
|
171
177
|
case SkipType:
|
172
178
|
break
|
173
179
|
default:
|