You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Logkit/gokit.go

351 lines
6.7 KiB

6 years ago
package logkit
import (
5 years ago
"flag"
6 years ago
"fmt"
"io"
5 years ago
"path"
"runtime"
5 years ago
"strconv"
"strings"
6 years ago
"time"
)
var (
5 years ago
inited bool
auto bool
logWriter io.Writer
flushInterval time.Duration
fileSplitSize uint64
logLevel = LevelInfo
logLevelName string
logName string
logPath string
channel Channel
alsoStdout bool
withCaller Caller
6 years ago
levelToNames = map[Level]string{
LevelFatal: "FATAL",
LevelError: "ERROR",
LevelWarn: "WARN",
LevelInfo: "INFO",
LevelDebug: "DEBUG",
LevelTrace: "TRACE",
}
)
//Level 日志等级
5 years ago
type Level int
6 years ago
const (
Default Level = iota
LevelTrace
LevelDebug
LevelInfo
LevelWarn
LevelError
LevelFatal
)
6 years ago
5 years ago
func (l *Level) String() string {
return levelToNames[*l]
}
// Get is part of the flag.Value interface.
func (l *Level) Get() interface{} {
return *l
}
func (l *Level) Set(value string) error {
for i, name := range levelToNames {
if strings.ToUpper(value) == name {
*l = i
}
}
if *l == Default {
v, err := strconv.Atoi(value)
if err != nil {
return err
}
*l = Level(v)
}
if *l == Default {
*l = LevelDebug
}
return nil
}
6 years ago
type Channel byte
6 years ago
6 years ago
const (
FIlE Channel = iota
SYSLOG
KAFKA
)
6 years ago
5 years ago
func (c *Channel) String() string {
switch *c {
case FIlE:
return "file"
case SYSLOG:
return "syslog"
}
return "file"
}
func (c *Channel) Set(value string) error {
switch value {
case "file":
*c = FIlE
case "syslog":
*c = SYSLOG
default:
*c = FIlE
}
return nil
}
type Caller byte
5 years ago
const (
_ Caller = iota
NONE
5 years ago
FullPATHFunc
BasePathFunc
BasePath
5 years ago
)
5 years ago
func (c *Caller) String() string {
switch *c {
case NONE:
return "none"
case FullPATHFunc:
return "full"
case BasePathFunc:
return "file_func"
case BasePath:
return "file"
}
return "file"
}
func (c *Caller) Set(value string) error {
switch value {
case "file":
*c = BasePath
case "file_func":
*c = BasePathFunc
case "full":
*c = FullPATHFunc
default:
*c = BasePathFunc
}
return nil
}
6 years ago
type Writer interface {
//Write 写日志
5 years ago
Write(msg []byte) (int, error)
6 years ago
//Exit 日志退出
5 years ago
Close() error
6 years ago
}
func GetWriter()( io.Writer, error) {
if logWriter == nil {
return nil, fmt.Errorf("logkit not inited")
}
return logWriter, nil
5 years ago
}
6 years ago
func Exit() {
5 years ago
if logWriter == nil {
return
}
5 years ago
logWriter.(io.Closer).Close()
6 years ago
}
5 years ago
func init() {
flag.Var(&logLevel, "log.level", "log level, default `INFO`, it can be `DEBUG, INFO, WARN, ERROR, FATAL`")
flag.Var(&channel, "log.channel", "write to , it can be `file syslog`")
5 years ago
flag.Var(&withCaller, "log.withCaller", "call context, by default filename and func name, it can be `file, file_func, full`")
flag.BoolVar(&alsoStdout, "log.alsoStdout", false, "log out to stand error as well, default `false`")
flag.StringVar(&logName, "log.name", "log", "log name, by default log will out to `/data/logs/{name}.log`")
flag.BoolVar(&auto, "log.autoInit", true, "log will be init automatic")
flag.DurationVar(&flushInterval, "log.interval", time.Second*5, "duration time on flush to disk")
flag.Uint64Var(&fileSplitSize, "log.split", uint64(1204*1024*1800), "log fail split on bytes")
5 years ago
}
//SetDebug set logger debug output
func SetDebug(debug bool) {
if debug {
alsoStdout = true
withCaller = BasePathFunc
logLevel = LevelDebug
}
}
5 years ago
func Init() (writer io.Writer, err error) {
6 years ago
if inited {
5 years ago
return nil, fmt.Errorf("logkit has been inited")
6 years ago
}
5 years ago
if logName == "" {
5 years ago
return nil, fmt.Errorf("log name must not be empty")
6 years ago
}
5 years ago
if logWriter == nil && channel == FIlE {
if logPath == "" {
logPath = "/data/logs/" + logName + ".log"
}
5 years ago
logWriter, err = NewFileLogger(logPath, logName, flushInterval, fileSplitSize, 4*1024)
if err != nil {
return
}
5 years ago
}
if logWriter == nil && channel == SYSLOG {
5 years ago
logWriter, _ = NewSyslogWriter("", "", logLevel, logName)
5 years ago
}
inited = true
return logWriter, nil
6 years ago
}
6 years ago
func SetPath(path string) {
logPath = path
}
6 years ago
func getLevelName(level Level) string {
levelName, _ := levelToNames[level]
return levelName
}
func format(level Level, msg string) string {
5 years ago
if withCaller != NONE {
var (
context string
pc uintptr
file string
line int
)
pc, file, line, _ = runtime.Caller(3)
5 years ago
switch withCaller {
case FullPATHFunc:
context = fmt.Sprintf("%s:%03d::%-30s", file, line, path.Base(runtime.FuncForPC(pc).Name()))
5 years ago
case BasePathFunc:
context = fmt.Sprintf("%s:%03d::%-15s", path.Base(file), line, path.Base(runtime.FuncForPC(pc).Name()))
5 years ago
case BasePath:
5 years ago
context = fmt.Sprintf("%s:%03d", path.Base(file), line)
5 years ago
default:
5 years ago
context = fmt.Sprintf("%s:%03d", path.Base(file), line)
5 years ago
}
5 years ago
5 years ago
return fmt.Sprintf("%s\t[%4s]\t%s\t%s\n", time.Now().Format("2006-01-02 15:04:05.999"), getLevelName(level), context, msg)
} else {
5 years ago
return fmt.Sprintf("%s\t[%4s]\t%s\n", time.Now().Format("2006-01-02 15:04:05.999"), getLevelName(level), msg)
}
6 years ago
}
5 years ago
func write(level Level, msg string) (err error) {
if !flag.Parsed() {
return fmt.Errorf("logkit write must been flag parsed")
}
if auto && !inited {
Init()
}
6 years ago
if !inited {
5 years ago
return fmt.Errorf("logkit has been inited")
6 years ago
}
messageStr := format(level, msg)
5 years ago
_, err = logWriter.Write([]byte(messageStr))
6 years ago
if alsoStdout {
5 years ago
fmt.Print(messageStr)
6 years ago
}
5 years ago
return
6 years ago
}
func level() Level {
return logLevel
}
func Debug(str string) {
if level() <= LevelDebug {
write(LevelDebug, str)
}
}
func Debugs(args ...interface{}) {
if level() <= LevelDebug {
write(LevelDebug, fmt.Sprintln(args...))
}
}
func Debugf(format string, args ...interface{}) {
if level() <= LevelDebug {
write(LevelDebug, fmt.Sprintf(format, args...))
}
}
func Info(str string) {
if level() <= LevelInfo {
write(LevelInfo, str)
}
}
func Infos(args ...interface{}) {
if level() <= LevelInfo {
write(LevelInfo, fmt.Sprintln(args...))
}
}
func Infof(format string, args ...interface{}) {
if level() <= LevelInfo {
write(LevelInfo, fmt.Sprintf(format, args...))
}
}
func Warn(str string) {
if level() <= LevelWarn {
write(LevelWarn, str)
}
}
func Warns(args ...interface{}) {
if level() <= LevelWarn {
write(LevelWarn, fmt.Sprintln(args...))
}
}
func Warnf(format string, args ...interface{}) {
if level() <= LevelWarn {
write(LevelWarn, fmt.Sprintf(format, args...))
}
}
func Error(str string) {
if level() <= LevelError {
write(LevelError, str)
}
}
func Errors(args ...interface{}) {
if level() <= LevelError {
write(LevelError, fmt.Sprintln(args...))
}
}
func Errorf(format string, args ...interface{}) {
if level() <= LevelError {
write(LevelError, fmt.Sprintf(format, args...))
}
}
func NewLogWriter(level Level) io.Writer {
return &stdWriter{level}
}
type stdWriter struct {
level Level
}
func (this *stdWriter) Write(data []byte) (int, error) {
write(this.level, string(data))
return len(data), nil
}