func HTTPLoggerFunc(name string, hf http.HandlerFunc) http.Handler {
	return glg.HTTPLoggerFunc(name, hf)
}
HTTPLoggerFunc is simple http access logger
package glg
import (
	"bytes"
	"fmt"
	"io"
	"math"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
	json "github.com/goccy/go-json"
	"github.com/kpango/fastime"
)
type Glg struct {
	bs           *uint64
	logger       loggers
	levelCounter *uint32
	levelMap     levelMap
	buffer       sync.Pool
	callerDepth  int
	enableJSON   bool
}
type JSONFormat struct {
	Date   string      `json:"date,omitempty"`
	Level  string      `json:"level,omitempty"`
	File   string      `json:"file,omitempty"`
	Detail interface{} `json:"detail,omitempty"`
}
type MODE uint8
type LEVEL uint8
type wMode uint8
type traceMode int64
type logger struct {
	tag              string
	rawtag           []byte
	writer           io.Writer
	std              io.Writer
	color            func(string) string
	isColor          bool
	traceMode        traceMode
	mode             MODE
	prevMode         MODE
	writeMode        wMode
	disableTimestamp bool
}
const (
	DEBG LEVEL = iota + 1
	TRACE
	PRINT
	LOG
	INFO
	OK
	WARN
	ERR
	FAIL
	FATAL
	UNKNOWN LEVEL = LEVEL(math.MaxUint8)
	NONE MODE = iota + 1
	STD
	BOTH
	WRITER
	writeColorStd wMode = iota + 1
	writeStd
	writeWriter
	writeColorBoth
	writeBoth
	none
	df = "%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " +
		"%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " +
		"%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " +
		"%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v "
	dfl = len(df) / 3
	timeFormat = "2006-01-02 15:04:05"
	rc  = "\n"
	rcl = len(rc)
	tab   = "\t"
	lsep  = tab + "["
	lsepl = len(lsep)
	sep   = "]:" + tab
	sepl  = len(sep)
	TraceLineNone traceMode = 1 << iota
	TraceLineShort
	TraceLineLong
	DefaultCallerDepth = 2
)
var (
	glg  *Glg
	once sync.Once
	exit = os.Exit
)
func init() {
	Get()
}
func (l LEVEL) String() string {
	switch l {
	case DEBG:
		return "DEBG"
	case TRACE:
		return "TRACE"
	case PRINT:
		return "PRINT"
	case LOG:
		return "LOG"
	case INFO:
		return "INFO"
	case OK:
		return "OK"
	case WARN:
		return "WARN"
	case ERR:
		return "ERR"
	case FAIL:
		return "FAIL"
	case FATAL:
		return "FATAL"
	}
	return ""
}
func (l *logger) updateMode() *logger {
	switch {
	case l.mode == WRITER && l.writer != nil:
		l.writeMode = writeWriter
	case l.mode == BOTH && l.isColor && l.writer != nil:
		l.writeMode = writeColorBoth
	case l.mode == BOTH && !l.isColor && l.writer != nil:
		l.writeMode = writeBoth
	case l.isColor && ((l.mode == BOTH && l.writer == nil) || l.mode == STD):
		l.writeMode = writeColorStd
	case !l.isColor && ((l.mode == BOTH && l.writer == nil) || l.mode == STD):
		l.writeMode = writeStd
	default:
		l.writeMode = none
	}
	return l
}
func New() *Glg {
	g := &Glg{
		levelCounter: new(uint32),
		callerDepth:  DefaultCallerDepth,
	}
	g.bs = new(uint64)
	atomic.StoreUint64(g.bs, uint64(len(timeFormat)+lsepl+sepl))
	g.buffer = sync.Pool{
		New: func() interface{} {
			return bytes.NewBuffer(make([]byte, 0, int(atomic.LoadUint64(g.bs))))
		},
	}
	atomic.StoreUint32(g.levelCounter, uint32(FATAL))
	for lev, log := range map[LEVEL]*logger{
		DEBG: {
			std:       os.Stdout,
			color:     Purple,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		TRACE: {
			std:       os.Stdout,
			color:     Yellow,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		PRINT: {
			std:       os.Stdout,
			color:     Colorless,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		LOG: {
			std:       os.Stdout,
			color:     Colorless,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		INFO: {
			std:       os.Stdout,
			color:     Green,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		OK: {
			std:       os.Stdout,
			color:     Cyan,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		WARN: {
			std:       os.Stdout,
			color:     Orange,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineNone,
		},
		ERR: {
			std:       os.Stderr,
			color:     Red,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineShort,
		},
		FAIL: {
			std:       os.Stderr,
			color:     Red,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineShort,
		},
		FATAL: {
			std:       os.Stderr,
			color:     Red,
			isColor:   true,
			mode:      STD,
			traceMode: TraceLineLong,
		},
	} {
		log.tag = lev.String()
		log.rawtag = []byte(lsep + log.tag + sep)
		log.prevMode = log.mode
		log.updateMode()
		g.logger.Store(lev, log)
	}
	return g
}
func Get() *Glg {
	once.Do(func() {
		fastime.SetFormat(timeFormat)
		glg = New()
	})
	return glg
}
func (g *Glg) EnableJSON() *Glg {
	g.enableJSON = true
	return g
}
func (g *Glg) DisableJSON() *Glg {
	g.enableJSON = false
	return g
}
func (g *Glg) EnablePoolBuffer(size int) *Glg {
	for range make([]struct{}, size) {
		g.buffer.Put(g.buffer.Get().(*bytes.Buffer))
	}
	return g
}
func (g *Glg) SetLevel(lv LEVEL) *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		if lev < lv {
			l.prevMode = l.mode
			l.mode = NONE
		} else {
			l.mode = l.prevMode
		}
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) SetMode(mode MODE) *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.mode = mode
		l.prevMode = mode
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) SetLevelMode(level LEVEL, mode MODE) *Glg {
	l, ok := g.logger.Load(level)
	if ok {
		l.mode = mode
		l.prevMode = mode
		l.updateMode()
		g.logger.Store(level, l)
	}
	return g
}
func SetPrefix(lev LEVEL, pref string) *Glg {
	return glg.SetPrefix(lev, pref)
}
func (g *Glg) SetPrefix(lev LEVEL, pref string) *Glg {
	l, ok := g.logger.Load(lev)
	if ok {
		l.tag = pref
		l.rawtag = []byte(lsep + l.tag + sep)
		g.logger.Store(lev, l)
	}
	return g
}
func (g *Glg) GetCurrentMode(level LEVEL) MODE {
	l, ok := g.logger.Load(level)
	if ok {
		return l.mode
	}
	return NONE
}
func (g *Glg) InitWriter() *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.writer = nil
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) SetWriter(writer io.Writer) *Glg {
	if writer == nil {
		return g
	}
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.writer = writer
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) AddWriter(writer io.Writer) *Glg {
	if writer == nil {
		return g
	}
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		if l.writer == nil {
			l.writer = writer
		} else {
			l.writer = io.MultiWriter(l.writer, writer)
		}
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) SetLevelColor(level LEVEL, color func(string) string) *Glg {
	l, ok := g.logger.Load(level)
	if ok {
		l.color = color
		g.logger.Store(level, l)
	}
	return g
}
func (g *Glg) SetLevelWriter(level LEVEL, writer io.Writer) *Glg {
	if writer == nil {
		return g
	}
	l, ok := g.logger.Load(level)
	if ok {
		l.writer = writer
		l.updateMode()
		g.logger.Store(level, l)
	}
	return g
}
func (g *Glg) AddLevelWriter(level LEVEL, writer io.Writer) *Glg {
	if writer == nil {
		return g
	}
	l, ok := g.logger.Load(level)
	if ok {
		if l.writer != nil {
			l.writer = io.MultiWriter(l.writer, writer)
		} else {
			l.writer = writer
		}
		l.updateMode()
		g.logger.Store(level, l)
	}
	return g
}
func (g *Glg) AddStdLevel(tag string, mode MODE, isColor bool) *Glg {
	return g.addLevel(tag, mode, isColor, os.Stdout)
}
func (g *Glg) AddErrLevel(tag string, mode MODE, isColor bool) *Glg {
	return g.addLevel(tag, mode, isColor, os.Stderr)
}
func (g *Glg) addLevel(tag string, mode MODE, isColor bool, std io.Writer) *Glg {
	lev := LEVEL(atomic.AddUint32(g.levelCounter, 1))
	tag = strings.ToUpper(tag)
	g.levelMap.Store(tag, lev)
	l := &logger{
		writer:   nil,
		std:      std,
		color:    Colorless,
		isColor:  isColor,
		mode:     mode,
		prevMode: mode,
		tag:      tag,
		rawtag:   []byte(lsep + tag + sep),
	}
	l.updateMode()
	g.logger.Store(lev, l)
	return g
}
func (g *Glg) EnableTimestamp() *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.disableTimestamp = false
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) DisableTimestamp() *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.disableTimestamp = true
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) EnableLevelTimestamp(lv LEVEL) *Glg {
	l, ok := g.logger.Load(lv)
	if ok {
		l.disableTimestamp = false
		g.logger.Store(lv, l)
	}
	return g
}
func (g *Glg) DisableLevelTimestamp(lv LEVEL) *Glg {
	l, ok := g.logger.Load(lv)
	if ok {
		l.disableTimestamp = true
		g.logger.Store(lv, l)
	}
	return g
}
func (g *Glg) SetCallerDepth(depth int) *Glg {
	if depth > DefaultCallerDepth {
		g.callerDepth = depth
	}
	return g
}
func (g *Glg) SetLineTraceMode(mode traceMode) *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.traceMode = mode
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) SetLevelLineTraceMode(lv LEVEL, mode traceMode) *Glg {
	l, ok := g.logger.Load(lv)
	if ok {
		l.traceMode = mode
		g.logger.Store(lv, l)
	}
	return g
}
func (g *Glg) EnableColor() *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.isColor = true
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) DisableColor() *Glg {
	g.logger.Range(func(lev LEVEL, l *logger) bool {
		l.isColor = false
		l.updateMode()
		g.logger.Store(lev, l)
		return true
	})
	return g
}
func (g *Glg) EnableLevelColor(lv LEVEL) *Glg {
	l, ok := g.logger.Load(lv)
	if ok {
		l.isColor = true
		l.updateMode()
		g.logger.Store(lv, l)
	}
	return g
}
func (g *Glg) DisableLevelColor(lv LEVEL) *Glg {
	l, ok := g.logger.Load(lv)
	if ok {
		l.isColor = false
		l.updateMode()
		g.logger.Store(lv, l)
	}
	return g
}
func (g *Glg) RawString(data []byte) string {
	str := *(*string)(unsafe.Pointer(&data))
	return str[strings.Index(str, sep)+sepl : len(str)-rcl]
}
func RawString(data []byte) string {
	return glg.RawString(data)
}
func (g *Glg) Atol(tag string) LEVEL {
	return g.TagStringToLevel(tag)
}
func Atol(tag string) LEVEL {
	return glg.TagStringToLevel(tag)
}
func (g *Glg) TagStringToLevel(tag string) LEVEL {
	tag = strings.TrimSpace(strings.ToUpper(tag))
	lv, ok := g.levelMap.Load(tag)
	if ok {
		return lv
	}
	switch tag {
	case DEBG.String(), "DBG", "DEBUG", "D":
		return DEBG
	case TRACE.String(), "TRC", "TRA", "TR", "T":
		return TRACE
	case PRINT.String(), "PRINT", "PNT", "P":
		return PRINT
	case LOG.String(), "LO", "LG", "L":
		return LOG
	case INFO.String(), "IFO", "INF", "I":
		return INFO
	case OK.String(), "O", "K":
		return OK
	case WARN.String(), "WARNING", "WRN", "W":
		return WARN
	case ERR.String(), "ERROR", "ER", "E":
		return ERR
	case FAIL.String(), "FAILED", "FI":
		return FAIL
	case FATAL.String(), "FAT", "FL", "F":
		return FATAL
	}
	return UNKNOWN
}
func TagStringToLevel(tag string) LEVEL {
	return glg.TagStringToLevel(tag)
}
func FileWriter(path string, perm os.FileMode) *os.File {
	if path == "" {
		return nil
	}
	var err error
	var file *os.File
	if _, err = os.Stat(path); err != nil {
		if _, err = os.Stat(filepath.Dir(path)); err != nil {
			err = os.MkdirAll(filepath.Dir(path), perm)
			if err != nil {
				return nil
			}
		}
		file, err = os.Create(path)
		if err != nil {
			return nil
		}
		err = file.Close()
		if err != nil {
			return nil
		}
	}
	file, err = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, perm)
	if err != nil {
		return nil
	}
	return file
}
func (g *Glg) HTTPLogger(name string, handler http.Handler) http.Handler {
	return g.HTTPLoggerFunc(name, handler.ServeHTTP)
}
func (g *Glg) HTTPLoggerFunc(name string, hf http.HandlerFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := fastime.UnixNanoNow()
		hf(w, r)
		start -= fastime.UnixNanoNow()
		err := g.Logf("Method: %s\tURI: %s\tName: %s\tTime: %s",
			r.Method, r.RequestURI, name, (*(*time.Duration)(unsafe.Pointer(&start))).String())
		if err != nil {
			err = g.Error(err)
			if err != nil {
				fmt.Println(err)
			}
		}
	})
}
func HTTPLogger(name string, handler http.Handler) http.Handler {
	return glg.HTTPLogger(name, handler)
}