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 }