Files
streamctl/cmd/streampanel/error_monitor_hook.go
2024-07-06 14:35:03 +01:00

80 lines
2.1 KiB
Go

package main
import (
"bytes"
"fmt"
"runtime"
"github.com/DataDog/gostackparse"
xruntime "github.com/facebookincubator/go-belt/pkg/runtime"
errmontypes "github.com/facebookincubator/go-belt/tool/experimental/errmon/types"
"github.com/facebookincubator/go-belt/tool/logger"
)
func getGoroutines() ([]errmontypes.Goroutine, int) {
// TODO: consider pprof.Lookup("goroutine") instead of runtime.Stack
// getting all goroutines
stackBufferSize := 65536 * runtime.NumGoroutine()
if stackBufferSize > 10*1024*1024 {
stackBufferSize = 10 * 1024 * 1024
}
stackBuffer := make([]byte, stackBufferSize)
n := runtime.Stack(stackBuffer, true)
goroutines, errs := gostackparse.Parse(bytes.NewReader(stackBuffer[:n]))
if len(errs) > 0 { //nolint:staticcheck
// TODO: do something
}
// convert goroutines for the output
goroutinesConverted := make([]errmontypes.Goroutine, 0, len(goroutines))
for _, goroutine := range goroutines {
goroutinesConverted = append(goroutinesConverted, *goroutine)
}
// getting current goroutine ID
n = runtime.Stack(stackBuffer, false)
currentGoroutines, errs := gostackparse.Parse(bytes.NewReader(stackBuffer[:n]))
if len(errs) > 0 { //nolint:staticcheck
// TODO: do something
}
var currentGoroutineID int
switch len(currentGoroutines) {
case 0:
// TODO: do something
case 1:
currentGoroutineID = currentGoroutines[0].ID
default:
// TODO: do something
}
return goroutinesConverted, currentGoroutineID
}
type ErrorMonitorLoggerHook struct {
ErrorMonitor errmontypes.ErrorMonitor
}
func (h *ErrorMonitorLoggerHook) ProcessLogEntry(entry *logger.Entry) bool {
if entry.Level > logger.LevelWarning {
return true
}
goroutines, currentGoroutineID := getGoroutines()
h.ErrorMonitor.Emitter().Emit(&errmontypes.Event{
Entry: *entry,
ID: "",
ExternalIDs: []any{},
Exception: errmontypes.Exception{
IsPanic: entry.Level <= logger.LevelPanic,
Error: fmt.Errorf("[%s] %s", entry.Level, entry.Message),
StackTrace: xruntime.CallerStackTrace(nil),
},
CurrentGoroutineID: currentGoroutineID,
Goroutines: goroutines,
})
return true
}
func (h *ErrorMonitorLoggerHook) Flush() {}