blob: bb8234c5b67b32e4738537c0ff937a90eb2272ab [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package log
import (
"fmt"
"io"
"os"
"runtime"
"time"
"go.uber.org/zap/zapcore"
)
var (
levelMap = map[string]zapcore.Level{
zapcore.DebugLevel.String(): zapcore.DebugLevel,
zapcore.InfoLevel.String(): zapcore.InfoLevel,
zapcore.WarnLevel.String(): zapcore.WarnLevel,
zapcore.ErrorLevel.String(): zapcore.ErrorLevel,
zapcore.PanicLevel.String(): zapcore.PanicLevel,
zapcore.FatalLevel.String(): zapcore.FatalLevel,
}
)
// Logger is a log object, which exposes standard APIs like
// errorf, error, warn, warnf and etcd.
type Logger struct {
writer io.Writer
core zapcore.Core
level zapcore.Level
}
// Level returns the log level
func (logger *Logger) Level() zapcore.Level {
return logger.level
}
func (logger *Logger) write(level zapcore.Level, message string, fields []zapcore.Field) {
e := zapcore.Entry{
Level: level,
Time: time.Now(),
Message: message,
Caller: zapcore.NewEntryCaller(runtime.Caller(3)),
}
_ = logger.core.Write(e, fields)
}
// Sync flushes all buffered logs to the their destination.
func (logger *Logger) Sync() (err error) {
file, ok := logger.writer.(*os.File)
if ok && file != os.Stdout && file != os.Stderr {
err = logger.core.Sync()
}
return
}
// Close flushes all buffered logs and closes the underlying writer.
func (logger *Logger) Close() (err error) {
closer, ok := logger.writer.(io.Closer)
if ok {
return closer.Close()
}
return nil
}
// Debug uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Debug(args ...interface{}) {
if logger.level <= zapcore.DebugLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.DebugLevel, msg, nil)
}
}
// Debugf uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Debugf(template string, args ...interface{}) {
if logger.level <= zapcore.DebugLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.DebugLevel, msg, nil)
}
}
// Debugw logs a message with some additional context.
func (logger *Logger) Debugw(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.DebugLevel {
logger.write(zapcore.DebugLevel, message, fields)
}
}
// Info uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Info(args ...interface{}) {
if logger.level <= zapcore.InfoLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.InfoLevel, msg, nil)
}
}
// Infof uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Infof(template string, args ...interface{}) {
if logger.level <= zapcore.InfoLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.InfoLevel, msg, nil)
}
}
// Infow logs a message with some additional context.
func (logger *Logger) Infow(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.InfoLevel {
logger.write(zapcore.InfoLevel, message, fields)
}
}
// Warn uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Warn(args ...interface{}) {
if logger.level <= zapcore.WarnLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.WarnLevel, msg, nil)
}
}
// Warnf uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Warnf(template string, args ...interface{}) {
if logger.level <= zapcore.WarnLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.WarnLevel, msg, nil)
}
}
// Warnw logs a message with some additional context.
func (logger *Logger) Warnw(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.WarnLevel {
logger.write(zapcore.WarnLevel, message, fields)
}
}
// Error uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Error(args ...interface{}) {
if logger.level <= zapcore.ErrorLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.ErrorLevel, msg, nil)
}
}
// Errorf uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Errorf(template string, args ...interface{}) {
if logger.level <= zapcore.ErrorLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.ErrorLevel, msg, nil)
}
}
// Errorw logs a message with some additional context.
func (logger *Logger) Errorw(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.ErrorLevel {
logger.write(zapcore.ErrorLevel, message, fields)
}
}
// Panic uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Panic(args ...interface{}) {
if logger.level <= zapcore.PanicLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.PanicLevel, msg, nil)
}
}
// Panicf uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Panicf(template string, args ...interface{}) {
if logger.level <= zapcore.PanicLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.PanicLevel, msg, nil)
}
}
// Panicw logs a message with some additional context.
func (logger *Logger) Panicw(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.PanicLevel {
logger.write(zapcore.PanicLevel, message, fields)
}
}
// Fatal uses the fmt.Sprint to construct and log a message.
func (logger *Logger) Fatal(args ...interface{}) {
if logger.level <= zapcore.FatalLevel {
msg := fmt.Sprint(args...)
logger.write(zapcore.FatalLevel, msg, nil)
}
}
// Fatalf uses the fmt.Sprintf to log a templated message.
func (logger *Logger) Fatalf(template string, args ...interface{}) {
if logger.level <= zapcore.FatalLevel {
msg := fmt.Sprintf(template, args...)
logger.write(zapcore.FatalLevel, msg, nil)
}
}
// Fatalw logs a message with some additional context.
func (logger *Logger) Fatalw(message string, fields ...zapcore.Field) {
if logger.level <= zapcore.FatalLevel {
logger.write(zapcore.FatalLevel, message, fields)
}
}
// NewLogger sets up a Logger object according to a series of options.
func NewLogger(opts ...Option) (*Logger, error) {
var (
writer zapcore.WriteSyncer
enc zapcore.Encoder
)
o := &options{
logLevel: "warn",
outputFile: "stderr",
}
for _, opt := range opts {
opt.apply(o)
}
level, ok := levelMap[o.logLevel]
if !ok {
return nil, fmt.Errorf("unknown log level %s", o.logLevel)
}
logger := &Logger{
level: level,
}
if o.writeSyncer != nil {
writer = o.writeSyncer
} else {
if o.outputFile == "stdout" {
writer = os.Stdout
} else if o.outputFile == "stderr" {
writer = os.Stderr
} else {
file, err := os.OpenFile(o.outputFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, err
}
writer = file
}
}
if writer == os.Stdout || writer == os.Stderr {
enc = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
TimeKey: "time",
NameKey: "context",
CallerKey: "caller",
StacktraceKey: "backtrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseColorLevelEncoder,
EncodeTime: zapcore.RFC3339TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
})
} else {
enc = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
TimeKey: "time",
NameKey: "context",
CallerKey: "caller",
StacktraceKey: "backtrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.RFC3339NanoTimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
})
}
logger.writer = writer
logger.core = zapcore.NewCore(enc, writer, level)
return logger, nil
}