github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/countlog/countlog.go (about)

     1  package countlog
     2  
     3  import (
     4  	"unsafe"
     5  	"runtime"
     6  	"time"
     7  	"github.com/v2pro/plz/countlog/spi"
     8  	"github.com/v2pro/plz/msgfmt"
     9  	"errors"
    10  	"github.com/v2pro/plz/concurrent"
    11  )
    12  
    13  const LevelTraceCall = spi.LevelTraceCall
    14  const LevelTrace = spi.LevelTrace
    15  const LevelDebugCall = spi.LevelDebugCall
    16  const LevelDebug = spi.LevelDebug
    17  const LevelInfoCall = spi.LevelInfoCall
    18  const LevelInfo = spi.LevelInfo
    19  const LevelWarn = spi.LevelWarn
    20  const LevelError = spi.LevelError
    21  const LevelFatal = spi.LevelFatal
    22  
    23  func init() {
    24  	concurrent.LogInfo = Info
    25  	concurrent.LogPanic = LogPanic
    26  }
    27  
    28  func SetMinLevel(level int) {
    29  	spi.MinLevel = level
    30  	spi.MinCallLevel = level + 5
    31  }
    32  
    33  func ShouldLog(level int) bool {
    34  	return level >= spi.MinLevel
    35  }
    36  
    37  func Trace(event string, properties ...interface{}) {
    38  	if LevelTrace < spi.MinLevel {
    39  		return
    40  	}
    41  	ptr := unsafe.Pointer(&properties)
    42  	log(LevelTrace, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
    43  }
    44  
    45  // TraceCall will calculate stats in TRACE level
    46  // TraceCall will output individual log entries in TRACE_CALL level
    47  func TraceCall(event string, err error, properties ...interface{}) error {
    48  	if err != nil {
    49  		ptr := unsafe.Pointer(&properties)
    50  		return log(LevelWarn, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
    51  	}
    52  	if LevelTrace < spi.MinLevel {
    53  		return nil
    54  	}
    55  	ptr := unsafe.Pointer(&properties)
    56  	log(LevelTrace, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
    57  	return nil
    58  }
    59  
    60  func Debug(event string, properties ...interface{}) {
    61  	if LevelDebug < spi.MinLevel {
    62  		return
    63  	}
    64  	ptr := unsafe.Pointer(&properties)
    65  	log(LevelDebug, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
    66  }
    67  
    68  // DebugCall will calculate stats in DEBUG level
    69  // DebugCall will output individual log entries in DEBUG_CALL level (TRACE includes DEBUG_CALL)
    70  func DebugCall(event string, err error, properties ...interface{}) error {
    71  	if err != nil {
    72  		ptr := unsafe.Pointer(&properties)
    73  		return log(LevelWarn, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
    74  	}
    75  	if LevelDebug < spi.MinLevel {
    76  		return nil
    77  	}
    78  	ptr := unsafe.Pointer(&properties)
    79  	log(LevelDebug, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
    80  	return nil
    81  }
    82  
    83  func Info(event string, properties ...interface{}) {
    84  	if LevelInfo < spi.MinLevel {
    85  		return
    86  	}
    87  	ptr := unsafe.Pointer(&properties)
    88  	log(LevelInfo, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
    89  }
    90  
    91  // InfoCall will calculate stats in INFO level
    92  // InfoCall will output individual log entries in INFO_CALL level (DEBUG includes INFO_CALL)
    93  func InfoCall(event string, err error, properties ...interface{}) error {
    94  	if err != nil {
    95  		ptr := unsafe.Pointer(&properties)
    96  		return log(LevelWarn, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
    97  	}
    98  	if LevelInfo < spi.MinLevel {
    99  		return nil
   100  	}
   101  	ptr := unsafe.Pointer(&properties)
   102  	log(LevelInfo, event, "call", nil, err, castEmptyInterfaces(uintptr(ptr)))
   103  	return nil
   104  }
   105  
   106  func Warn(event string, properties ...interface{}) {
   107  	ptr := unsafe.Pointer(&properties)
   108  	log(LevelWarn, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
   109  }
   110  
   111  func Error(event string, properties ...interface{}) {
   112  	ptr := unsafe.Pointer(&properties)
   113  	log(LevelError, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
   114  }
   115  
   116  func Fatal(event string, properties ...interface{}) {
   117  	ptr := unsafe.Pointer(&properties)
   118  	log(LevelFatal, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
   119  }
   120  
   121  func Log(level int, event string, properties ...interface{}) {
   122  	if level < spi.MinLevel {
   123  		return
   124  	}
   125  	ptr := unsafe.Pointer(&properties)
   126  	log(level, event, "", nil, nil, castEmptyInterfaces(uintptr(ptr)))
   127  }
   128  
   129  func LogPanic(recovered interface{}, properties ...interface{}) interface{} {
   130  	if recovered == nil {
   131  		return nil
   132  	}
   133  	buf := make([]byte, 1<<16)
   134  	runtime.Stack(buf, false)
   135  	if len(properties) > 0 {
   136  		properties = append(properties, "err", recovered, "stacktrace", string(buf))
   137  		Fatal("event!panic", properties...)
   138  	} else {
   139  		Fatal("event!panic", "err", recovered, "stacktrace", string(buf))
   140  	}
   141  	return recovered
   142  }
   143  
   144  var handlerCache = concurrent.NewMap()
   145  
   146  func log(level int, eventName string, agg string, ctx *Context, err error, properties []interface{}) error {
   147  	handler := getHandler(eventName, agg, ctx, properties)
   148  	event := &spi.Event{
   149  		Level:      level,
   150  		Context:    ctx,
   151  		Error:      err,
   152  		Timestamp:  time.Now(),
   153  		Properties: properties,
   154  	}
   155  	ptr := unsafe.Pointer(event)
   156  	castedEvent := castEvent(uintptr(ptr))
   157  	handler.Handle(castedEvent)
   158  	if castedEvent.Error != nil {
   159  		formatter := msgfmt.FormatterOf(eventName, properties)
   160  		errMsg := formatter.Format(nil, properties)
   161  		errMsg = append(errMsg, ": "...)
   162  		errMsg = append(errMsg, castedEvent.Error.Error()...)
   163  		castedEvent.Error = errors.New(string(errMsg))
   164  	}
   165  	return castedEvent.Error
   166  }
   167  
   168  func addMemo(level int, eventName string, agg string, ctx *Context, err error, properties []interface{}) {
   169  	event := &spi.Event{
   170  		Level:      level,
   171  		Context:    ctx,
   172  		Error:      err,
   173  		Timestamp:  time.Now(),
   174  		Properties: properties,
   175  	}
   176  	ptr := unsafe.Pointer(event)
   177  	castedEvent := castEvent(uintptr(ptr))
   178  	if castedEvent.Error != nil {
   179  		formatter := msgfmt.FormatterOf(eventName, properties)
   180  		errMsg := formatter.Format(nil, properties)
   181  		errMsg = append(errMsg, ": "...)
   182  		errMsg = append(errMsg, castedEvent.Error.Error()...)
   183  		castedEvent.Error = errors.New(string(errMsg))
   184  	}
   185  }
   186  
   187  func castEmptyInterfaces(ptr uintptr) []interface{} {
   188  	return *(*[]interface{})(unsafe.Pointer(ptr))
   189  }
   190  
   191  func castEvent(ptr uintptr) *spi.Event {
   192  	return (*spi.Event)(unsafe.Pointer(ptr))
   193  }
   194  func castString(ptr uintptr) string {
   195  	return *(*string)(unsafe.Pointer(ptr))
   196  }
   197  
   198  func getHandler(event string, agg string, ctx *Context, properties []interface{}) spi.EventHandler {
   199  	handler, found := handlerCache.Load(event)
   200  	if found {
   201  		return handler.(spi.EventHandler)
   202  	}
   203  	return newHandler(event, agg, ctx, properties)
   204  }
   205  
   206  func newHandler(eventName string, agg string, ctx *Context, properties []interface{}) spi.EventHandler {
   207  	pc, callerFile, callerLine, _ := runtime.Caller(4)
   208  	site := &spi.LogSite{
   209  		Context: ctx,
   210  		Func: runtime.FuncForPC(pc).Name(),
   211  		Event:  eventName,
   212  		Agg:    agg,
   213  		File:   callerFile,
   214  		Line:   callerLine,
   215  		Sample: properties,
   216  	}
   217  	handler := newRootHandler(site, nomalModeOnPanic)
   218  	handlerCache.Store(eventName, handler)
   219  	return handler
   220  }