重构并优化日志库

This commit is contained in:
boyce
2021-07-01 14:03:03 +08:00
parent 745caa88de
commit 7392d90ef2
2 changed files with 412 additions and 64 deletions

91
log/buffer.go Normal file
View File

@@ -0,0 +1,91 @@
package log // import "go.uber.org/zap/buffer"
import "strconv"
const _size = 9216
type Buffer struct {
bs []byte
}
func (buff *Buffer) Init(){
buff.bs = make([]byte,_size)
}
// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
b.bs = append(b.bs, v)
}
func (b *Buffer) AppendBytes(v []byte) {
b.bs = append(b.bs, v...)
}
// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
b.bs = append(b.bs, s...)
}
// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
b.bs = strconv.AppendInt(b.bs, i, 10)
}
// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
b.bs = strconv.AppendUint(b.bs, i, 10)
}
// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
b.bs = strconv.AppendBool(b.bs, v)
}
// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}
// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
return len(b.bs)
}
// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
return cap(b.bs)
}
// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
return b.bs
}
// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
return string(b.bs)
}
// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
b.bs = b.bs[:0]
}
// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
b.bs = append(b.bs, bs...)
return len(bs), nil
}
// TrimNewline trims any final "\n" byte from the end of the buffer.
func (b *Buffer) TrimNewline() {
if i := len(b.bs) - 1; i >= 0 {
if b.bs[i] == '\n' {
b.bs = b.bs[:i]
}
}
}

View File

@@ -9,9 +9,15 @@ import (
"runtime/debug"
"strings"
"time"
"sync"
"io"
"runtime"
syslog "log"
jsoniter "github.com/json-iterator/go"
)
var OpenConsole bool = true
var json = jsoniter.ConfigCompatibleWithStandardLibrary
var OpenConsole bool
// levels
const (
@@ -35,15 +41,50 @@ const (
type Logger struct {
filePath string
filepre string
logTime time.Time
//logTime time.Time
fileDay int
level int
stdLogger *log.Logger
baseLogger *log.Logger
baseFile *os.File
flag int
buf Buffer
outFile io.Writer // destination for output
outConsole io.Writer //os.Stdout
mu sync.Mutex // ensures atomic writes; protects the following fields
}
func New(strLevel string, pathname string, filepre string, flag int) (*Logger, error) {
func (logger *Logger) GenDayFile(now *time.Time) error {
if logger.fileDay == now.Day() {
return nil
}
filename := fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d.log",
now.Year(),
now.Month(),
now.Day(),
now.Hour(),
now.Minute(),
now.Second())
if logger.filePath != "" {
var err error
logger.outFile,err = os.Create(path.Join(logger.filePath, logger.filepre+filename))
if err != nil {
return err
}
logger.fileDay = now.Day()
if OpenConsole == true {
logger.outConsole = os.Stdout
}
}else{
logger.outConsole = os.Stdout
}
return nil
}
func New(strLevel string, pathName string, filePre string, flag int) (*Logger, error) {
// level
var level int
switch strings.ToLower(strLevel) {
@@ -63,88 +104,213 @@ func New(strLevel string, pathname string, filepre string, flag int) (*Logger, e
return nil, errors.New("unknown level: " + strLevel)
}
// logger
var baseLogger *log.Logger
var baseFile *os.File
now := time.Now()
if pathname != "" {
filename := fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d.log",
now.Year(),
now.Month(),
now.Day(),
now.Hour(),
now.Minute(),
now.Second())
file, err := os.Create(path.Join(pathname, filepre+filename))
if err != nil {
return nil, err
}
baseLogger = log.New(file, "", flag)
baseFile = file
} else {
baseLogger = log.New(os.Stdout, "", flag)
OpenConsole = false
}
// new
logger := new(Logger)
logger.level = level
logger.stdLogger = log.New(os.Stdout, "", flag)
logger.baseLogger = baseLogger
logger.baseFile = baseFile
logger.logTime = now
logger.filePath = pathname
logger.filePath = pathName
logger.filepre = filePre
logger.flag = flag
logger.filepre = filepre
logger.buf.Init()
now := time.Now()
err := logger.GenDayFile(&now)
if err != nil {
return nil,err
}
return logger, nil
}
// It's dangerous to call the method on logging
func (logger *Logger) Close() {
if logger.baseFile != nil {
logger.baseFile.Close()
if logger.outFile != nil {
logger.outFile.(io.Closer).Close()
logger.outFile = nil
}
logger.baseLogger = nil
logger.baseFile = nil
}
func (logger *Logger) doPrintf(level int, printLevel string, format string, a ...interface{}) {
if level < logger.level {
return
}
if logger.baseLogger == nil {
panic("logger closed")
now := time.Now()
logger.mu.Lock()
logger.GenDayFile(&now)
logger.buf.Reset()
logger.formatHeader(3,&now)
logger.buf.AppendString(printLevel)
logger.buf.AppendString(fmt.Sprintf(format, a...))
logger.buf.AppendByte('\n')
if logger.outFile!= nil {
logger.outFile.Write(logger.buf.Bytes())
}
if logger.outConsole!= nil {
logger.outConsole.Write(logger.buf.Bytes())
}
logger.mu.Unlock()
if level == fatalLevel {
os.Exit(1)
}
}
if logger.baseFile != nil {
now := time.Now()
if now.Day() != logger.logTime.Day() {
filename := fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d.log",
now.Year(),
now.Month(),
now.Day(),
now.Hour(),
now.Minute(),
now.Second())
file, err := os.Create(path.Join(logger.filePath, logger.filepre+filename))
if err == nil {
logger.baseFile.Close()
logger.baseLogger = log.New(file, "", logger.flag)
logger.baseFile = file
logger.logTime = now
func (logger *Logger) doSPrintf(level int, printLevel string, a []interface{}) {
if level < logger.level {
return
}
now := time.Now()
logger.mu.Lock()
logger.GenDayFile(&now)
logger.buf.Reset()
logger.formatHeader(3,&now)
logger.buf.AppendString(printLevel)
for _,s := range a {
switch s.(type) {
case int:
logger.buf.AppendInt(int64(s.(int)))
case int8:
logger.buf.AppendInt(int64(s.(int8)))
case int16:
logger.buf.AppendInt(int64(s.(int16)))
case int32:
logger.buf.AppendInt(int64(s.(int32)))
case int64:
logger.buf.AppendInt(s.(int64))
case uint:
logger.buf.AppendUint(uint64(s.(uint)))
case uint8:
logger.buf.AppendUint(uint64(s.(uint8)))
case uint16:
logger.buf.AppendUint(uint64(s.(uint16)))
case uint32:
logger.buf.AppendUint(uint64(s.(uint32)))
case uint64:
logger.buf.AppendUint(s.(uint64))
case float32:
logger.buf.AppendFloat(float64(s.(float32)),32)
case float64:
logger.buf.AppendFloat(s.(float64),64)
case bool:
logger.buf.AppendBool(s.(bool))
case string:
logger.buf.AppendString(s.(string))
case *int:
val := s.(*int)
if val != nil {
logger.buf.AppendInt(int64(*val))
}else{
logger.buf.AppendString("nil<*int>")
}
case *int8:
val := s.(*int8)
if val != nil {
logger.buf.AppendInt(int64(*val))
}else{
logger.buf.AppendString("nil<*int8>")
}
case *int16:
val := s.(*int16)
if val != nil {
logger.buf.AppendInt(int64(*val))
}else{
logger.buf.AppendString("nil<*int16>")
}
case *int32:
val := s.(*int32)
if val != nil {
logger.buf.AppendInt(int64(*val))
}else{
logger.buf.AppendString("nil<*int32>")
}
case *int64:
val := s.(*int64)
if val != nil {
logger.buf.AppendInt(int64(*val))
}else{
logger.buf.AppendString("nil<*int64>")
}
case *uint:
val := s.(*uint)
if val != nil {
logger.buf.AppendUint(uint64(*val))
}else{
logger.buf.AppendString("nil<*uint>")
}
case *uint8:
val := s.(*uint8)
if val != nil {
logger.buf.AppendUint(uint64(*val))
}else{
logger.buf.AppendString("nil<*uint8>")
}
case *uint16:
val := s.(*uint16)
if val != nil {
logger.buf.AppendUint(uint64(*val))
}else{
logger.buf.AppendString("nil<*uint16>")
}
case *uint32:
val := s.(*uint32)
if val != nil {
logger.buf.AppendUint(uint64(*val))
}else{
logger.buf.AppendString("nil<*uint32>")
}
case *uint64:
val := s.(*uint64)
if val != nil {
logger.buf.AppendUint(uint64(*val))
}else{
logger.buf.AppendString("nil<*uint64>")
}
case *float32:
val := s.(*float32)
if val != nil {
logger.buf.AppendFloat(float64(*val),32)
}else{
logger.buf.AppendString("nil<*float32>")
}
case *float64:
val := s.(*float32)
if val != nil {
logger.buf.AppendFloat(float64(*val),64)
}else{
logger.buf.AppendString("nil<*float64>")
}
case *bool:
val := s.(*bool)
if val != nil {
logger.buf.AppendBool(*val)
}else{
logger.buf.AppendString("nil<*bool>")
}
case *string:
val := s.(*string)
if val != nil {
logger.buf.AppendString(*val)
}else{
logger.buf.AppendString("nil<*string>")
}
default:
b,err := json.Marshal(s)
if err != nil {
logger.buf.AppendString("<unknown type>")
}else{
logger.buf.AppendBytes(b)
}
}
}
format = printLevel + format
logger.baseLogger.Output(3, fmt.Sprintf(format, a...))
if OpenConsole == true {
logger.stdLogger.Output(3, fmt.Sprintf(format, a...))
logger.buf.AppendByte('\n')
if logger.outFile!= nil {
logger.outFile.Write(logger.buf.Bytes())
}
if logger.outConsole!= nil {
logger.outConsole.Write(logger.buf.Bytes())
}
logger.mu.Unlock()
if level == fatalLevel {
os.Exit(1)
}
@@ -211,3 +377,94 @@ func Fatal(format string, a ...interface{}) {
func Close() {
gLogger.Close()
}
func SDebug(a ...interface{}) {
gLogger.doSPrintf(debugLevel, printDebugLevel, a)
}
func SRelease(a ...interface{}) {
gLogger.doSPrintf(releaseLevel, printReleaseLevel, a)
}
func SWarning(a ...interface{}) {
gLogger.doSPrintf(warningLevel, printWarningLevel, a)
}
func SError(a ...interface{}) {
gLogger.doSPrintf(errorLevel, printErrorLevel, a)
}
func SStack(a ...interface{}) {
gLogger.doSPrintf(stackLevel, printStackLevel, a)
gLogger.doSPrintf(stackLevel, printStackLevel, []interface{}{string(debug.Stack())})
}
func SFatal(a ...interface{}) {
gLogger.doSPrintf(fatalLevel, printFatalLevel, a)
}
const timeFlag = syslog.Ldate|syslog.Ltime|syslog.Lmicroseconds
func (l *Logger) formatHeader(calldepth int,t *time.Time) {
var file string
var line int
if l.flag&(syslog.Lshortfile|syslog.Llongfile) != 0 {
// Release lock while getting caller info - it's expensive.
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
}
if l.flag&syslog.Lmsgprefix != 0 {
l.buf.AppendString(l.filepre)
}
if l.flag&timeFlag != 0 {
if l.flag&syslog.Ldate != 0 {
year, month, day := t.Date()
l.buf.AppendInt(int64(year))
l.buf.AppendByte('/')
l.buf.AppendInt(int64(month))
l.buf.AppendByte('/')
l.buf.AppendInt(int64(day))
l.buf.AppendByte(' ')
}
if l.flag&(syslog.Ltime|syslog.Lmicroseconds) != 0 {
hour, min, sec := t.Clock()
l.buf.AppendInt(int64(hour))
l.buf.AppendByte(':')
l.buf.AppendInt(int64(min))
l.buf.AppendByte(':')
l.buf.AppendInt(int64(sec))
if l.flag&syslog.Lmicroseconds != 0 {
l.buf.AppendByte('.')
l.buf.AppendInt(int64(t.Nanosecond()/1e3))
}
l.buf.AppendByte(' ')
}
}
if l.flag&(syslog.Lshortfile|syslog.Llongfile) != 0 {
if l.flag&syslog.Lshortfile != 0 {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
file = short
}
l.buf.AppendString(file)
l.buf.AppendByte(':')
l.buf.AppendInt(int64(line))
l.buf.AppendString(": ")
}
if l.flag&syslog.Lmsgprefix != 0 {
l.buf.AppendString(l.filepre)
}
}