|
|
@ -1,23 +1,29 @@ |
|
|
|
package logkit |
|
|
|
package logkit |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
|
|
|
|
"flag" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"path" |
|
|
|
"path" |
|
|
|
"runtime" |
|
|
|
"runtime" |
|
|
|
|
|
|
|
"strconv" |
|
|
|
|
|
|
|
"strings" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
inited bool |
|
|
|
inited bool |
|
|
|
logWriter io.Writer |
|
|
|
auto bool |
|
|
|
logLevel = LevelInfo |
|
|
|
logWriter io.Writer |
|
|
|
logLevelName string |
|
|
|
flushInterval time.Duration |
|
|
|
logName string |
|
|
|
fileSplitSize uint64 |
|
|
|
logPath string |
|
|
|
logLevel = LevelInfo |
|
|
|
channel Channel |
|
|
|
logLevelName string |
|
|
|
alsoStdout bool |
|
|
|
logName string |
|
|
|
withCaller Caller |
|
|
|
logPath string |
|
|
|
|
|
|
|
channel Channel |
|
|
|
|
|
|
|
alsoStdout bool |
|
|
|
|
|
|
|
withCaller Caller |
|
|
|
|
|
|
|
|
|
|
|
levelToNames = map[Level]string{ |
|
|
|
levelToNames = map[Level]string{ |
|
|
|
LevelFatal: "FATAL", |
|
|
|
LevelFatal: "FATAL", |
|
|
@ -42,8 +48,35 @@ const ( |
|
|
|
LevelFatal |
|
|
|
LevelFatal |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type Channel byte |
|
|
|
type Channel byte |
|
|
|
type Caller byte |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
const ( |
|
|
|
FIlE Channel = iota |
|
|
|
FIlE Channel = iota |
|
|
@ -51,6 +84,29 @@ const ( |
|
|
|
KAFKA |
|
|
|
KAFKA |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
const ( |
|
|
|
_ Caller = iota |
|
|
|
_ Caller = iota |
|
|
|
NONE |
|
|
|
NONE |
|
|
@ -59,6 +115,33 @@ const ( |
|
|
|
BasePath |
|
|
|
BasePath |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type Writer interface { |
|
|
|
type Writer interface { |
|
|
|
//Write 写日志
|
|
|
|
//Write 写日志
|
|
|
|
Write(msg []byte) (int, error) |
|
|
|
Write(msg []byte) (int, error) |
|
|
@ -66,36 +149,50 @@ type Writer interface { |
|
|
|
Close() error |
|
|
|
Close() error |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func GetWriter() io.Closer { |
|
|
|
|
|
|
|
return logWriter.(io.Closer) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func Exit() { |
|
|
|
func Exit() { |
|
|
|
|
|
|
|
if logWriter == nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
logWriter.(io.Closer).Close() |
|
|
|
logWriter.(io.Closer).Close() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func Init(_channel Channel, name string, level Level, _alsoStdout bool, _withCaller Caller) (writer io.Writer, err error ){ |
|
|
|
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`") |
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func Init() (writer io.Writer, err error) { |
|
|
|
if inited { |
|
|
|
if inited { |
|
|
|
return nil, fmt.Errorf("logkit has been inited") |
|
|
|
return nil, fmt.Errorf("logkit has been inited") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if name != "" { |
|
|
|
if logName == "" { |
|
|
|
logName = name |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return nil, fmt.Errorf("log name must not be empty") |
|
|
|
return nil, fmt.Errorf("log name must not be empty") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if logWriter == nil && channel == FIlE { |
|
|
|
if logWriter == nil && channel == FIlE { |
|
|
|
if logPath == "" { |
|
|
|
if logPath == "" { |
|
|
|
logPath = "/data/logs/" + logName + ".log" |
|
|
|
logPath = "/data/logs/" + logName + ".log" |
|
|
|
} |
|
|
|
} |
|
|
|
logWriter = NewFileLogger(logPath, logName, time.Second*5, 1204*1024*1800, 4*1024) |
|
|
|
logWriter, err = NewFileLogger(logPath, logName, flushInterval, fileSplitSize, 4*1024) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if logWriter == nil && channel == SYSLOG { |
|
|
|
if logWriter == nil && channel == SYSLOG { |
|
|
|
logWriter, _ = NewSyslogWriter("", "", level, logName) |
|
|
|
logWriter, _ = NewSyslogWriter("", "", logLevel, logName) |
|
|
|
} |
|
|
|
} |
|
|
|
inited = true |
|
|
|
inited = true |
|
|
|
|
|
|
|
|
|
|
|
logLevel = level |
|
|
|
|
|
|
|
channel = _channel |
|
|
|
|
|
|
|
alsoStdout = _alsoStdout |
|
|
|
|
|
|
|
withCaller = _withCaller |
|
|
|
|
|
|
|
return logWriter, nil |
|
|
|
return logWriter, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -118,16 +215,16 @@ func format(level Level, msg string) string { |
|
|
|
pc, file, line, _ = runtime.Caller(3) |
|
|
|
pc, file, line, _ = runtime.Caller(3) |
|
|
|
switch withCaller { |
|
|
|
switch withCaller { |
|
|
|
case FullPATHFunc: |
|
|
|
case FullPATHFunc: |
|
|
|
context = fmt.Sprintf("%s:%03d::%s", file, line, path.Base(runtime.FuncForPC(pc).Name())) |
|
|
|
context = fmt.Sprintf("%s:%03d::%30s", file, line, path.Base(runtime.FuncForPC(pc).Name())) |
|
|
|
case BasePathFunc: |
|
|
|
case BasePathFunc: |
|
|
|
context = fmt.Sprintf("%s:%03d::%s", path.Base(file), line, path.Base(runtime.FuncForPC(pc).Name())) |
|
|
|
context = fmt.Sprintf("%s:%03d::%30s", path.Base(file), line, path.Base(runtime.FuncForPC(pc).Name())) |
|
|
|
case BasePath: |
|
|
|
case BasePath: |
|
|
|
context = fmt.Sprintf("%s:%03d", path.Base(file), line) |
|
|
|
context = fmt.Sprintf("%s:%03d", path.Base(file), line) |
|
|
|
default: |
|
|
|
default: |
|
|
|
context = fmt.Sprintf("%s:%03d", path.Base(file), line) |
|
|
|
context = fmt.Sprintf("%s:%03d", path.Base(file), line) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s\t[%4s]\t%-20.64s\t%s\n", time.Now().Format("2006-01-02 15:04:05.999"), getLevelName(level), context, msg) |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
return fmt.Sprintf("%s\t[%4s]\t%s\n", time.Now().Format("2006-01-02 15:04:05.999"), getLevelName(level), msg) |
|
|
|
return fmt.Sprintf("%s\t[%4s]\t%s\n", time.Now().Format("2006-01-02 15:04:05.999"), getLevelName(level), msg) |
|
|
|
} |
|
|
|
} |
|
|
|