github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/countlog/root.go (about) 1 package countlog 2 3 import ( 4 "github.com/v2pro/plz/countlog/spi" 5 "runtime" 6 "fmt" 7 "runtime/debug" 8 "github.com/v2pro/plz/countlog/loglog" 9 ) 10 11 type panicHandler func(recovered interface{}, event *spi.Event, site *spi.LogSite) 12 13 func newRootHandler(site *spi.LogSite, onPanic panicHandler) spi.EventHandler { 14 statsHandler := EventAggregator.HandlerOf(site) 15 if statsHandler == nil { 16 return &oneHandler{ 17 site: site, 18 handler: EventWriter.HandlerOf(site), 19 onPanic: onPanic, 20 } 21 } 22 return &statsAndOutput{ 23 site: site, 24 statsHandler: statsHandler, 25 outputHandler: EventWriter.HandlerOf(site), 26 onPanic: onPanic, 27 } 28 } 29 30 type oneHandler struct { 31 site *spi.LogSite 32 handler spi.EventHandler 33 onPanic panicHandler 34 } 35 36 func (handler *oneHandler) Handle(event *spi.Event) { 37 defer func() { 38 recovered := recover() 39 if recovered != nil { 40 handler.onPanic(recovered, event, handler.site) 41 } 42 }() 43 handler.handler.Handle(event) 44 } 45 46 func (handler *oneHandler) LogSite() *spi.LogSite { 47 return handler.site 48 } 49 50 type statsAndOutput struct { 51 site *spi.LogSite 52 statsHandler spi.EventHandler 53 outputHandler spi.EventHandler 54 onPanic panicHandler 55 } 56 57 func (handler *statsAndOutput) Handle(event *spi.Event) { 58 defer func() { 59 recovered := recover() 60 if recovered != nil { 61 handler.onPanic(recovered, event, handler.site) 62 } 63 }() 64 if event.Level >= spi.MinCallLevel { 65 handler.outputHandler.Handle(event) 66 } 67 handler.statsHandler.Handle(event) 68 } 69 70 func (handler *statsAndOutput) LogSite() *spi.LogSite { 71 return handler.site 72 } 73 74 func nomalModeOnPanic(recovered interface{}, event *spi.Event, site *spi.LogSite) { 75 redirector := &redirector{ 76 site: *site, 77 } 78 handlerCache.Store(site.Event, redirector) 79 newSite := *site 80 newSite.File = "unknown" 81 newSite.Line = 0 82 newSite.Sample = event.Properties 83 newRootHandler(&newSite, fallbackModeOnPanic).Handle(event) 84 } 85 86 func fallbackModeOnPanic(recovered interface{}, event *spi.Event, site *spi.LogSite) { 87 loglog.Error(fmt.Errorf("%v", recovered)) 88 if spi.MinLevel <= spi.LevelDebug { 89 debug.PrintStack() 90 } 91 } 92 93 type redirector struct { 94 site spi.LogSite 95 } 96 97 func (redirector *redirector) Handle(event *spi.Event) { 98 _, callerFile, callerLine, _ := runtime.Caller(3) 99 key := accurateHandlerKey{callerFile, callerLine} 100 handlerObj, found := handlerCache.Load(key) 101 if found { 102 handlerObj.(spi.EventHandler).Handle(event) 103 return 104 } 105 site := redirector.site 106 site.File = callerFile 107 site.Line = callerLine 108 site.Sample = event.Properties 109 handler := newRootHandler(&site, fallbackModeOnPanic) 110 handlerCache.Store(key, handler) 111 handler.Handle(event) 112 return 113 } 114 115 type accurateHandlerKey struct { 116 File string 117 Line int 118 }