Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add global functions #2

Merged
merged 5 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
vendor
7 changes: 7 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ type Config struct {
Sampling *zap.SamplingConfig `toml:"sampling" json:"sampling"`
}

// ZapProperties records some information about zap.
type ZapProperties struct {
Core zapcore.Core
Syncer zapcore.WriteSyncer
Level zap.AtomicLevel
}

func newZapTextEncoder(cfg *Config) zapcore.Encoder {
cc := zapcore.EncoderConfig{
// Keys can be anything except the empty string.
Expand Down
70 changes: 70 additions & 0 deletions global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package log

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

// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Debug(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Debug(msg, fields...)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add this option to the logger directly when creating the logger?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can. But I do not directly create the logger with this option because the user may use L(),S() without the export function.

}

// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Info(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Info(msg, fields...)
}

// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Warn(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Warn(msg, fields...)
}

// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Error(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Error(msg, fields...)
}

// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func Panic(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Panic(msg, fields...)
}

// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func Fatal(msg string, fields ...zap.Field) {
L().WithOptions(zap.AddCallerSkip(1)).Fatal(msg, fields...)
}

// SetLevel alters the logging level.
func SetLevel(l zapcore.Level) {
_globalP.Level.SetLevel(l)
}

// GetLevel gets the logging level.
func GetLevel() zapcore.Level {
return _globalP.Level.Level()
}
55 changes: 29 additions & 26 deletions log.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ package log
import (
"errors"
"os"
"sync"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)

// InitLogger initializes a zap logger.
func InitLogger(cfg *Config) (*zap.Logger, zapcore.WriteSyncer, error) {
func InitLogger(cfg *Config, opts ...zap.Option) (*zap.Logger, *ZapProperties, error) {
var output zapcore.WriteSyncer
if len(cfg.File.Filename) > 0 {
lg, err := initFileLog(&cfg.File)
Expand All @@ -46,9 +45,14 @@ func InitLogger(cfg *Config) (*zap.Logger, zapcore.WriteSyncer, error) {
return nil, nil, err
}
core := zapcore.NewCore(newZapTextEncoder(cfg), output, level)
lg := zap.New(core, cfg.buildOptions(output)...)

return lg, output, nil
opts = append(opts, cfg.buildOptions(output)...)
lg := zap.New(core, opts...)
r := &ZapProperties{
Core: core,
Syncer: output,
Level: level,
}
return lg, r, nil
}

// initFileLog initializes file based logging options.
Expand All @@ -72,43 +76,42 @@ func initFileLog(cfg *FileLogConfig) (*lumberjack.Logger, error) {
}, nil
}

func newStdLogger() *zap.Logger {
func newStdLogger() (*zap.Logger, *ZapProperties) {
conf := &Config{Level: "info", File: FileLogConfig{}}
lg, _, _ := InitLogger(conf)
return lg
lg, r, _ := InitLogger(conf)
return lg, r
}

var (
_globalMu sync.RWMutex
_globalL = newStdLogger()
_globalS = _globalL.Sugar()
_globalL, _globalP = newStdLogger()
_globalS = _globalL.Sugar()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When do we need to use sugar?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure in our situation but keep supporting it.

)

// L returns the global Logger, which can be reconfigured with ReplaceGlobals.
// It's safe for concurrent use.
func L() *zap.Logger {
_globalMu.RLock()
l := _globalL
_globalMu.RUnlock()
return l
return _globalL
}

// S returns the global SugaredLogger, which can be reconfigured with
// ReplaceGlobals. It's safe for concurrent use.
func S() *zap.SugaredLogger {
_globalMu.RLock()
s := _globalS
_globalMu.RUnlock()
return s
return _globalS
}

// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
// function to restore the original values. It's safe for concurrent use.
func ReplaceGlobals(logger *zap.Logger) func() {
_globalMu.Lock()
prev := _globalL
// ReplaceGlobals replaces the global Logger and SugaredLogger.
// It's unsafe for concurrent use.
func ReplaceGlobals(logger *zap.Logger, props *ZapProperties) {
_globalL = logger
_globalS = logger.Sugar()
_globalMu.Unlock()
return func() { ReplaceGlobals(prev) }
_globalP = props
}

// Sync flushes any buffered log entries.
func Sync() error {
err := L().Sync()
if err != nil {
return err
}
return S().Sync()
}
33 changes: 33 additions & 0 deletions log_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package log

import (
. "github.com/pingcap/check"
)

var _ = Suite(&testLogSuite{})

type testLogSuite struct{}

func (t *testLogSuite) TestExport(c *C) {
conf := &Config{Level: "debug", File: FileLogConfig{}, DisableTimestamp: true}
lg := newZapTestLogger(conf, c)
ReplaceGlobals(lg.Logger, nil)
Info("Testing")
Debug("Testing")
Warn("Testing")
Error("Testing")
lg.AssertContains("log_test.go:")
}
7 changes: 7 additions & 0 deletions zap_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"math"
"net"
"os"
"strings"
"testing"
"time"
"unsafe"
Expand Down Expand Up @@ -70,6 +71,12 @@ func (v *verifyLogger) AssertMessage(msg ...string) {
}
}

func (v *verifyLogger) AssertContains(substr string) {
for _, m := range v.w.messages {
v.w.c.Assert(strings.Contains(m, substr), IsTrue)
}
}

func newZapTestLogger(cfg *Config, c *C) verifyLogger {
writer := newTestingWriter(c)
opt := cfg.buildOptions(writer)
Expand Down