/*********************************************************************************************************************** * * MIT License * * Copyright (c) 2021 Nicolas JUHEL * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * **********************************************************************************************************************/ package entry import ( "os" "strings" "time" ginsdk "github.com/gin-gonic/gin" logfld "github.com/nabbar/golib/logger/fields" loglvl "github.com/nabbar/golib/logger/level" logtps "github.com/nabbar/golib/logger/types" "github.com/sirupsen/logrus" ) type entry struct { log func() *logrus.Logger gin *ginsdk.Context clean bool //Time is the time of the event (can be empty time if disabled timestamp) Time time.Time `json:"time"` //Level define the level of the entry (cannot be empty or nil) Level loglvl.Level `json:"level"` //Stack define the process goroutine number (can be 0 if disabled) Stack uint64 `json:"stack"` //Caller define the function caller of the entry (can be empty if trace disabled, not found or anonymous function) Caller string `json:"caller"` //File define the file function caller of the entry (can be empty if trace disabled, not found or anonymous function) File string `json:"file"` //Caller define the line in file caller of the entry (can be 0 if trace disabled, not found or anonymous function) Line uint64 `json:"line"` //Message define the main message of the entry (can be empty) Message string `json:"message"` //Error define a slice of error interface (can be nil, or a silce with one or more nil values) Error []error `json:"error"` //Data is a unknown type data to add to logger (can be nil) Data interface{} `json:"data"` //Fields are a list of custom information to add to log entry (can be nil or can overwrite Entry values) Fields logfld.Fields `json:"fields"` } func (e *entry) SetEntryContext(etime time.Time, stack uint64, caller, file string, line uint64, msg string) Entry { if e == nil { return nil } e.Time = etime e.Stack = stack e.Caller = caller e.File = file e.Line = line e.Message = msg return e } func (e *entry) SetMessageOnly(flag bool) Entry { if e == nil { return nil } e.clean = flag return e } func (e *entry) SetLevel(lvl loglvl.Level) Entry { if e == nil { return nil } e.Level = lvl return e } func (e *entry) SetLogger(fct func() *logrus.Logger) Entry { if e == nil { return nil } e.log = fct return e } // SetGinContext allow to register a gin context pointer to register the errors of the current entry intro gin Context Error Slice. func (e *entry) SetGinContext(ctx *ginsdk.Context) Entry { if e == nil { return nil } e.gin = ctx return e } func (e *entry) DataSet(data interface{}) Entry { if e == nil { return nil } e.Data = data return e } func (e *entry) Check(lvlNoErr loglvl.Level) bool { if e == nil { return false } var found = false if len(e.Error) > 0 { for _, er := range e.Error { if er == nil { continue } found = true break } } if !found { e.Level = lvlNoErr } e.Log() return found } func (e *entry) Log() { if e == nil { return } else if e.log == nil { return } else if e.Fields == nil { return } else if e.Fields.Err() != nil { return } else if e.clean { e._logClean() return } else if e.gin != nil && len(e.Error) > 0 { for _, err := range e.Error { _ = e.gin.Error(err) } } if e.Level == loglvl.NilLevel { return } var ( ent *logrus.Entry tag = logfld.New(e.Fields.GetContext).Add(logtps.FieldLevel, e.Level.String()) log *logrus.Logger ) if !e.Time.IsZero() { tag = tag.Add(logtps.FieldTime, e.Time.Format(time.RFC3339Nano)) } if e.Stack > 0 { tag = tag.Add(logtps.FieldStack, e.Stack) } if e.Caller != "" { tag = tag.Add(logtps.FieldCaller, e.Caller) } else if e.File != "" { tag = tag.Add(logtps.FieldFile, e.File) } if e.Line > 0 { tag = tag.Add(logtps.FieldLine, e.Line) } if e.Message != "" { tag = tag.Add(logtps.FieldMessage, e.Message) } if len(e.Error) > 0 { var msg = make([]string, 0) for _, er := range e.Error { if er == nil { continue } msg = append(msg, er.Error()) } tag = tag.Add(logtps.FieldError, strings.Join(msg, ", ")) } if e.Data != nil { tag = tag.Add(logtps.FieldData, e.Data) } tag.Merge(e.Fields) if e.log == nil { return } else if log = e.log(); log == nil { return } else { ent = log.WithFields(tag.Logrus()) } ent.Log(e.Level.Logrus()) if e.Level <= loglvl.FatalLevel { os.Exit(1) } } func (e *entry) _logClean() { var ( log *logrus.Logger ) if e.log == nil { return } else if log = e.log(); log == nil { return } else { //log.SetLevel(logrus.InfoLevel) log.Info(e.Message) } }