Default Log implementions

remotes/r/develop
Guoqiang Chen 8 years ago
commit 00fcb49366

@ -0,0 +1,94 @@
package log
import (
"io"
"os"
)
// std is a default logger for console
var std = New(os.Stdout).EnableColorizedLevel(true).SkipCaller(3)
// Get log level
func GetLevel() int {
return std.GetLevel()
}
// Set log level
func SetLevel(level int) {
std.SetLevel(level)
}
// Set a name to indicate a process
func SetName(name string) {
std.SetName(name)
}
// Set time layout for log line
func SetTimeLayout(layout string) {
std.SetTimeLayout(layout)
}
// EnableGoroutineId output goroutinue id
func EnableGoroutineId(enable bool) {
std.EnableGoroutineId(enable)
}
// EnableLongFileFormat output long file name
func EnableLongFileFormat(enable bool) {
std.EnableLongFileFormat(enable)
}
// EnableColorizedLevel output colorized level
func EnableColorizedLevel(enable bool) {
std.EnableColorizedLevel(enable)
}
// Set a writer
func SetWriter(w io.Writer) {
std.SetWriter(w)
}
// Indicate whether output debug message
func IsDebugEnabled() bool {
return std.IsDebugEnabled()
}
// Indicate whether output info message
func IsInfoEnabled() bool {
return std.IsInfoEnabled()
}
// Indicate whether output warning message
func IsWarnEnabled() bool {
return std.IsWarnEnabled()
}
// Indicate whether output error message
func IsErrorEnabled() bool {
return std.IsErrorEnabled()
}
// Output an debug message
func Debug(msg string, args ...interface{}) {
std.Debug(msg, args...)
}
// Output an info message
func Info(msg string, args ...interface{}) {
std.Info(msg, args...)
}
// Output a warning message
func Warn(msg string, args ...interface{}) {
std.Warn(msg, args...)
}
// Output an error message
func Error(msg string, args ...interface{}) {
std.Error(msg, args)
}
// Output a fatal message with full stack
func Fatal(msg string, args ...interface{}) {
std.Fatal(msg, args)
}

@ -0,0 +1,215 @@
package log
import (
"bytes"
"fmt"
"io"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
"github.com/subchen/gstack/gls"
)
// Log Level
const (
DEBUG = iota
INFO
WARN
ERROR
FATAL
)
var (
levelStr = []string{
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL",
}
levelStrWithColor = []string{
"\033[34mDEBUG\033[0m",
"\033[32mINFO\033[0m",
"\033[33mWARN\033[0m",
"\033[31mERROR\033[0m",
"\033[35mFATAL\033[0m",
}
)
func New(out io.Writer) *Logger {
return &Logger{
out: out,
level: INFO,
pid: os.Getpid(),
name: "",
timeLayout: "2006-01-02 15:04:05.000",
goroutineId: false,
longFileFormat: false,
colorizedLevel: false,
callerSkip: 2,
}
}
type Logger struct {
mu sync.Mutex
out io.Writer
level int
pid int
name string
timeLayout string
goroutineId bool
longFileFormat bool
colorizedLevel bool
callerSkip int
}
func (l *Logger) GetLevel() int {
return l.level
}
func (l *Logger) SetLevel(level int) *Logger {
l.level = level
return l
}
func (l *Logger) SetName(name string) *Logger {
l.name = name
return l
}
func (l *Logger) SetTimeLayout(layout string) *Logger {
l.timeLayout = layout
return l
}
func (l *Logger) EnableGoroutineId(enable bool) *Logger {
l.goroutineId = enable
return l
}
func (l *Logger) EnableLongFileFormat(enable bool) *Logger {
l.longFileFormat = enable
return l
}
func (l *Logger) EnableColorizedLevel(enable bool) *Logger {
l.colorizedLevel = enable
return l
}
func (l *Logger) SkipCaller(skip int) *Logger {
l.callerSkip = skip
return l
}
func (l *Logger) SetWriter(w io.Writer) *Logger {
l.out = w
return l
}
func (l *Logger) IsDebugEnabled() bool {
return l.level <= DEBUG
}
func (l *Logger) IsInfoEnabled() bool {
return l.level <= INFO
}
func (l *Logger) IsWarnEnabled() bool {
return l.level <= WARN
}
func (l *Logger) IsErrorEnabled() bool {
return l.level <= ERROR
}
func (l *Logger) Debug(msg string, args ...interface{}) {
if l.level <= DEBUG {
l.log(DEBUG, msg, args...)
}
}
func (l *Logger) Info(msg string, args ...interface{}) {
if l.level <= INFO {
l.log(INFO, msg, args...)
}
}
func (l *Logger) Warn(msg string, args ...interface{}) {
if l.level <= WARN {
l.log(WARN, msg, args...)
}
}
func (l *Logger) Error(msg string, args ...interface{}) {
if l.level <= ERROR {
l.log(ERROR, msg, args...)
}
}
func (l *Logger) Fatal(msg string, args ...interface{}) {
l.log(FATAL, msg, args...)
}
func (l *Logger) log(level int, msg string, args ...interface{}) {
_, file, line, ok := runtime.Caller(l.callerSkip)
if !ok {
file = "???"
line = 0
} else if !l.longFileFormat {
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
}
// output format: DATE PID [NAME] [GID] LEVEL file:line message
// 2001-10-10 12:00:00,000+0800 1234 app 987 INFO main.go:1234 log message ...
buf := new(bytes.Buffer)
buf.WriteByte(' ')
buf.WriteString(strconv.Itoa(l.pid))
buf.WriteByte(' ')
if l.name != "" {
buf.WriteString(l.name)
buf.WriteByte(' ')
}
if l.goroutineId || l.level == DEBUG {
buf.WriteString(strconv.FormatUint(gls.GoroutineID(), 10))
buf.WriteByte(' ')
}
if l.colorizedLevel {
buf.WriteString(levelStrWithColor[level])
} else {
buf.WriteString(levelStr[level])
}
buf.WriteByte(' ')
buf.WriteString(file)
buf.WriteByte(':')
buf.WriteString(strconv.Itoa(line))
buf.WriteByte(' ')
fmt.Fprintf(buf, msg, args...)
buf.WriteByte('\n')
if level == FATAL {
for i := l.callerSkip; ; i++ {
pc, file, line, ok := runtime.Caller(i)
if !ok {
break
}
fmt.Fprintf(buf, "\tat %s:%d (0x%x)\n", file, line, pc)
}
}
l.mu.Lock()
defer l.mu.Unlock()
timeStr := time.Now().Format(l.timeLayout)
l.out.Write([]byte(timeStr))
l.out.Write(buf.Bytes())
}

@ -0,0 +1,34 @@
package log
import (
"os"
"testing"
"time"
)
func TestLogger(t *testing.T) {
stdout := New(os.Stdout)
stdout.SetTimeLayout("15:04:05.999")
stdout.SetName("main")
stdout.SetLevel(DEBUG)
stdout.EnableColorizedLevel(true)
stdout.EnableGoroutineId(true)
for i := 0; i < 3; i++ {
go func(i int) {
stdout.Debug("i = %d", i)
stdout.Info("i = %d", i)
}(i)
}
for i := 0; i < 3; i++ {
go func(i int) {
stdout.Debug("i = %d", i)
stdout.Info("i = %d", i)
}(i)
}
stdout.Warn("warning")
stdout.Error("error")
stdout.Fatal("fatal")
time.Sleep(1 * time.Second)
}
Loading…
Cancel
Save