frank 38308d48f2
feat_: log on panic (#5849)
* feat_: log error and stacktrace when panic in goroutine

* test_: add test TestSafeGo

* chore_: rename logAndCall to call

* chore_: rename SafeGo to Go

* chore_: make lint-fix

* chore_: use t.Cleanup

* chore_: Revert "chore_: use t.Cleanup"

This reverts commit 4eb420d179cc0e208e84c13cb941e6b3d1ed9819.

* chore_: Revert "chore_: make lint-fix"

This reverts commit fcc995f157e671a4229b47419c3a0e4004b5fdab.

* chore_: Revert "chore_: rename SafeGo to Go"

This reverts commit a6d73d6df583f313032d79aac62f66328039cb55.

* chore_: Revert "chore_: rename logAndCall to call"

This reverts commit 8fbe993bedb9fbba67349a44f151e2dd5e3bc4cc.

* chore_: Revert "test_: add test TestSafeGo"

This reverts commit a1fa91839f3960398980c6bf456e6462ec944819.

* chore_: Revert "feat_: log error and stacktrace when panic in goroutine"

This reverts commit f612dd828fa2ce410d0e806fe773ecbe3e86a68a.

* feat_: log error and stacktrace when panic in goroutine

* chore_: make lint-fix

* chore_: rename logAndCall to call

* chore_: renaming LogOnPanic

* chore_: update rest goroutine function calls

* chore_: make lint-fix
2024-09-27 06:37:32 +08:00

124 lines
2.5 KiB
Go

package common
import (
"sync"
"time"
"github.com/ethereum/go-ethereum/rlp"
"github.com/status-im/status-go/common"
"github.com/status-im/status-go/eth-node/types"
)
type Measure struct {
Timestamp int64
Size uint64
}
type StatsTracker struct {
Uploads []Measure
Downloads []Measure
statsMutex sync.Mutex
}
const measurementPeriod = 15 * time.Second
func measure(input interface{}) (*Measure, error) {
b, err := rlp.EncodeToBytes(input)
if err != nil {
return nil, err
}
return &Measure{
Timestamp: time.Now().UnixNano(),
Size: uint64(len(b)),
}, nil
}
func (s *StatsTracker) AddUpload(input interface{}) {
go func(input interface{}) {
defer common.LogOnPanic()
m, err := measure(input)
if err != nil {
return
}
s.statsMutex.Lock()
defer s.statsMutex.Unlock()
s.Uploads = append(s.Uploads, *m)
}(input)
}
func (s *StatsTracker) AddDownload(input interface{}) {
go func(input interface{}) {
defer common.LogOnPanic()
m, err := measure(input)
if err != nil {
return
}
s.statsMutex.Lock()
defer s.statsMutex.Unlock()
s.Downloads = append(s.Downloads, *m)
}(input)
}
func (s *StatsTracker) AddUploadBytes(size uint64) {
go func(size uint64) {
defer common.LogOnPanic()
m := Measure{
Timestamp: time.Now().UnixNano(),
Size: size,
}
s.statsMutex.Lock()
defer s.statsMutex.Unlock()
s.Uploads = append(s.Uploads, m)
}(size)
}
func (s *StatsTracker) AddDownloadBytes(size uint64) {
go func(size uint64) {
defer common.LogOnPanic()
m := Measure{
Timestamp: time.Now().UnixNano(),
Size: size,
}
s.statsMutex.Lock()
defer s.statsMutex.Unlock()
s.Downloads = append(s.Downloads, m)
}(size)
}
func calculateAverage(measures []Measure, minTime int64) (validMeasures []Measure, rate uint64) {
for _, m := range measures {
if m.Timestamp > minTime {
// Only use recent measures
validMeasures = append(validMeasures, m)
rate += m.Size
}
}
rate /= (uint64(measurementPeriod) / uint64(1*time.Second))
return
}
func (s *StatsTracker) GetRatePerSecond() (uploadRate uint64, downloadRate uint64) {
s.statsMutex.Lock()
defer s.statsMutex.Unlock()
minTime := time.Now().Add(-measurementPeriod).UnixNano()
s.Uploads, uploadRate = calculateAverage(s.Uploads, minTime)
s.Downloads, downloadRate = calculateAverage(s.Downloads, minTime)
return
}
func (s *StatsTracker) GetStats() types.StatsSummary {
uploadRate, downloadRate := s.GetRatePerSecond()
summary := types.StatsSummary{
UploadRate: uploadRate,
DownloadRate: downloadRate,
}
return summary
}