Merge pull request #25 from ywk253100/logger_util

Logger util
This commit is contained in:
Haining Henry Zhang 2016-03-17 12:22:28 +08:00
commit 2ee1e0a2a0
5 changed files with 460 additions and 0 deletions

21
log/formatter.go Normal file
View File

@ -0,0 +1,21 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
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,
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
// Formatter formats records in different ways: text, json, etc.
type Formatter interface {
Format(*Record) ([]byte, error)
}

75
log/level.go Normal file
View File

@ -0,0 +1,75 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
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,
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"
)
// Level ...
type Level int
const (
// DebugLevel debug
DebugLevel Level = iota
// InfoLevel info
InfoLevel
// WarningLevel warning
WarningLevel
// ErrorLevel error
ErrorLevel
// FatalLevel fatal
FatalLevel
)
func (l Level) string() (lvl string) {
switch l {
case DebugLevel:
lvl = "DEBUG"
case InfoLevel:
lvl = "INFO"
case WarningLevel:
lvl = "WARNING"
case ErrorLevel:
lvl = "ERROR"
case FatalLevel:
lvl = "FATAL"
default:
lvl = "UNKNOWN"
}
return
}
func parseLevel(lvl string) (level Level, err error) {
switch lvl {
case "debug":
level = DebugLevel
case "info":
level = InfoLevel
case "warning":
level = WarningLevel
case "error":
level = ErrorLevel
case "fatal":
level = FatalLevel
default:
err = fmt.Errorf("invalid log level: %s", lvl)
}
return
}

263
log/logger.go Normal file
View File

@ -0,0 +1,263 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
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,
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"
"sync"
"time"
)
var logger = New(os.Stdout, NewTextFormatter(), WarningLevel)
func init() {
// TODO add item in configuaration file
lvl := os.Getenv("LOG_LEVEL")
if len(lvl) == 0 {
logger.SetLevel(InfoLevel)
return
}
level, err := parseLevel(lvl)
if err != nil {
logger.SetLevel(InfoLevel)
return
}
logger.SetLevel(level)
}
// Logger provides a struct with fields that describe the details of logger.
type Logger struct {
out io.Writer
fmtter Formatter
lvl Level
mu sync.Mutex
}
// New returns a customized Logger
func New(out io.Writer, fmtter Formatter, lvl Level) *Logger {
return &Logger{
out: out,
fmtter: fmtter,
lvl: lvl,
}
}
//SetOutput sets the output of Logger l
func (l *Logger) SetOutput(out io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.out = out
}
//SetFormatter sets the formatter of Logger l
func (l *Logger) SetFormatter(fmtter Formatter) {
l.mu.Lock()
defer l.mu.Unlock()
l.fmtter = fmtter
}
//SetLevel sets the level of Logger l
func (l *Logger) SetLevel(lvl Level) {
l.mu.Lock()
defer l.mu.Unlock()
l.lvl = lvl
}
//SetOutput sets the output of default Logger
func SetOutput(out io.Writer) {
logger.SetOutput(out)
}
//SetFormatter sets the formatter of default Logger
func SetFormatter(fmtter Formatter) {
logger.SetFormatter(fmtter)
}
//SetLevel sets the level of default Logger
func SetLevel(lvl Level) {
logger.SetLevel(lvl)
}
func (l *Logger) output(record *Record) (err error) {
b, err := l.fmtter.Format(record)
if err != nil {
return
}
l.mu.Lock()
defer l.mu.Unlock()
_, err = l.out.Write(b)
return
}
// Debug ...
func (l *Logger) Debug(v ...interface{}) {
if l.lvl <= DebugLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprint(v...), line, DebugLevel)
l.output(record)
}
}
// Debugf ...
func (l *Logger) Debugf(format string, v ...interface{}) {
if l.lvl <= DebugLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, DebugLevel)
l.output(record)
}
}
// Info ...
func (l *Logger) Info(v ...interface{}) {
if l.lvl <= InfoLevel {
record := NewRecord(time.Now(), fmt.Sprint(v...), "", InfoLevel)
l.output(record)
}
}
// Infof ...
func (l *Logger) Infof(format string, v ...interface{}) {
if l.lvl <= InfoLevel {
record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", InfoLevel)
l.output(record)
}
}
// Warning ...
func (l *Logger) Warning(v ...interface{}) {
if l.lvl <= WarningLevel {
record := NewRecord(time.Now(), fmt.Sprint(v...), "", WarningLevel)
l.output(record)
}
}
// Warningf ...
func (l *Logger) Warningf(format string, v ...interface{}) {
if l.lvl <= WarningLevel {
record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", WarningLevel)
l.output(record)
}
}
// Error ...
func (l *Logger) Error(v ...interface{}) {
if l.lvl <= ErrorLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprint(v...), line, ErrorLevel)
l.output(record)
}
}
// Errorf ...
func (l *Logger) Errorf(format string, v ...interface{}) {
if l.lvl <= ErrorLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, ErrorLevel)
l.output(record)
}
}
// Fatal ...
func (l *Logger) Fatal(v ...interface{}) {
if l.lvl <= FatalLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprint(v...), line, FatalLevel)
l.output(record)
}
os.Exit(1)
}
// Fatalf ...
func (l *Logger) Fatalf(format string, v ...interface{}) {
if l.lvl <= FatalLevel {
line := line(2)
record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, FatalLevel)
l.output(record)
}
os.Exit(1)
}
// Debug ...
func Debug(v ...interface{}) {
logger.Debug(v...)
}
// Debugf ...
func Debugf(format string, v ...interface{}) {
logger.Debugf(format, v...)
}
// Info ...
func Info(v ...interface{}) {
logger.Info(v...)
}
// Infof ...
func Infof(format string, v ...interface{}) {
logger.Infof(format, v...)
}
// Warning ...
func Warning(v ...interface{}) {
logger.Warning(v...)
}
// Warningf ...
func Warningf(format string, v ...interface{}) {
logger.Warningf(format, v...)
}
// Error ...
func Error(v ...interface{}) {
logger.Error(v...)
}
// Errorf ...
func Errorf(format string, v ...interface{}) {
logger.Errorf(format, v...)
}
// Fatal ...
func Fatal(v ...interface{}) {
logger.Fatal(v...)
}
// Fatalf ...
func Fatalf(format string, v ...interface{}) {
logger.Fatalf(format, v...)
}
func line(calldepth int) string {
_, file, line, ok := runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
return fmt.Sprintf("%s:%d", file, line)
}

38
log/record.go Normal file
View File

@ -0,0 +1,38 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
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,
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 (
"time"
)
// Record holds information about log
type Record struct {
Time time.Time // time when the log produced
Msg string // content of the log
Line string // in which file and line that the log produced
Lvl Level // level of the log
}
// NewRecord creates a record according to the arguments provided and returns it
func NewRecord(time time.Time, msg, line string, lvl Level) *Record {
return &Record{
Time: time,
Msg: msg,
Line: line,
Lvl: lvl,
}
}

63
log/textformatter.go Normal file
View File

@ -0,0 +1,63 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
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,
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"
"time"
)
var defaultTimeFormat = time.RFC3339 // 2006-01-02T15:04:05Z07:00
// TextFormatter represents a kind of formatter that formats the logs as plain text
type TextFormatter struct {
timeFormat string
}
// NewTextFormatter returns a TextFormatter, the format of time is time.RFC3339
func NewTextFormatter() *TextFormatter {
return &TextFormatter{
timeFormat: defaultTimeFormat,
}
}
// Format formats the logs as "time [level] line message"
func (t *TextFormatter) Format(r *Record) (b []byte, err error) {
s := fmt.Sprintf("%s [%s] ", r.Time.Format(t.timeFormat), r.Lvl.string())
if len(r.Line) != 0 {
s = s + r.Line + " "
}
if len(r.Msg) != 0 {
s = s + r.Msg
}
b = []byte(s)
if len(b) == 0 || b[len(b)-1] != '\n' {
b = append(b, '\n')
}
return
}
// SetTimeFormat sets time format of TextFormatter if the parameter fmt is not null
func (t *TextFormatter) SetTimeFormat(fmt string) {
if len(fmt) != 0 {
t.timeFormat = fmt
}
}