mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
//go:build darwin || linux || windows
|
|
|
|
package libbox
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/sagernet/sing-box/experimental/libbox/internal/oomprofile"
|
|
"github.com/sagernet/sing-box/service/oomkiller"
|
|
"github.com/sagernet/sing/common/byteformats"
|
|
"github.com/sagernet/sing/common/memory"
|
|
)
|
|
|
|
func init() {
|
|
sOOMReporter = &oomReporter{}
|
|
}
|
|
|
|
var oomReportProfiles = []string{
|
|
"allocs",
|
|
"block",
|
|
"goroutine",
|
|
"heap",
|
|
"mutex",
|
|
"threadcreate",
|
|
}
|
|
|
|
type oomReportMetadata struct {
|
|
reportMetadata
|
|
RecordedAt string `json:"recordedAt"`
|
|
MemoryUsage string `json:"memoryUsage"`
|
|
AvailableMemory string `json:"availableMemory,omitempty"`
|
|
// Heap
|
|
HeapAlloc string `json:"heapAlloc,omitempty"`
|
|
HeapObjects uint64 `json:"heapObjects,omitempty,string"`
|
|
HeapInuse string `json:"heapInuse,omitempty"`
|
|
HeapIdle string `json:"heapIdle,omitempty"`
|
|
HeapReleased string `json:"heapReleased,omitempty"`
|
|
HeapSys string `json:"heapSys,omitempty"`
|
|
// Stack
|
|
StackInuse string `json:"stackInuse,omitempty"`
|
|
StackSys string `json:"stackSys,omitempty"`
|
|
// Runtime metadata
|
|
MSpanInuse string `json:"mSpanInuse,omitempty"`
|
|
MSpanSys string `json:"mSpanSys,omitempty"`
|
|
MCacheSys string `json:"mCacheSys,omitempty"`
|
|
BuckHashSys string `json:"buckHashSys,omitempty"`
|
|
GCSys string `json:"gcSys,omitempty"`
|
|
OtherSys string `json:"otherSys,omitempty"`
|
|
Sys string `json:"sys,omitempty"`
|
|
// GC & runtime
|
|
TotalAlloc string `json:"totalAlloc,omitempty"`
|
|
NumGC uint32 `json:"numGC,omitempty,string"`
|
|
NumGoroutine int `json:"numGoroutine,omitempty,string"`
|
|
NextGC string `json:"nextGC,omitempty"`
|
|
LastGC string `json:"lastGC,omitempty"`
|
|
}
|
|
|
|
type oomReporter struct{}
|
|
|
|
var _ oomkiller.OOMReporter = (*oomReporter)(nil)
|
|
|
|
func (r *oomReporter) WriteReport(memoryUsage uint64) error {
|
|
now := time.Now().UTC()
|
|
reportsDir := filepath.Join(sWorkingPath, "oom_reports")
|
|
err := os.MkdirAll(reportsDir, 0o777)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chownReport(reportsDir)
|
|
|
|
destPath, err := nextAvailableReportPath(reportsDir, now)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.MkdirAll(destPath, 0o777)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chownReport(destPath)
|
|
|
|
for _, name := range oomReportProfiles {
|
|
writeOOMProfile(destPath, name)
|
|
}
|
|
|
|
writeReportFile(destPath, "cmdline", []byte(strings.Join(os.Args, "\000")))
|
|
|
|
var memStats runtime.MemStats
|
|
runtime.ReadMemStats(&memStats)
|
|
|
|
metadata := oomReportMetadata{
|
|
reportMetadata: baseReportMetadata(),
|
|
RecordedAt: now.Format(time.RFC3339),
|
|
MemoryUsage: byteformats.FormatMemoryBytes(memoryUsage),
|
|
// Heap
|
|
HeapAlloc: byteformats.FormatMemoryBytes(memStats.HeapAlloc),
|
|
HeapObjects: memStats.HeapObjects,
|
|
HeapInuse: byteformats.FormatMemoryBytes(memStats.HeapInuse),
|
|
HeapIdle: byteformats.FormatMemoryBytes(memStats.HeapIdle),
|
|
HeapReleased: byteformats.FormatMemoryBytes(memStats.HeapReleased),
|
|
HeapSys: byteformats.FormatMemoryBytes(memStats.HeapSys),
|
|
// Stack
|
|
StackInuse: byteformats.FormatMemoryBytes(memStats.StackInuse),
|
|
StackSys: byteformats.FormatMemoryBytes(memStats.StackSys),
|
|
// Runtime metadata
|
|
MSpanInuse: byteformats.FormatMemoryBytes(memStats.MSpanInuse),
|
|
MSpanSys: byteformats.FormatMemoryBytes(memStats.MSpanSys),
|
|
MCacheSys: byteformats.FormatMemoryBytes(memStats.MCacheSys),
|
|
BuckHashSys: byteformats.FormatMemoryBytes(memStats.BuckHashSys),
|
|
GCSys: byteformats.FormatMemoryBytes(memStats.GCSys),
|
|
OtherSys: byteformats.FormatMemoryBytes(memStats.OtherSys),
|
|
Sys: byteformats.FormatMemoryBytes(memStats.Sys),
|
|
// GC & runtime
|
|
TotalAlloc: byteformats.FormatMemoryBytes(memStats.TotalAlloc),
|
|
NumGC: memStats.NumGC,
|
|
NumGoroutine: runtime.NumGoroutine(),
|
|
NextGC: byteformats.FormatMemoryBytes(memStats.NextGC),
|
|
}
|
|
if memStats.LastGC > 0 {
|
|
metadata.LastGC = time.Unix(0, int64(memStats.LastGC)).UTC().Format(time.RFC3339)
|
|
}
|
|
availableMemory := memory.Available()
|
|
if availableMemory > 0 {
|
|
metadata.AvailableMemory = byteformats.FormatMemoryBytes(availableMemory)
|
|
}
|
|
writeReportMetadata(destPath, metadata)
|
|
copyConfigSnapshot(destPath)
|
|
|
|
return nil
|
|
}
|
|
|
|
func writeOOMProfile(destPath string, name string) {
|
|
filePath, err := oomprofile.WriteFile(destPath, name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
chownReport(filePath)
|
|
}
|