123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- package golog
- import (
- "fmt"
- "path/filepath"
- "runtime"
- "strings"
- "time"
- )
- // A Log represents a log line.
- type Log struct {
- // Logger is the original printer of this Log.
- Logger *Logger `json:"-"`
- // Time is the time of fired.
- Time time.Time `json:"-"`
- // Timestamp is the unix time in second of fired.
- Timestamp int64 `json:"timestamp,omitempty"`
- // Level is the log level.
- Level Level `json:"level"`
- // Message is the string reprensetation of the log's main body.
- Message string `json:"message"`
- // Fields any data information useful to represent this log.
- Fields Fields `json:"fields,omitempty"`
- // Stacktrace contains the stack callers when on `Debug` level.
- // The first one should be the Logger's direct caller function.
- Stacktrace []Frame `json:"stacktrace,omitempty"`
- // NewLine returns false if this Log
- // derives from a `Print` function,
- // otherwise true if derives from a `Println`, `Error`, `Errorf`, `Warn`, etc...
- //
- // This NewLine does not mean that `Message` ends with "\n" (or `pio#NewLine`).
- // NewLine has to do with the methods called,
- // not the original content of the `Message`.
- NewLine bool `json:"-"`
- }
- // Frame represents the log's caller.
- type Frame struct {
- // Function is the package path-qualified function name of
- // this call frame. If non-empty, this string uniquely
- // identifies a single function in the program.
- // This may be the empty string if not known.
- Function string `json:"function"`
- // Source contains the file name and line number of the
- // location in this frame. For non-leaf frames, this will be
- // the location of a call.
- Source string `json:"source"`
- }
- // String method returns the concat value of "file:line".
- // Implements the `fmt.Stringer` interface.
- func (f Frame) String() string {
- return f.Source
- }
- // FormatTime returns the formatted `Time`.
- func (l *Log) FormatTime() string {
- if l.Logger.TimeFormat == "" {
- return ""
- }
- return l.Time.Format(l.Logger.TimeFormat)
- }
- var funcNameReplacer = strings.NewReplacer(")", "", "(", "", "*", "")
- // GetStacktrace tries to return the callers of this function.
- func GetStacktrace(limit int) (callerFrames []Frame) {
- if limit < 0 {
- return nil
- }
- var pcs [32]uintptr
- n := runtime.Callers(1, pcs[:])
- frames := runtime.CallersFrames(pcs[:n])
- for {
- f, more := frames.Next()
- file := filepath.ToSlash(f.File)
- if strings.Contains(file, "go/src/") {
- continue
- }
- if strings.Contains(file, "github.com/kataras/golog") &&
- !(strings.Contains(file, "_examples") ||
- strings.Contains(file, "_test.go") ||
- strings.Contains(file, "integration.go")) {
- continue
- }
- if file != "" { // keep it here, break should be respected.
- funcName := f.Function
- if idx := strings.Index(funcName, ".("); idx > 1 {
- funcName = funcNameReplacer.Replace(funcName[idx+1:])
- // e.g. method: github.com/kataras/iris/v12.(*Application).Listen to:
- // Application.Listen
- } else if idx = strings.LastIndexByte(funcName, '/'); idx >= 0 && len(funcName) > idx+1 {
- funcName = strings.Replace(funcName[idx+1:], ".", "/", 1)
- // e.g. package-level function: github.com/kataras/iris/v12/context.Do to
- // context/Do
- }
- callerFrames = append(callerFrames, Frame{
- Function: funcName,
- Source: fmt.Sprintf("%s:%d", f.File, f.Line),
- })
- if limit > 0 && len(callerFrames) >= limit {
- break
- }
- }
- if !more {
- break
- }
- }
- return
- }
|