Files
DragonCoreSSH-NewWEB/panel_log_limiter.go
2026-05-03 11:05:13 -03:00

106 lines
2.4 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
const (
defaultPanelLogMaxBytes int64 = 1 * 1024 * 1024
defaultPanelLogCheckEvery = 10 * time.Second
)
type panelLogResetResponse struct {
OK bool `json:"ok"`
Path string `json:"path"`
MaxBytes int64 `json:"max_bytes"`
}
func panelLogFilePath() string {
path := strings.TrimSpace(os.Getenv("PANEL_LOG_FILE"))
if path == "" {
path = defaultPanelLogFile
}
return path
}
func panelLogMaxBytes() int64 {
raw := strings.TrimSpace(os.Getenv("PANEL_LOG_MAX_BYTES"))
if raw == "" {
return defaultPanelLogMaxBytes
}
n, err := strconv.ParseInt(raw, 10, 64)
if err != nil || n <= 0 {
return defaultPanelLogMaxBytes
}
// Do not allow a tiny limit that would cause continuous truncation.
if n < 64*1024 {
return 64 * 1024
}
return n
}
func startPanelLogLimiter() {
path := panelLogFilePath()
maxBytes := panelLogMaxBytes()
if path == "" || maxBytes <= 0 {
return
}
go func() {
_ = enforcePanelLogLimit(path, maxBytes)
ticker := time.NewTicker(defaultPanelLogCheckEvery)
defer ticker.Stop()
for range ticker.C {
_ = enforcePanelLogLimit(path, maxBytes)
}
}()
}
func enforcePanelLogLimit(path string, maxBytes int64) error {
st, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if st.Size() <= maxBytes {
return nil
}
return truncatePanelLog(path, maxBytes, "automatic 1 MiB log limit")
}
func truncatePanelLog(path string, maxBytes int64, reason string) error {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = fmt.Fprintf(f, "%s sshpanel: panel log cleaned (%s, max=%d bytes)\n", time.Now().Format(time.RFC3339), reason, maxBytes)
return err
}
func handleSystemLogsReset(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
path := panelLogFilePath()
maxBytes := panelLogMaxBytes()
if err := truncatePanelLog(path, maxBytes, "manual clean from admin panel"); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(panelLogResetResponse{OK: true, Path: path, MaxBytes: maxBytes})
}