| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- package logger
- import (
- "context"
- "fmt"
- "log"
- "os"
- "runtime"
- "sort"
- "strings"
- "sync"
- "time"
- dlog "IotAdmin/core/debug/log"
- )
- func init() {
- lvl, err := GetLevel(os.Getenv("IOT_ADMIN_LOG_LEVEL"))
- if err != nil {
- lvl = InfoLevel
- }
- DefaultLogger = NewHelper(NewLogger(WithLevel(lvl)))
- }
- type defaultLogger struct {
- sync.RWMutex
- opts Options
- }
- // Init (opts...) should only overwrite provided options
- func (l *defaultLogger) Init(opts ...Option) error {
- for _, o := range opts {
- o(&l.opts)
- }
- return nil
- }
- func (l *defaultLogger) String() string {
- return "default"
- }
- func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
- l.Lock()
- l.opts.Fields = copyFields(fields)
- l.Unlock()
- return l
- }
- // logCallerFilePath 返回调用程序的package/file:line描述,只保留叶目录名和文件名。
- func logCallerFilePath(loggingFilePath string) string {
- // To make sure we trim the path correctly on Windows too, we
- // counter-intuitively need to use '/' and *not* os.PathSeparator here,
- // because the path given originates from Go stdlib, specifically
- // runtime.Caller() which (as of Mar/17) returns forward slashes even on
- // Windows.
- //
- // See https://github.com/golang/go/issues/3335
- // and https://github.com/golang/go/issues/18151
- //
- // for discussion on the issue on Go side.
- idx := strings.LastIndexByte(loggingFilePath, '/')
- if idx == -1 {
- return loggingFilePath
- }
- idx = strings.LastIndexByte(loggingFilePath[:idx], '/')
- if idx == -1 {
- return loggingFilePath
- }
- return loggingFilePath[idx+1:]
- }
- func (l *defaultLogger) Log(level Level, v ...interface{}) {
- l.logf(level, "", v...)
- }
- func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
- l.logf(level, format, v...)
- }
- func (l *defaultLogger) logf(level Level, format string, v ...interface{}) {
- // TODO decide does we need to write message if log level not used?
- if !l.opts.Level.Enabled(level) {
- return
- }
- l.RLock()
- fields := copyFields(l.opts.Fields)
- l.RUnlock()
- rec := dlog.Record{
- Timestamp: time.Now(),
- Metadata: make(map[string]string, len(fields)),
- }
- //s := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000Z0700")
- str := "[" + rec.Timestamp.Format("2006-01-02 15:04:05.000")
- if l.opts.Name != "" {
- str += " " + l.opts.Name
- }
- str += "][" + strings.ToUpper(level.String()) + "]"
- if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok && level.String() == "error" {
- str += "[ERR:" + fmt.Sprintf("%s:%d", logCallerFilePath(file), line) + "]"
- }
- if format == "" {
- rec.Message = fmt.Sprint(v...)
- } else {
- rec.Message = fmt.Sprintf(format, v...)
- }
- keys := make([]string, 0, len(fields))
- for k, v := range fields {
- keys = append(keys, k)
- rec.Metadata[k] = fmt.Sprintf("%v", v)
- }
- sort.Strings(keys)
- metadata := ""
- for i, k := range keys {
- if i == 0 {
- metadata += fmt.Sprintf("%v", fields[k])
- } else {
- metadata += fmt.Sprintf(" %v", fields[k])
- }
- }
- logStr := fmt.Sprintf("%s %s %v\n", str, metadata, rec.Message)
- _, err := l.opts.Out.Write([]byte(logStr))
- if err != nil {
- log.Printf("log [Logf] write error: %s \n", err.Error())
- }
- }
- func (l *defaultLogger) Options() Options {
- // not guard against options Context values
- l.RLock()
- opts := l.opts
- opts.Fields = copyFields(l.opts.Fields)
- l.RUnlock()
- return opts
- }
- // NewLogger builds a new logger based on options
- func NewLogger(opts ...Option) Logger {
- // Default options
- options := Options{
- Level: InfoLevel,
- Fields: make(map[string]interface{}),
- Out: os.Stderr,
- CallerSkipCount: 3,
- Context: context.Background(),
- Name: "",
- }
- l := &defaultLogger{opts: options}
- if err := l.Init(opts...); err != nil {
- l.Log(FatalLevel, err)
- }
- return l
- }
|