From 7de0adbff0c74302ce7d6df53c770c40ae635243 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 14 Mar 2016 14:00:37 +0800 Subject: [PATCH] add log util --- log/formatter.go | 20 ++++ log/level.go | 45 +++++++ log/logger.go | 265 ++++++++++++++++++++++++++++++++++++++++++ log/record.go | 36 ++++++ log/text_formatter.go | 58 +++++++++ 5 files changed, 424 insertions(+) create mode 100644 log/formatter.go create mode 100644 log/level.go create mode 100644 log/logger.go create mode 100644 log/record.go create mode 100644 log/text_formatter.go diff --git a/log/formatter.go b/log/formatter.go new file mode 100644 index 000000000..8d5dc371d --- /dev/null +++ b/log/formatter.go @@ -0,0 +1,20 @@ +/* + 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 + +type Formatter interface { + Format(*Record) ([]byte, error) +} diff --git a/log/level.go b/log/level.go new file mode 100644 index 000000000..60ae3ab28 --- /dev/null +++ b/log/level.go @@ -0,0 +1,45 @@ +/* + 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 + +type Level int + +const ( + DebugLevel Level = iota + InfoLevel + WarningLevel + ErrorLevel + FatalLevel +) + +func (l Level) string() string { + switch l { + case DebugLevel: + return "DEBUG" + case InfoLevel: + return "INFO" + case WarningLevel: + return "WARNING" + case ErrorLevel: + return "ERROR" + case FatalLevel: + return "FATAL" + } + + return "unknown" +} + +//DEBUG, INFO, WARNING, ERROR, and FATAL diff --git a/log/logger.go b/log/logger.go new file mode 100644 index 000000000..a0e815e7e --- /dev/null +++ b/log/logger.go @@ -0,0 +1,265 @@ +/* + 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) + +// 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 +} + +func New(out io.Writer, fmtter Formatter, lvl Level) *Logger { + return &Logger{ + out: out, + fmtter: fmtter, + lvl: lvl, + } +} + +func (l *Logger) SetOutput(out io.Writer) { + l.mu.Lock() + defer l.mu.Unlock() + + l.out = out +} + +func (l *Logger) SetFormatter(fmtter Formatter) { + l.mu.Lock() + defer l.mu.Unlock() + + l.fmtter = fmtter +} + +func (l *Logger) SetLevel(lvl Level) { + l.mu.Lock() + defer l.mu.Unlock() + + l.lvl = lvl +} + +func SetOutput(out io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + + logger.out = out +} + +func SetFormatter(fmtter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + + logger.fmtter = fmtter +} + +func SetLevel(lvl Level) { + logger.mu.Lock() + defer logger.mu.Unlock() + + logger.lvl = 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 +} + +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) + } +} + +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) + } +} + +func (l *Logger) Info(v ...interface{}) { + if l.lvl <= InfoLevel { + record := NewRecord(time.Now(), fmt.Sprint(v...), "", InfoLevel) + l.output(record) + } +} + +func (l *Logger) Infof(format string, v ...interface{}) { + if l.lvl <= InfoLevel { + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", InfoLevel) + l.output(record) + } +} + +func (l *Logger) Warning(v ...interface{}) { + if l.lvl <= WarningLevel { + record := NewRecord(time.Now(), fmt.Sprint(v...), "", WarningLevel) + l.output(record) + } +} + +func (l *Logger) Warningf(format string, v ...interface{}) { + if l.lvl <= WarningLevel { + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", WarningLevel) + l.output(record) + } +} + +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) + } +} + +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) + } +} + +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) +} + +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) +} + +func Debug(v ...interface{}) { + if logger.lvl <= DebugLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprint(v...), line, DebugLevel) + logger.output(record) + } +} + +func Debugf(format string, v ...interface{}) { + if logger.lvl <= DebugLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, DebugLevel) + logger.output(record) + } +} + +func Info(v ...interface{}) { + if logger.lvl <= InfoLevel { + record := NewRecord(time.Now(), fmt.Sprint(v...), "", InfoLevel) + logger.output(record) + } +} + +func Infof(format string, v ...interface{}) { + if logger.lvl <= InfoLevel { + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", InfoLevel) + logger.output(record) + } +} + +func Warning(v ...interface{}) { + if logger.lvl <= WarningLevel { + record := NewRecord(time.Now(), fmt.Sprint(v...), "", WarningLevel) + logger.output(record) + } +} + +func Warningf(format string, v ...interface{}) { + if logger.lvl <= WarningLevel { + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), "", WarningLevel) + logger.output(record) + } +} + +func Error(v ...interface{}) { + if logger.lvl <= ErrorLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprint(v...), line, ErrorLevel) + logger.output(record) + } +} + +func Errorf(format string, v ...interface{}) { + if logger.lvl <= ErrorLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, ErrorLevel) + logger.output(record) + } +} + +func Fatal(v ...interface{}) { + if logger.lvl <= FatalLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprint(v...), line, FatalLevel) + logger.output(record) + } + os.Exit(1) +} + +func Fatalf(format string, v ...interface{}) { + if logger.lvl <= FatalLevel { + line := line(2) + record := NewRecord(time.Now(), fmt.Sprintf(format, v...), line, FatalLevel) + logger.output(record) + } + os.Exit(1) +} + +func line(calldepth int) string { + _, file, line, ok := runtime.Caller(calldepth) + if !ok { + file = "???" + line = 0 + } + + return fmt.Sprintf("%s:%d", file, line) +} diff --git a/log/record.go b/log/record.go new file mode 100644 index 000000000..96cf6f197 --- /dev/null +++ b/log/record.go @@ -0,0 +1,36 @@ +/* + 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" +) + +type Record struct { + Time time.Time + Msg string + Line string + Lvl Level +} + +func NewRecord(time time.Time, msg, line string, lvl Level) *Record { + return &Record{ + Time: time, + Msg: msg, + Line: line, + Lvl: lvl, + } +} diff --git a/log/text_formatter.go b/log/text_formatter.go new file mode 100644 index 000000000..bd4d19919 --- /dev/null +++ b/log/text_formatter.go @@ -0,0 +1,58 @@ +/* + 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 string = time.RFC3339 + +type TextFormatter struct { + timeFormat string +} + +func NewTextFormatter(timeFormat string) *TextFormatter { + if len(timeFormat) == 0 { + timeFormat = defaultTimeFormat + } + + return &TextFormatter{ + timeFormat: timeFormat, + } +} + +// 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 +}